on xenial help sign in
merged with lp:~dandrader/unity8/mouseClickSwitchesSurfaceFocus
commitf54591a73e7014a6b72d31cfda1e04dce341bfc5 authorNick Dedekind <nick.dedekind@canonical.com> dateThu 2 Apr 2015, 11:32 (12 years ago) parente885a33a1b46e0
10 files changed+234−18
plugins/Ubuntu/Gestures/TouchGate.cpp−2 plugins/Ubuntu/Gestures/TouchGate.h−2 plugins/Utils/CMakeLists.txt+1 plugins/Utils/inputwatcher.cpp+118 plugins/Utils/inputwatcher.h+58 plugins/Utils/plugin.cpp+2 qml/Stages/SurfaceContainer.qml+12−9 tests/mocks/Unity/Application/MirSurfaceItem.cpp+6 tests/mocks/Unity/Application/MirSurfaceItem.h+5 tests/qmltests/Stages/tst_SurfaceContainer.qml+32−5
plugins/Ubuntu/Gestures/TouchGate.cpp−2
@@ -53,8 +53,6 @@ void TouchGate::touchEvent(QTouchEvent *event)
5353 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
5454 m_touchInfoMap[touchPoint.id()].ended = false;
5555 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
56−
57− Q_EMIT pressed();
5856 }
5957
6058 goodToGo &= m_touchInfoMap.contains(touchPoint.id())
plugins/Ubuntu/Gestures/TouchGate.h−2
@@ -53,8 +53,6 @@ public:
5353Q_SIGNALS:
5454 void targetItemChanged(QQuickItem *item);
5555
56− void pressed();
57−
5856protected:
5957 void touchEvent(QTouchEvent *event) override;
6058private:
plugins/Utils/CMakeLists.txt+1
@@ -9,6 +9,7 @@ include_directories(
99
1010set(QMLPLUGIN_SRC
1111 constants.cpp
12+ inputwatcher.cpp
1213 qlimitproxymodelqml.cpp
1314 unitysortfilterproxymodelqml.cpp
1415 relativetimeformatter.cpp
plugins/Utils/inputwatcher.cppnew file+118
@@ -0,0 +1,118 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
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
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ */
17+
18+#include "inputwatcher.h"
19+
20+#include <QMouseEvent>
21+
22+InputWatcher::InputWatcher(QObject *parent)
23+ : QObject(parent)
24+ , m_mousePressed(false)
25+ , m_touchPressed(false)
26+{
27+}
28+
29+QObject *InputWatcher::target() const
30+{
31+ return m_target;
32+}
33+
34+void InputWatcher::setTarget(QObject *value)
35+{
36+ if (m_target == value) {
37+ return;
38+ }
39+
40+ if (m_target) {
41+ m_target->removeEventFilter(this);
42+ }
43+
44+ setMousePressed(false);
45+ setTouchPressed(false);
46+
47+ m_target = value;
48+ if (m_target) {
49+ m_target->installEventFilter(this);
50+ }
51+
52+ Q_EMIT targetChanged(value);
53+}
54+
55+bool InputWatcher::targetPressed() const
56+{
57+ return m_mousePressed || m_touchPressed;
58+}
59+
60+bool InputWatcher::eventFilter(QObject* /*watched*/, QEvent *event)
61+{
62+ switch (event->type()) {
63+ case QEvent::TouchBegin:
64+ setTouchPressed(true);
65+ break;
66+ case QEvent::TouchEnd:
67+ setTouchPressed(false);
68+ break;
69+ case QEvent::MouseButtonPress:
70+ {
71+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
72+ if (mouseEvent->button() == Qt::LeftButton) {
73+ setMousePressed(true);
74+ }
75+ }
76+ break;
77+ case QEvent::MouseButtonRelease:
78+ {
79+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
80+ if (mouseEvent->button() == Qt::LeftButton) {
81+ setMousePressed(false);
82+ }
83+ }
84+ break;
85+ default:
86+ // Not interested
87+ break;
88+ }
89+
90+ // We never filter them out. We are just watching.
91+ return false;
92+}
93+
94+void InputWatcher::setMousePressed(bool value)
95+{
96+ if (value == m_mousePressed) {
97+ return;
98+ }
99+
100+ bool oldPressed = targetPressed();
101+ m_mousePressed = value;
102+ if (targetPressed() != oldPressed) {
103+ Q_EMIT targetPressedChanged(targetPressed());
104+ }
105+}
106+
107+void InputWatcher::setTouchPressed(bool value)
108+{
109+ if (value == m_touchPressed) {
110+ return;
111+ }
112+
113+ bool oldPressed = targetPressed();
114+ m_touchPressed = value;
115+ if (targetPressed() != oldPressed) {
116+ Q_EMIT targetPressedChanged(targetPressed());
117+ }
118+}
plugins/Utils/inputwatcher.hnew file+58
@@ -0,0 +1,58 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
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
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ */
17+
18+#ifndef UNITY_INPUTWATCHER_H
19+#define UNITY_INPUTWATCHER_H
20+
21+#include <QObject>
22+#include <QPointer>
23+
24+/*
25+ Monitors the target object for input events to figure out whether it's pressed
26+ or not.
27+ */
28+class InputWatcher : public QObject
29+{
30+ Q_OBJECT
31+ Q_PROPERTY(QObject* target READ target WRITE setTarget NOTIFY targetChanged)
32+
33+ // Whether the target object is pressed (by either touch or mouse)
34+ Q_PROPERTY(bool targetPressed READ targetPressed NOTIFY targetPressedChanged)
35+public:
36+ InputWatcher(QObject *parent = nullptr);
37+
38+ QObject *target() const;
39+ void setTarget(QObject *value);
40+
41+ bool targetPressed() const;
42+
43+ bool eventFilter(QObject *watched, QEvent *event) override;
44+
45+Q_SIGNALS:
46+ void targetChanged(QObject *value);
47+ void targetPressedChanged(bool value);
48+
49+private:
50+ void setMousePressed(bool value);
51+ void setTouchPressed(bool value);
52+
53+ bool m_mousePressed;
54+ bool m_touchPressed;
55+ QPointer<QObject> m_target;
56+};
57+
58+#endif // UNITY_INPUTWATCHER_H
plugins/Utils/plugin.cpp+2
@@ -26,6 +26,7 @@
2626#include "plugin.h"
2727
2828// local
29+#include "inputwatcher.h"
2930#include "qlimitproxymodelqml.h"
3031#include "unitysortfilterproxymodelqml.h"
3132#include "relativetimeformatter.h"
@@ -62,6 +63,7 @@ void UtilsPlugin::registerTypes(const char *uri)
6263 qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
6364 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
6465 qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter");
66+ qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
6567 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
6668 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
6769}
qml/Stages/SurfaceContainer.qml+12−9
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -17,6 +17,7 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 1.1
1919import Ubuntu.Gestures 0.1 // For TouchGate
20+import Utils 0.1 // for InputWatcher
2021
2122FocusScope {
2223 id: root
@@ -26,8 +27,6 @@ FocusScope {
2627 property int orientation
2728 property bool interactive
2829
29− signal surfacePressed()
30−
3130 onSurfaceChanged: {
3231 if (surface) {
3332 // Set the surface focus *after* it is added to the scene to
@@ -45,17 +44,21 @@ FocusScope {
4544 Binding { target: surface; property: "enabled"; value: root.interactive; when: surface }
4645 Binding { target: surface; property: "antialiasing"; value: !root.interactive; when: surface }
4746
47+ InputWatcher {
48+ target: root.surface
49+ onTargetPressedChanged: {
50+ if (targetPressed && root.interactive) {
51+ root.focus = true;
52+ root.forceActiveFocus();
53+ }
54+ }
55+ }
56+
4857 TouchGate {
4958 targetItem: surface
5059 anchors.fill: root
5160 enabled: root.surface ? root.surface.enabled : false
5261 z: 2
53− onPressed: {
54− root.focus = true;
55− if (root.interactive) {
56− root.forceActiveFocus();
57− }
58− }
5962 }
6063
6164 states: [
tests/mocks/Unity/Application/MirSurfaceItem.cpp+6
@@ -47,6 +47,12 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
4747{
4848 qDebug() << "MirSurfaceItem::MirSurfaceItem() " << this->name();
4949
50+ setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
51+ Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
52+ Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
53+ Qt::ExtraButton9 | Qt::ExtraButton10 | Qt::ExtraButton11 |
54+ Qt::ExtraButton12 | Qt::ExtraButton13);
55+
5056 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
5157
5258 connect(this, &QQuickItem::focusChanged,
tests/mocks/Unity/Application/MirSurfaceItem.h+5
@@ -104,6 +104,11 @@ Q_SIGNALS:
104104protected:
105105 void touchEvent(QTouchEvent * event) override;
106106
107+ // becaue the default implementation ignores the events
108+ void mousePressEvent(QMouseEvent *) override {}
109+ void mouseMoveEvent(QMouseEvent *) override {}
110+ void mouseReleaseEvent(QMouseEvent *) override {}
111+
107112private Q_SLOTS:
108113 void onFocusChanged();
109114 void onComponentStatusChanged(QQmlComponent::Status status);
tests/qmltests/Stages/tst_SurfaceContainer.qml+32−5
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2014 Canonical Ltd.
2+ * Copyright 2014-2015 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
1616
1717import QtQuick 2.0
1818import QtTest 1.0
19−import Unity.Test 0.1 as UT
19+import Unity.Test 0.1
2020import ".."
2121import "../../../qml/Stages"
2222import Ubuntu.Components 0.1
@@ -32,6 +32,8 @@ Rectangle {
3232 id: surfaceContainerComponent
3333 SurfaceContainer {
3434 anchors.fill: parent
35+ orientation: Qt.PortraitOrientation
36+ interactive: interactiveCheckbox.checked
3537 }
3638 }
3739 Loader {
@@ -85,6 +87,12 @@ Rectangle {
8587 CheckBox {id: fullscreenCheckbox; checked: true; }
8688 Label { text: "fullscreen" }
8789 }
90+ Row {
91+ anchors { left: parent.left; right: parent.right }
92+ CheckBox {id: interactiveCheckbox; checked: true; }
93+ Label { text: "interactive" }
94+ }
95+ MouseTouchEmulationCheckbox {}
8896 }
8997 }
9098
@@ -94,7 +102,7 @@ Rectangle {
94102 signalName: "surfaceDestroyed"
95103 }
96104
97− UT.UnityTestCase {
105+ UnityTestCase {
98106 id: testCase
99107 name: "SurfaceContainer"
100108 when: windowShown
@@ -110,6 +118,8 @@ Rectangle {
110118
111119 tryCompare(surfaceContainerLoader.item, "surface", null);
112120 surfaceSpy.clear();
121+
122+ interactiveCheckbox.checked = true;
113123 }
114124
115125 /*
@@ -145,14 +155,13 @@ Rectangle {
145155 surfaceContainer.surface.touchPressCount = 0;
146156 surfaceContainer.surface.touchReleaseCount = 0;
147157
148− surfaceContainer.interactive = true;
149158 tap(surfaceContainer, surfaceContainer.width / 2, surfaceContainer.height / 2);
150159
151160 // surface got touches as the surfaceContainer is interactive
152161 compare(surfaceContainer.surface.touchPressCount, 1)
153162 compare(surfaceContainer.surface.touchReleaseCount, 1);
154163
155− surfaceContainer.interactive = false;
164+ interactiveCheckbox.checked = false;
156165 tap(surfaceContainer, surfaceContainer.width / 2, surfaceContainer.height / 2);
157166
158167 // surface shouldn't get the touches from the second tap as the surfaceContainer
@@ -160,5 +169,23 @@ Rectangle {
160169 compare(surfaceContainer.surface.touchPressCount, 1)
161170 compare(surfaceContainer.surface.touchReleaseCount, 1);
162171 }
172+
173+ function test_surfaceGetsActiveFocusOnMousePress() {
174+ surfaceCheckbox.checked = true;
175+ verify(surfaceContainer.surface !== null);
176+
177+ compare(surfaceContainer.surface.activeFocus, false);
178+ mouseClick(surfaceContainer);
179+ compare(surfaceContainer.surface.activeFocus, true);
180+ }
181+
182+ function test_surfaceGetsActiveFocusOnTap() {
183+ surfaceCheckbox.checked = true;
184+ verify(surfaceContainer.surface !== null);
185+
186+ compare(surfaceContainer.surface.activeFocus, false);
187+ tap(surfaceContainer);
188+ compare(surfaceContainer.surface.activeFocus, true);
189+ }
163190 }
164191}