Use locked cursor position hint
Summary: Listen for cursor position hint changes and set cursor position to the hint on unlock if a valid position hint was set. Test Plan: With pointer constraints test app. Reviewers: #kwin, graesslin Reviewed By: #kwin, graesslin Subscribers: graesslin, kwin Tags: #kwin Maniphest Tasks: T4693 Differential Revision: https://phabricator.kde.org/D14176icc-effect-5.14.5
parent
d723ce2c40
commit
054ccc3898
|
@ -594,6 +594,12 @@ void PointerInputRedirection::disconnectConfinedPointerRegionConnection()
|
||||||
m_confinedPointerRegionConnection = QMetaObject::Connection();
|
m_confinedPointerRegionConnection = QMetaObject::Connection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PointerInputRedirection::disconnectLockedPointerAboutToBeUnboundConnection()
|
||||||
|
{
|
||||||
|
disconnect(m_lockedPointerAboutToBeUnboundConnection);
|
||||||
|
m_lockedPointerAboutToBeUnboundConnection = QMetaObject::Connection();
|
||||||
|
}
|
||||||
|
|
||||||
void PointerInputRedirection::disconnectPointerConstraintsConnection()
|
void PointerInputRedirection::disconnectPointerConstraintsConnection()
|
||||||
{
|
{
|
||||||
disconnect(m_constraintsConnection);
|
disconnect(m_constraintsConnection);
|
||||||
|
@ -689,8 +695,13 @@ void PointerInputRedirection::updatePointerConstraints()
|
||||||
if (lock) {
|
if (lock) {
|
||||||
if (lock->isLocked()) {
|
if (lock->isLocked()) {
|
||||||
if (!canConstrain) {
|
if (!canConstrain) {
|
||||||
|
const auto hint = lock->cursorPositionHint();
|
||||||
lock->setLocked(false);
|
lock->setLocked(false);
|
||||||
m_locked = false;
|
m_locked = false;
|
||||||
|
disconnectLockedPointerAboutToBeUnboundConnection();
|
||||||
|
if (! (hint.x() < 0 || hint.y() < 0) && m_window) {
|
||||||
|
processMotion(m_window->pos() - m_window->clientContentPos() + hint, waylandServer()->seat()->timestamp());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -698,6 +709,24 @@ void PointerInputRedirection::updatePointerConstraints()
|
||||||
if (canConstrain && r.contains(m_pos.toPoint())) {
|
if (canConstrain && r.contains(m_pos.toPoint())) {
|
||||||
lock->setLocked(true);
|
lock->setLocked(true);
|
||||||
m_locked = true;
|
m_locked = true;
|
||||||
|
|
||||||
|
// The client might cancel pointer locking from its side by unbinding the LockedPointerInterface.
|
||||||
|
// In this case the cached cursor position hint must be fetched before the resource goes away
|
||||||
|
m_lockedPointerAboutToBeUnboundConnection = connect(lock.data(), &KWayland::Server::LockedPointerInterface::aboutToBeUnbound, this,
|
||||||
|
[this, lock]() {
|
||||||
|
const auto hint = lock->cursorPositionHint();
|
||||||
|
if (hint.x() < 0 || hint.y() < 0 || !m_window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto globalHint = m_window->pos() - m_window->clientContentPos() + hint;
|
||||||
|
|
||||||
|
// When the resource finally goes away, reposition the cursor according to the hint
|
||||||
|
connect(lock.data(), &KWayland::Server::LockedPointerInterface::unbound, this,
|
||||||
|
[this, globalHint]() {
|
||||||
|
processMotion(globalHint, waylandServer()->seat()->timestamp());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
OSD::show(i18nc("notification about mouse pointer locked",
|
OSD::show(i18nc("notification about mouse pointer locked",
|
||||||
"Pointer locked to current position.\nTo end pointer lock hold Escape for 3 seconds."),
|
"Pointer locked to current position.\nTo end pointer lock hold Escape for 3 seconds."),
|
||||||
QStringLiteral("preferences-desktop-mouse"), 5000);
|
QStringLiteral("preferences-desktop-mouse"), 5000);
|
||||||
|
@ -705,6 +734,7 @@ void PointerInputRedirection::updatePointerConstraints()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_locked = false;
|
m_locked = false;
|
||||||
|
disconnectLockedPointerAboutToBeUnboundConnection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,6 +155,7 @@ private:
|
||||||
void warpXcbOnSurfaceLeft(KWayland::Server::SurfaceInterface *surface);
|
void warpXcbOnSurfaceLeft(KWayland::Server::SurfaceInterface *surface);
|
||||||
QPointF applyPointerConfinement(const QPointF &pos) const;
|
QPointF applyPointerConfinement(const QPointF &pos) const;
|
||||||
void disconnectConfinedPointerRegionConnection();
|
void disconnectConfinedPointerRegionConnection();
|
||||||
|
void disconnectLockedPointerAboutToBeUnboundConnection();
|
||||||
void disconnectPointerConstraintsConnection();
|
void disconnectPointerConstraintsConnection();
|
||||||
void breakPointerConstraints(KWayland::Server::SurfaceInterface *surface);
|
void breakPointerConstraints(KWayland::Server::SurfaceInterface *surface);
|
||||||
bool areButtonsPressed() const;
|
bool areButtonsPressed() const;
|
||||||
|
@ -169,6 +170,7 @@ private:
|
||||||
QMetaObject::Connection m_constraintsConnection;
|
QMetaObject::Connection m_constraintsConnection;
|
||||||
QMetaObject::Connection m_constraintsActivatedConnection;
|
QMetaObject::Connection m_constraintsActivatedConnection;
|
||||||
QMetaObject::Connection m_confinedPointerRegionConnection;
|
QMetaObject::Connection m_confinedPointerRegionConnection;
|
||||||
|
QMetaObject::Connection m_lockedPointerAboutToBeUnboundConnection;
|
||||||
QMetaObject::Connection m_decorationGeometryConnection;
|
QMetaObject::Connection m_decorationGeometryConnection;
|
||||||
bool m_confined = false;
|
bool m_confined = false;
|
||||||
bool m_locked = false;
|
bool m_locked = false;
|
||||||
|
|
|
@ -142,8 +142,14 @@ void WaylandBackend::lockRequest(bool persistent, QRect region)
|
||||||
}
|
}
|
||||||
m_lockedPointer = lockedPointer;
|
m_lockedPointer = lockedPointer;
|
||||||
m_lockedPointerPersistent = persistent;
|
m_lockedPointerPersistent = persistent;
|
||||||
|
|
||||||
connect(lockedPointer, &LockedPointer::locked, this, [this]() {
|
connect(lockedPointer, &LockedPointer::locked, this, [this]() {
|
||||||
qDebug() << "------ LOCKED! ------";
|
qDebug() << "------ LOCKED! ------";
|
||||||
|
if(lockHint()) {
|
||||||
|
m_lockedPointer->setCursorPositionHint(QPointF(10., 10.));
|
||||||
|
forceSurfaceCommit();
|
||||||
|
}
|
||||||
|
|
||||||
Q_EMIT lockChanged(true);
|
Q_EMIT lockChanged(true);
|
||||||
});
|
});
|
||||||
connect(lockedPointer, &LockedPointer::unlocked, this, [this]() {
|
connect(lockedPointer, &LockedPointer::unlocked, this, [this]() {
|
||||||
|
|
|
@ -49,6 +49,7 @@ public:
|
||||||
Backend(QObject *parent = nullptr) : QObject(parent) {}
|
Backend(QObject *parent = nullptr) : QObject(parent) {}
|
||||||
|
|
||||||
Q_PROPERTY(int mode READ mode CONSTANT)
|
Q_PROPERTY(int mode READ mode CONSTANT)
|
||||||
|
Q_PROPERTY(bool lockHint MEMBER m_lockHint NOTIFY lockHintChanged)
|
||||||
Q_PROPERTY(bool errorsAllowed READ errorsAllowed WRITE setErrorsAllowed NOTIFY errorsAllowedChanged)
|
Q_PROPERTY(bool errorsAllowed READ errorsAllowed WRITE setErrorsAllowed NOTIFY errorsAllowedChanged)
|
||||||
|
|
||||||
virtual void init(QQuickView *view) {
|
virtual void init(QQuickView *view) {
|
||||||
|
@ -57,6 +58,10 @@ public:
|
||||||
int mode() const {
|
int mode() const {
|
||||||
return (int)m_mode;
|
return (int)m_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool lockHint() const {
|
||||||
|
return m_lockHint;
|
||||||
|
}
|
||||||
bool errorsAllowed() const {
|
bool errorsAllowed() const {
|
||||||
return m_errorsAllowed;
|
return m_errorsAllowed;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +92,9 @@ public:
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void confineChanged(bool confined);
|
void confineChanged(bool confined);
|
||||||
void lockChanged(bool locked);
|
void lockChanged(bool locked);
|
||||||
|
void lockHintChanged();
|
||||||
void errorsAllowedChanged();
|
void errorsAllowedChanged();
|
||||||
|
void forceSurfaceCommit();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum class Mode {
|
enum class Mode {
|
||||||
|
@ -105,6 +112,8 @@ protected:
|
||||||
private:
|
private:
|
||||||
QQuickView *m_view;
|
QQuickView *m_view;
|
||||||
Mode m_mode;
|
Mode m_mode;
|
||||||
|
|
||||||
|
bool m_lockHint = true;
|
||||||
bool m_errorsAllowed = false;
|
bool m_errorsAllowed = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,28 @@ ColumnLayout {
|
||||||
return activArea.rect();
|
return activArea.rect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: org_kde_kwin_tests_pointerconstraints_backend
|
||||||
|
onForceSurfaceCommit: {
|
||||||
|
forceCommitRect.visible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: forceCommitRect
|
||||||
|
width: 10
|
||||||
|
height: 10
|
||||||
|
color: "red"
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 500
|
||||||
|
running: forceCommitRect.visible
|
||||||
|
repeat: false
|
||||||
|
onTriggered: forceCommitRect.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GridLayout {
|
GridLayout {
|
||||||
columns: 2
|
columns: 2
|
||||||
rowSpacing: 10
|
rowSpacing: 10
|
||||||
|
@ -120,6 +142,13 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: lockHintChck
|
||||||
|
text: "Send position hint on lock"
|
||||||
|
checked: root.waylandNative
|
||||||
|
enabled: root.waylandNative
|
||||||
|
onCheckedChanged: org_kde_kwin_tests_pointerconstraints_backend.lockHint = checked;
|
||||||
|
}
|
||||||
CheckBox {
|
CheckBox {
|
||||||
id: restrAreaChck
|
id: restrAreaChck
|
||||||
text: "Restrict input area (not yet implemented)"
|
text: "Restrict input area (not yet implemented)"
|
||||||
|
|
Loading…
Reference in New Issue