on xenial help sign in
Implement cursor confinement
2daaabdDaniel d'Andrada
CMakeLists.txt+1−1
@@ -57,7 +57,7 @@ find_package(Qt5DBus 5.4 REQUIRED)
57find_package(Qt5Concurrent 5.4 REQUIRED)
57find_package(Qt5Concurrent 5.4 REQUIRED)
58find_package(Qt5Sql 5.4 REQUIRED)
58find_package(Qt5Sql 5.4 REQUIRED)
59
59
60−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=20)
60+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=21)
61pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
61pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
62pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
62pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
63pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
63pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
debian/control+3−3
@@ -37,7 +37,7 @@ Build-Depends: cmake,
37 libubuntugestures5-private-dev (>= 1.3.2030),
37 libubuntugestures5-private-dev (>= 1.3.2030),
38 libudev-dev,
38 libudev-dev,
39 libudm-common-dev,
39 libudm-common-dev,
40− libunity-api-dev (>= 7.117),
40+ libunity-api-dev (>= 7.118),
41 libusermetricsoutput1-dev,
41 libusermetricsoutput1-dev,
42# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
42# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
43 libx11-dev[!arm64 !armhf],
43 libx11-dev[!arm64 !armhf],
@@ -157,7 +157,7 @@ Depends: qml-module-qtquick-layouts,
157 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
157 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
158 ubuntu-thumbnailer-impl-0,
158 ubuntu-thumbnailer-impl-0,
159 ubuntu-wallpapers,
159 ubuntu-wallpapers,
160− unity-application-impl-20,
160+ unity-application-impl-21,
161 unity-notifications-impl-3,
161 unity-notifications-impl-3,
162 unity-plugin-scopes | unity-scopes-impl,
162 unity-plugin-scopes | unity-scopes-impl,
163 unity-scopes-impl-12,
163 unity-scopes-impl-12,
@@ -203,7 +203,7 @@ Pre-Depends: ${misc:Pre-Depends},
203Depends: ${misc:Depends},
203Depends: ${misc:Depends},
204 ${shlibs:Depends},
204 ${shlibs:Depends},
205Provides: unity-application-impl,
205Provides: unity-application-impl,
206− unity-application-impl-20,
206+ unity-application-impl-21,
207Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
207Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
208Description: Fake environment for running Unity 8 shell
208Description: Fake environment for running Unity 8 shell
209 Provides fake implementations of some QML modules used by Unity 8 shell
209 Provides fake implementations of some QML modules used by Unity 8 shell
plugins/Cursor/MousePointer.cpp+42−1
@@ -56,7 +56,6 @@ void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::Mouse
56 Q_EMIT pushedRightBoundary(newX - (parentItem()->width() - 1), buttons);
56 Q_EMIT pushedRightBoundary(newX - (parentItem()->width() - 1), buttons);
57 newX = parentItem()->width() - 1;
57 newX = parentItem()->width() - 1;
58 }
58 }
59− setX(newX);
60
59
61 qreal newY = y() + appliedMovement.y();
60 qreal newY = y() + appliedMovement.y();
62 if (newY < 0) {
61 if (newY < 0) {
@@ -64,6 +63,10 @@ void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::Mouse
64 } else if (newY >= parentItem()->height()) {
63 } else if (newY >= parentItem()->height()) {
65 newY = parentItem()->height() - 1;
64 newY = parentItem()->height() - 1;
66 }
65 }
66+
67+ applyItemConfinement(newX, newY);
68+
69+ setX(newX);
67 setY(newY);
70 setY(newY);
68
71
69 QPointF scenePosition = mapToItem(nullptr, QPointF(0, 0));
72 QPointF scenePosition = mapToItem(nullptr, QPointF(0, 0));
@@ -71,6 +74,31 @@ void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::Mouse
71 buttons, modifiers);
74 buttons, modifiers);
72}
75}
73
76
77+void MousePointer::applyItemConfinement(qreal &newX, qreal &newY)
78+{
79+ Q_ASSERT(parentItem() != nullptr);
80+
81+ if (m_confiningItem.isNull()) {
82+ return;
83+ }
84+
85+ QRectF confiningItemGeometry(0, 0, m_confiningItem->width(), m_confiningItem->height());
86+
87+ QRectF confiningRect = m_confiningItem->mapRectToItem(parentItem(), confiningItemGeometry);
88+
89+ if (newX < confiningRect.x()) {
90+ newX = confiningRect.x();
91+ } else if (newX > confiningRect.right()) {
92+ newX = confiningRect.right();
93+ }
94+
95+ if (newY < confiningRect.y()) {
96+ newY = confiningRect.y();
97+ } else if (newY > confiningRect.bottom()) {
98+ newY = confiningRect.bottom();
99+ }
100+}
101+
74void MousePointer::handleWheelEvent(ulong timestamp, QPoint angleDelta, Qt::KeyboardModifiers modifiers)
102void MousePointer::handleWheelEvent(ulong timestamp, QPoint angleDelta, Qt::KeyboardModifiers modifiers)
75{
103{
76 if (!parentItem()) {
104 if (!parentItem()) {
@@ -156,3 +184,16 @@ void MousePointer::setCustomCursor(const QCursor &customCursor)
156{
184{
157 CursorImageProvider::instance()->setCustomCursor(customCursor);
185 CursorImageProvider::instance()->setCustomCursor(customCursor);
158}
186}
187+
188+QQuickItem* MousePointer::confiningItem() const
189+{
190+ return m_confiningItem.data();
191+}
192+
193+void MousePointer::setConfiningItem(QQuickItem *item)
194+{
195+ if (item != m_confiningItem) {
196+ m_confiningItem = item;
197+ Q_EMIT confiningItemChanged();
198+ }
199+}
plugins/Cursor/MousePointer.h+10
@@ -27,6 +27,9 @@
27
27
28class MousePointer : public MirMousePointerInterface {
28class MousePointer : public MirMousePointerInterface {
29 Q_OBJECT
29 Q_OBJECT
30+
31+ Q_PROPERTY(QQuickItem* confiningItem READ confiningItem WRITE setConfiningItem NOTIFY confiningItemChanged)
32+
30public:
33public:
31 MousePointer(QQuickItem *parent = nullptr);
34 MousePointer(QQuickItem *parent = nullptr);
32
35
@@ -38,6 +41,9 @@ public:
38
41
39 void setCustomCursor(const QCursor &) override;
42 void setCustomCursor(const QCursor &) override;
40
43
44+ QQuickItem* confiningItem() const;
45+ void setConfiningItem(QQuickItem*);
46+
41public Q_SLOTS:
47public Q_SLOTS:
42 void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
48 void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
43 Qt::KeyboardModifiers modifiers) override;
49 Qt::KeyboardModifiers modifiers) override;
@@ -47,6 +53,7 @@ Q_SIGNALS:
47 void pushedLeftBoundary(qreal amount, Qt::MouseButtons buttons);
53 void pushedLeftBoundary(qreal amount, Qt::MouseButtons buttons);
48 void pushedRightBoundary(qreal amount, Qt::MouseButtons buttons);
54 void pushedRightBoundary(qreal amount, Qt::MouseButtons buttons);
49 void mouseMoved();
55 void mouseMoved();
56+ void confiningItemChanged();
50
57
51protected:
58protected:
52 void itemChange(ItemChange change, const ItemChangeData &value) override;
59 void itemChange(ItemChange change, const ItemChangeData &value) override;
@@ -56,6 +63,7 @@ private Q_SLOTS:
56
63
57private:
64private:
58 void registerWindow(QWindow *window);
65 void registerWindow(QWindow *window);
66+ void applyItemConfinement(qreal &newX, qreal &newY);
59
67
60 QPointer<QWindow> m_registeredWindow;
68 QPointer<QWindow> m_registeredWindow;
61 QPointer<QScreen> m_registeredScreen;
69 QPointer<QScreen> m_registeredScreen;
@@ -64,6 +72,8 @@ private:
64
72
65 // Accumulated, unapplied, mouse movement.
73 // Accumulated, unapplied, mouse movement.
66 QPointF m_accumulatedMovement;
74 QPointF m_accumulatedMovement;
75+
76+ QPointer<QQuickItem> m_confiningItem;
67};
77};
68
78
69#endif // MOUSEPOINTER_H
79#endif // MOUSEPOINTER_H
qml/Shell.qml+2
@@ -814,6 +814,8 @@ StyledItem {
814 visible: shell.hasMouse
814 visible: shell.hasMouse
815 z: itemGrabber.z + 1
815 z: itemGrabber.z + 1
816
816
817+ confiningItem: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.itemConfiningMouseCursor : null
818+
817 property bool mouseNeverMoved: true
819 property bool mouseNeverMoved: true
818 Binding {
820 Binding {
819 target: cursor; property: "x"; value: shell.width / 2
821 target: cursor; property: "x"; value: shell.width / 2
qml/Stages/AbstractStage.qml+3
@@ -55,6 +55,9 @@ FocusScope {
55 | Qt.InvertedPortraitOrientation
55 | Qt.InvertedPortraitOrientation
56 | Qt.InvertedLandscapeOrientation
56 | Qt.InvertedLandscapeOrientation
57
57
58+ property Item itemConfiningMouseCursor: null
59+
60+
58 signal stageAboutToBeUnloaded
61 signal stageAboutToBeUnloaded
59 signal itemSnapshotRequested(Item item)
62 signal itemSnapshotRequested(Item item)
60
63
qml/Stages/DecoratedWindow.qml+2
@@ -53,6 +53,8 @@ FocusScope {
53
53
54 property alias overlayShown: decoration.overlayShown
54 property alias overlayShown: decoration.overlayShown
55
55
56+ readonly property Item clientAreaItem: applicationWindow
57+
56 signal closeClicked()
58 signal closeClicked()
57 signal maximizeClicked()
59 signal maximizeClicked()
58 signal maximizeHorizontallyClicked()
60 signal maximizeHorizontallyClicked()
qml/Stages/DesktopStage.qml+6
@@ -52,6 +52,11 @@ AbstractStage {
52
52
53 orientationChangesEnabled: true
53 orientationChangesEnabled: true
54
54
55+
56+ itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.surface &&
57+ priv.focusedAppDelegate.surface.confinesMousePointer ?
58+ priv.focusedAppDelegate.clientAreaItem : null;
59+
55 GlobalShortcut {
60 GlobalShortcut {
56 id: showSpreadShortcut
61 id: showSpreadShortcut
57 shortcut: Qt.MetaModifier|Qt.Key_W
62 shortcut: Qt.MetaModifier|Qt.Key_W
@@ -335,6 +340,7 @@ AbstractStage {
335 readonly property alias focusedSurface: decoratedWindow.focusedSurface
340 readonly property alias focusedSurface: decoratedWindow.focusedSurface
336
341
337 readonly property bool isDash: model.application.appId == "unity8-dash"
342 readonly property bool isDash: model.application.appId == "unity8-dash"
343+ readonly property alias clientAreaItem: decoratedWindow.clientAreaItem
338
344
339 function claimFocus() {
345 function claimFocus() {
340 if (spread.state == "altTab") {
346 if (spread.state == "altTab") {
tests/mocks/Unity/Application/MirSurface.h+2
@@ -104,6 +104,8 @@ public:
104 bool focused() const override;
104 bool focused() const override;
105 QRect inputBounds() const override;
105 QRect inputBounds() const override;
106
106
107+ bool confinesMousePointer() const override { return false; }
108+
107 Q_INVOKABLE void requestFocus() override;
109 Q_INVOKABLE void requestFocus() override;
108
110
109 Q_INVOKABLE void close() override;
111 Q_INVOKABLE void close() override;