on xenial help sign in
Implement cursor confinement (LP: #1590099)
999ef19Daniel 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=21)
60+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=22)
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.118),
40+ libunity-api-dev (>= 7.119),
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-21,
160+ unity-application-impl-22,
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-21,
206+ unity-application-impl-22,
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
@@ -813,6 +813,8 @@ StyledItem {
813 visible: shell.hasMouse
813 visible: shell.hasMouse
814 z: itemGrabber.z + 1
814 z: itemGrabber.z + 1
815
815
816+ confiningItem: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.itemConfiningMouseCursor : null
817+
816 property bool mouseNeverMoved: true
818 property bool mouseNeverMoved: true
817 Binding {
819 Binding {
818 target: cursor; property: "x"; value: shell.width / 2
820 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/Cursor/Cursor.qml+2−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
17import QtQuick 2.4
17import QtQuick 2.4
18
18
19Item {
19Item {
20+ property Item confiningItem
20 signal pushedLeftBoundary(real amount, int buttons)
21 signal pushedLeftBoundary(real amount, int buttons)
21 signal pushedRightBoundary(real amount, int buttons)
22 signal pushedRightBoundary(real amount, int buttons)
22 signal mouseMoved()
23 signal mouseMoved()
tests/mocks/Unity/Application/MirSurface.h+2
@@ -106,6 +106,8 @@ public:
106 bool focused() const override;
106 bool focused() const override;
107 QRect inputBounds() const override;
107 QRect inputBounds() const override;
108
108
109+ bool confinesMousePointer() const override { return false; }
110+
109 Q_INVOKABLE void requestFocus() override;
111 Q_INVOKABLE void requestFocus() override;
110
112
111 Q_INVOKABLE void close() override;
113 Q_INVOKABLE void close() override;