on xenial help sign in
Implement cursor confinement
commit2daaabd8465f12a6090e8fa42f0de8d76656c82d authorDaniel d'Andrada <daniel.dandrada@canonical.com> dateFri 2 Sep 2016, 11:08 (10 years ago) parent1612875
9 files changed+71−5
CMakeLists.txt+1−1 debian/control+3−3 plugins/Cursor/MousePointer.cpp+42−1 plugins/Cursor/MousePointer.h+10 qml/Shell.qml+2 qml/Stages/AbstractStage.qml+3 qml/Stages/DecoratedWindow.qml+2 qml/Stages/DesktopStage.qml+6 tests/mocks/Unity/Application/MirSurface.h+2
CMakeLists.txt+1−1
@@ -57,7 +57,7 @@ find_package(Qt5DBus 5.4 REQUIRED)
5757find_package(Qt5Concurrent 5.4 REQUIRED)
5858find_package(Qt5Sql 5.4 REQUIRED)
5959
60−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=20)
60+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=21)
6161pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
6262pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
6363pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
debian/control+3−3
@@ -37,7 +37,7 @@ Build-Depends: cmake,
3737 libubuntugestures5-private-dev (>= 1.3.2030),
3838 libudev-dev,
3939 libudm-common-dev,
40− libunity-api-dev (>= 7.117),
40+ libunity-api-dev (>= 7.118),
4141 libusermetricsoutput1-dev,
4242# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
4343 libx11-dev[!arm64 !armhf],
@@ -157,7 +157,7 @@ Depends: qml-module-qtquick-layouts,
157157 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
158158 ubuntu-thumbnailer-impl-0,
159159 ubuntu-wallpapers,
160− unity-application-impl-20,
160+ unity-application-impl-21,
161161 unity-notifications-impl-3,
162162 unity-plugin-scopes | unity-scopes-impl,
163163 unity-scopes-impl-12,
@@ -203,7 +203,7 @@ Pre-Depends: ${misc:Pre-Depends},
203203Depends: ${misc:Depends},
204204 ${shlibs:Depends},
205205Provides: unity-application-impl,
206− unity-application-impl-20,
206+ unity-application-impl-21,
207207Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
208208Description: Fake environment for running Unity 8 shell
209209 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
5656 Q_EMIT pushedRightBoundary(newX - (parentItem()->width() - 1), buttons);
5757 newX = parentItem()->width() - 1;
5858 }
59− setX(newX);
6059
6160 qreal newY = y() + appliedMovement.y();
6261 if (newY < 0) {
@@ -64,6 +63,10 @@ void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::Mouse
6463 } else if (newY >= parentItem()->height()) {
6564 newY = parentItem()->height() - 1;
6665 }
66+
67+ applyItemConfinement(newX, newY);
68+
69+ setX(newX);
6770 setY(newY);
6871
6972 QPointF scenePosition = mapToItem(nullptr, QPointF(0, 0));
@@ -71,6 +74,31 @@ void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::Mouse
7174 buttons, modifiers);
7275}
7376
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+
74102void MousePointer::handleWheelEvent(ulong timestamp, QPoint angleDelta, Qt::KeyboardModifiers modifiers)
75103{
76104 if (!parentItem()) {
@@ -156,3 +184,16 @@ void MousePointer::setCustomCursor(const QCursor &customCursor)
156184{
157185 CursorImageProvider::instance()->setCustomCursor(customCursor);
158186}
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 @@
2727
2828class MousePointer : public MirMousePointerInterface {
2929 Q_OBJECT
30+
31+ Q_PROPERTY(QQuickItem* confiningItem READ confiningItem WRITE setConfiningItem NOTIFY confiningItemChanged)
32+
3033public:
3134 MousePointer(QQuickItem *parent = nullptr);
3235
@@ -38,6 +41,9 @@ public:
3841
3942 void setCustomCursor(const QCursor &) override;
4043
44+ QQuickItem* confiningItem() const;
45+ void setConfiningItem(QQuickItem*);
46+
4147public Q_SLOTS:
4248 void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
4349 Qt::KeyboardModifiers modifiers) override;
@@ -47,6 +53,7 @@ Q_SIGNALS:
4753 void pushedLeftBoundary(qreal amount, Qt::MouseButtons buttons);
4854 void pushedRightBoundary(qreal amount, Qt::MouseButtons buttons);
4955 void mouseMoved();
56+ void confiningItemChanged();
5057
5158protected:
5259 void itemChange(ItemChange change, const ItemChangeData &value) override;
@@ -56,6 +63,7 @@ private Q_SLOTS:
5663
5764private:
5865 void registerWindow(QWindow *window);
66+ void applyItemConfinement(qreal &newX, qreal &newY);
5967
6068 QPointer<QWindow> m_registeredWindow;
6169 QPointer<QScreen> m_registeredScreen;
@@ -64,6 +72,8 @@ private:
6472
6573 // Accumulated, unapplied, mouse movement.
6674 QPointF m_accumulatedMovement;
75+
76+ QPointer<QQuickItem> m_confiningItem;
6777};
6878
6979#endif // MOUSEPOINTER_H
qml/Shell.qml+2
@@ -814,6 +814,8 @@ StyledItem {
814814 visible: shell.hasMouse
815815 z: itemGrabber.z + 1
816816
817+ confiningItem: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.itemConfiningMouseCursor : null
818+
817819 property bool mouseNeverMoved: true
818820 Binding {
819821 target: cursor; property: "x"; value: shell.width / 2
qml/Stages/AbstractStage.qml+3
@@ -55,6 +55,9 @@ FocusScope {
5555 | Qt.InvertedPortraitOrientation
5656 | Qt.InvertedLandscapeOrientation
5757
58+ property Item itemConfiningMouseCursor: null
59+
60+
5861 signal stageAboutToBeUnloaded
5962 signal itemSnapshotRequested(Item item)
6063
qml/Stages/DecoratedWindow.qml+2
@@ -53,6 +53,8 @@ FocusScope {
5353
5454 property alias overlayShown: decoration.overlayShown
5555
56+ readonly property Item clientAreaItem: applicationWindow
57+
5658 signal closeClicked()
5759 signal maximizeClicked()
5860 signal maximizeHorizontallyClicked()
qml/Stages/DesktopStage.qml+6
@@ -52,6 +52,11 @@ AbstractStage {
5252
5353 orientationChangesEnabled: true
5454
55+
56+ itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.surface &&
57+ priv.focusedAppDelegate.surface.confinesMousePointer ?
58+ priv.focusedAppDelegate.clientAreaItem : null;
59+
5560 GlobalShortcut {
5661 id: showSpreadShortcut
5762 shortcut: Qt.MetaModifier|Qt.Key_W
@@ -335,6 +340,7 @@ AbstractStage {
335340 readonly property alias focusedSurface: decoratedWindow.focusedSurface
336341
337342 readonly property bool isDash: model.application.appId == "unity8-dash"
343+ readonly property alias clientAreaItem: decoratedWindow.clientAreaItem
338344
339345 function claimFocus() {
340346 if (spread.state == "altTab") {
tests/mocks/Unity/Application/MirSurface.h+2
@@ -104,6 +104,8 @@ public:
104104 bool focused() const override;
105105 QRect inputBounds() const override;
106106
107+ bool confinesMousePointer() const override { return false; }
108+
107109 Q_INVOKABLE void requestFocus() override;
108110
109111 Q_INVOKABLE void close() override;