Merge lp:~dandrader/unity8/mouseClickSwitchesSurfaceFocus into lp:unity8

Proposed by Daniel d'Andrada on 2015-03-12
Status: Merged
Approved by: Michael Zanetti on 2015-03-24
Approved revision: 1667
Merged at revision: 1710
Proposed branch: lp:~dandrader/unity8/mouseClickSwitchesSurfaceFocus
Merge into: lp:unity8
Prerequisite: lp:~dandrader/unity8/controlTouchEmulationFromQML
Diff against target: 432 lines (+234/-18)
10 files modified
plugins/Ubuntu/Gestures/TouchGate.cpp (+0/-2)
plugins/Ubuntu/Gestures/TouchGate.h (+0/-2)
plugins/Utils/CMakeLists.txt (+1/-0)
plugins/Utils/inputwatcher.cpp (+118/-0)
plugins/Utils/inputwatcher.h (+58/-0)
plugins/Utils/plugin.cpp (+2/-0)
qml/Stages/SurfaceContainer.qml (+12/-9)
tests/mocks/Unity/Application/MirSurfaceItem.cpp (+6/-0)
tests/mocks/Unity/Application/MirSurfaceItem.h (+5/-0)
tests/qmltests/Stages/tst_SurfaceContainer.qml (+32/-5)
To merge this branch: bzr merge lp:~dandrader/unity8/mouseClickSwitchesSurfaceFocus
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing on 2015-03-24
Michael Zanetti (community) 2015-03-12 Approve on 2015-03-24
Review via email: mp+252745@code.launchpad.net

Commit Message

Surface gets active focus also with mouse clicks

Description of the Change

* Are there any related MPs required for this MP to build/function as expected? Please list.
No

* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes

* Did you make sure that your branch does not contain spurious tags?
Yes

* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
Not applicable

* If you changed the UI, has there been a design review?
Not applicable

To post a comment you must log in.
1664. By Daniel d'Andrada on 2015-03-12

Remove comment

1665. By Daniel d'Andrada on 2015-03-13

Just to trigger a new Jenkins build

Albert Astals Cid (aacid) wrote :

Lots of segfaults in the qmluitests, you may want to revise those

1666. By Daniel d'Andrada on 2015-03-19

Merge trunk

[ Albert Astals Cid ]
* Add some context to tr calls (LP: #1431497)
* Require binaries and .pc files we call from code
* Test: More stubborn flick to the end
[ Andrea Cimitan ]
* Refactor PreviewOverlay to fix weird zoom out/in animations when
  previewing images from the Previews
[ CI Train Bot ]
* Resync trunk.
[ Charles Kerr ]
* Re-enable a rotation lock test now that the bug that broke that test
  has been fixed. (LP: #1410915)
[ Daniel d'Andrada ]
* Darkened area behind indicators menu should eat input until it fully
  disappears (LP: #1417967)
* DesktopStage - fix focus switch when user taps on window (LP:
  #1431325)
* Fix warnings when launching tutorial
* Make MouseTouchAdaptor controllable from within QML
* Make tst_Shell absorb tst_TabletShell
[ Leo Arias ]
* Changed the autopilot dependencies so they do not require qt4. (LP:
  #1429158)
* Drop the support for python2 in autopilot tests. (LP: #1429163)
* Stop using the deprecated toolkit emulators namespace in autopilot
  tests. (LP: #1341681)
[ Michael Terry ]
* Don't close wizard & edge tutorial when the unity8-dash closes (LP:
  #1425484)
* Don't let the wizard sit indefinitely, waiting for a wizard page to
  finish preparing itself. (LP: #1425737)
* Fix two broken qmluitest files by waiting for everything to settle
  before starting the tests.
* Only call unlockAllModems once the wizard is done. (LP: #1425161)
  (LP: #1425161)
* When we are locking the user out from too many login failures,
  notice when time passes even if the device is suspended. (LP:
  #1396817) (LP: #1396817)
[ Michael Zanetti ]
* Add a mouse area to the indicators panel so we can open them by
  clicking. (LP: #1417650)
* fix launcher not reacting to first click when revealed by mouse
  hover, add tests
* performance improvements (LP: #1430233, #1425087)
[ Michał Sawicz ]
* Remove the activity indicator from tests
* Use targets instead of custom ld arguments for linking
[ Mirco Müller ]
* Updated the visuals of the SwipeToAct-widget for incoming-call snap-
  decision notifications according to new design-spec.
* Updated the visuals of the SwipeToAct-widget for incoming-call snap-
  decision notifications according to new design-spec.
* No-change rebuild against Qt 5.4.1.

1667. By Daniel d'Andrada on 2015-03-19

Handle null targets properly

Daniel d'Andrada (dandrader) wrote :

> Lots of segfaults in the qmluitests, you may want to revise those

Fixed. Thanks.

Michael Zanetti (mzanetti) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?

y

 * Did CI run pass? If not, please explain why.

AP

 * Did you make sure that the branch does not contain spurious tags?

yes

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/Ubuntu/Gestures/TouchGate.cpp'
2--- plugins/Ubuntu/Gestures/TouchGate.cpp 2015-01-28 12:59:21 +0000
3+++ plugins/Ubuntu/Gestures/TouchGate.cpp 2015-03-19 14:42:50 +0000
4@@ -53,8 +53,6 @@
5 m_touchInfoMap[touchPoint.id()].ownership = OwnershipRequested;
6 m_touchInfoMap[touchPoint.id()].ended = false;
7 TouchRegistry::instance()->requestTouchOwnership(touchPoint.id(), this);
8-
9- Q_EMIT pressed();
10 }
11
12 goodToGo &= m_touchInfoMap.contains(touchPoint.id())
13
14=== modified file 'plugins/Ubuntu/Gestures/TouchGate.h'
15--- plugins/Ubuntu/Gestures/TouchGate.h 2015-01-28 12:59:21 +0000
16+++ plugins/Ubuntu/Gestures/TouchGate.h 2015-03-19 14:42:50 +0000
17@@ -53,8 +53,6 @@
18 Q_SIGNALS:
19 void targetItemChanged(QQuickItem *item);
20
21- void pressed();
22-
23 protected:
24 void touchEvent(QTouchEvent *event) override;
25 private:
26
27=== modified file 'plugins/Utils/CMakeLists.txt'
28--- plugins/Utils/CMakeLists.txt 2015-02-11 17:12:22 +0000
29+++ plugins/Utils/CMakeLists.txt 2015-03-19 14:42:50 +0000
30@@ -8,6 +8,7 @@
31 )
32
33 set(QMLPLUGIN_SRC
34+ inputwatcher.cpp
35 qlimitproxymodelqml.cpp
36 unitysortfilterproxymodelqml.cpp
37 relativetimeformatter.cpp
38
39=== added file 'plugins/Utils/inputwatcher.cpp'
40--- plugins/Utils/inputwatcher.cpp 1970-01-01 00:00:00 +0000
41+++ plugins/Utils/inputwatcher.cpp 2015-03-19 14:42:50 +0000
42@@ -0,0 +1,118 @@
43+/*
44+ * Copyright (C) 2015 Canonical, Ltd.
45+ *
46+ * This program is free software; you can redistribute it and/or modify
47+ * it under the terms of the GNU General Public License as published by
48+ * the Free Software Foundation; version 3.
49+ *
50+ * This program is distributed in the hope that it will be useful,
51+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
52+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53+ * GNU General Public License for more details.
54+ *
55+ * You should have received a copy of the GNU General Public License
56+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
57+ *
58+ */
59+
60+#include "inputwatcher.h"
61+
62+#include <QMouseEvent>
63+
64+InputWatcher::InputWatcher(QObject *parent)
65+ : QObject(parent)
66+ , m_mousePressed(false)
67+ , m_touchPressed(false)
68+{
69+}
70+
71+QObject *InputWatcher::target() const
72+{
73+ return m_target;
74+}
75+
76+void InputWatcher::setTarget(QObject *value)
77+{
78+ if (m_target == value) {
79+ return;
80+ }
81+
82+ if (m_target) {
83+ m_target->removeEventFilter(this);
84+ }
85+
86+ setMousePressed(false);
87+ setTouchPressed(false);
88+
89+ m_target = value;
90+ if (m_target) {
91+ m_target->installEventFilter(this);
92+ }
93+
94+ Q_EMIT targetChanged(value);
95+}
96+
97+bool InputWatcher::targetPressed() const
98+{
99+ return m_mousePressed || m_touchPressed;
100+}
101+
102+bool InputWatcher::eventFilter(QObject* /*watched*/, QEvent *event)
103+{
104+ switch (event->type()) {
105+ case QEvent::TouchBegin:
106+ setTouchPressed(true);
107+ break;
108+ case QEvent::TouchEnd:
109+ setTouchPressed(false);
110+ break;
111+ case QEvent::MouseButtonPress:
112+ {
113+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
114+ if (mouseEvent->button() == Qt::LeftButton) {
115+ setMousePressed(true);
116+ }
117+ }
118+ break;
119+ case QEvent::MouseButtonRelease:
120+ {
121+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
122+ if (mouseEvent->button() == Qt::LeftButton) {
123+ setMousePressed(false);
124+ }
125+ }
126+ break;
127+ default:
128+ // Not interested
129+ break;
130+ }
131+
132+ // We never filter them out. We are just watching.
133+ return false;
134+}
135+
136+void InputWatcher::setMousePressed(bool value)
137+{
138+ if (value == m_mousePressed) {
139+ return;
140+ }
141+
142+ bool oldPressed = targetPressed();
143+ m_mousePressed = value;
144+ if (targetPressed() != oldPressed) {
145+ Q_EMIT targetPressedChanged(targetPressed());
146+ }
147+}
148+
149+void InputWatcher::setTouchPressed(bool value)
150+{
151+ if (value == m_touchPressed) {
152+ return;
153+ }
154+
155+ bool oldPressed = targetPressed();
156+ m_touchPressed = value;
157+ if (targetPressed() != oldPressed) {
158+ Q_EMIT targetPressedChanged(targetPressed());
159+ }
160+}
161
162=== added file 'plugins/Utils/inputwatcher.h'
163--- plugins/Utils/inputwatcher.h 1970-01-01 00:00:00 +0000
164+++ plugins/Utils/inputwatcher.h 2015-03-19 14:42:50 +0000
165@@ -0,0 +1,58 @@
166+/*
167+ * Copyright (C) 2015 Canonical, Ltd.
168+ *
169+ * This program is free software; you can redistribute it and/or modify
170+ * it under the terms of the GNU General Public License as published by
171+ * the Free Software Foundation; version 3.
172+ *
173+ * This program is distributed in the hope that it will be useful,
174+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
175+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
176+ * GNU General Public License for more details.
177+ *
178+ * You should have received a copy of the GNU General Public License
179+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
180+ *
181+ */
182+
183+#ifndef UNITY_INPUTWATCHER_H
184+#define UNITY_INPUTWATCHER_H
185+
186+#include <QObject>
187+#include <QPointer>
188+
189+/*
190+ Monitors the target object for input events to figure out whether it's pressed
191+ or not.
192+ */
193+class InputWatcher : public QObject
194+{
195+ Q_OBJECT
196+ Q_PROPERTY(QObject* target READ target WRITE setTarget NOTIFY targetChanged)
197+
198+ // Whether the target object is pressed (by either touch or mouse)
199+ Q_PROPERTY(bool targetPressed READ targetPressed NOTIFY targetPressedChanged)
200+public:
201+ InputWatcher(QObject *parent = nullptr);
202+
203+ QObject *target() const;
204+ void setTarget(QObject *value);
205+
206+ bool targetPressed() const;
207+
208+ bool eventFilter(QObject *watched, QEvent *event) override;
209+
210+Q_SIGNALS:
211+ void targetChanged(QObject *value);
212+ void targetPressedChanged(bool value);
213+
214+private:
215+ void setMousePressed(bool value);
216+ void setTouchPressed(bool value);
217+
218+ bool m_mousePressed;
219+ bool m_touchPressed;
220+ QPointer<QObject> m_target;
221+};
222+
223+#endif // UNITY_INPUTWATCHER_H
224
225=== modified file 'plugins/Utils/plugin.cpp'
226--- plugins/Utils/plugin.cpp 2015-02-10 17:03:11 +0000
227+++ plugins/Utils/plugin.cpp 2015-03-19 14:42:50 +0000
228@@ -26,6 +26,7 @@
229 #include "plugin.h"
230
231 // local
232+#include "inputwatcher.h"
233 #include "qlimitproxymodelqml.h"
234 #include "unitysortfilterproxymodelqml.h"
235 #include "relativetimeformatter.h"
236@@ -55,6 +56,7 @@
237 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
238 qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter");
239 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
240+ qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
241 }
242
243 void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
244
245=== modified file 'qml/Stages/SurfaceContainer.qml'
246--- qml/Stages/SurfaceContainer.qml 2015-01-28 12:59:21 +0000
247+++ qml/Stages/SurfaceContainer.qml 2015-03-19 14:42:50 +0000
248@@ -1,5 +1,5 @@
249 /*
250- * Copyright 2014 Canonical Ltd.
251+ * Copyright 2014-2015 Canonical Ltd.
252 *
253 * This program is free software; you can redistribute it and/or modify
254 * it under the terms of the GNU Lesser General Public License as published by
255@@ -17,6 +17,7 @@
256 import QtQuick 2.0
257 import Ubuntu.Components 1.1
258 import Ubuntu.Gestures 0.1 // For TouchGate
259+import Utils 0.1 // for InputWatcher
260
261 FocusScope {
262 id: root
263@@ -26,8 +27,6 @@
264 property int orientation
265 property bool interactive
266
267- signal surfacePressed()
268-
269 onSurfaceChanged: {
270 if (surface) {
271 // Set the surface focus *after* it is added to the scene to
272@@ -45,17 +44,21 @@
273 Binding { target: surface; property: "enabled"; value: root.interactive; when: surface }
274 Binding { target: surface; property: "antialiasing"; value: !root.interactive; when: surface }
275
276+ InputWatcher {
277+ target: root.surface
278+ onTargetPressedChanged: {
279+ if (targetPressed && root.interactive) {
280+ root.focus = true;
281+ root.forceActiveFocus();
282+ }
283+ }
284+ }
285+
286 TouchGate {
287 targetItem: surface
288 anchors.fill: root
289 enabled: root.surface ? root.surface.enabled : false
290 z: 2
291- onPressed: {
292- root.focus = true;
293- if (root.interactive) {
294- root.forceActiveFocus();
295- }
296- }
297 }
298
299 states: [
300
301=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.cpp'
302--- tests/mocks/Unity/Application/MirSurfaceItem.cpp 2014-10-01 13:20:32 +0000
303+++ tests/mocks/Unity/Application/MirSurfaceItem.cpp 2015-03-19 14:42:50 +0000
304@@ -47,6 +47,12 @@
305 {
306 qDebug() << "MirSurfaceItem::MirSurfaceItem() " << this->name();
307
308+ setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
309+ Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
310+ Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
311+ Qt::ExtraButton9 | Qt::ExtraButton10 | Qt::ExtraButton11 |
312+ Qt::ExtraButton12 | Qt::ExtraButton13);
313+
314 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
315
316 connect(this, &QQuickItem::focusChanged,
317
318=== modified file 'tests/mocks/Unity/Application/MirSurfaceItem.h'
319--- tests/mocks/Unity/Application/MirSurfaceItem.h 2014-10-01 13:20:32 +0000
320+++ tests/mocks/Unity/Application/MirSurfaceItem.h 2015-03-19 14:42:50 +0000
321@@ -104,6 +104,11 @@
322 protected:
323 void touchEvent(QTouchEvent * event) override;
324
325+ // becaue the default implementation ignores the events
326+ void mousePressEvent(QMouseEvent *) override {}
327+ void mouseMoveEvent(QMouseEvent *) override {}
328+ void mouseReleaseEvent(QMouseEvent *) override {}
329+
330 private Q_SLOTS:
331 void onFocusChanged();
332 void onComponentStatusChanged(QQmlComponent::Status status);
333
334=== modified file 'tests/qmltests/Stages/tst_SurfaceContainer.qml'
335--- tests/qmltests/Stages/tst_SurfaceContainer.qml 2014-10-01 13:20:32 +0000
336+++ tests/qmltests/Stages/tst_SurfaceContainer.qml 2015-03-19 14:42:50 +0000
337@@ -1,5 +1,5 @@
338 /*
339- * Copyright 2014 Canonical Ltd.
340+ * Copyright 2014-2015 Canonical Ltd.
341 *
342 * This program is free software; you can redistribute it and/or modify
343 * it under the terms of the GNU General Public License as published by
344@@ -16,7 +16,7 @@
345
346 import QtQuick 2.0
347 import QtTest 1.0
348-import Unity.Test 0.1 as UT
349+import Unity.Test 0.1
350 import ".."
351 import "../../../qml/Stages"
352 import Ubuntu.Components 0.1
353@@ -32,6 +32,8 @@
354 id: surfaceContainerComponent
355 SurfaceContainer {
356 anchors.fill: parent
357+ orientation: Qt.PortraitOrientation
358+ interactive: interactiveCheckbox.checked
359 }
360 }
361 Loader {
362@@ -85,6 +87,12 @@
363 CheckBox {id: fullscreenCheckbox; checked: true; }
364 Label { text: "fullscreen" }
365 }
366+ Row {
367+ anchors { left: parent.left; right: parent.right }
368+ CheckBox {id: interactiveCheckbox; checked: true; }
369+ Label { text: "interactive" }
370+ }
371+ MouseTouchEmulationCheckbox {}
372 }
373 }
374
375@@ -94,7 +102,7 @@
376 signalName: "surfaceDestroyed"
377 }
378
379- UT.UnityTestCase {
380+ UnityTestCase {
381 id: testCase
382 name: "SurfaceContainer"
383 when: windowShown
384@@ -110,6 +118,8 @@
385
386 tryCompare(surfaceContainerLoader.item, "surface", null);
387 surfaceSpy.clear();
388+
389+ interactiveCheckbox.checked = true;
390 }
391
392 /*
393@@ -145,14 +155,13 @@
394 surfaceContainer.surface.touchPressCount = 0;
395 surfaceContainer.surface.touchReleaseCount = 0;
396
397- surfaceContainer.interactive = true;
398 tap(surfaceContainer, surfaceContainer.width / 2, surfaceContainer.height / 2);
399
400 // surface got touches as the surfaceContainer is interactive
401 compare(surfaceContainer.surface.touchPressCount, 1)
402 compare(surfaceContainer.surface.touchReleaseCount, 1);
403
404- surfaceContainer.interactive = false;
405+ interactiveCheckbox.checked = false;
406 tap(surfaceContainer, surfaceContainer.width / 2, surfaceContainer.height / 2);
407
408 // surface shouldn't get the touches from the second tap as the surfaceContainer
409@@ -160,5 +169,23 @@
410 compare(surfaceContainer.surface.touchPressCount, 1)
411 compare(surfaceContainer.surface.touchReleaseCount, 1);
412 }
413+
414+ function test_surfaceGetsActiveFocusOnMousePress() {
415+ surfaceCheckbox.checked = true;
416+ verify(surfaceContainer.surface !== null);
417+
418+ compare(surfaceContainer.surface.activeFocus, false);
419+ mouseClick(surfaceContainer);
420+ compare(surfaceContainer.surface.activeFocus, true);
421+ }
422+
423+ function test_surfaceGetsActiveFocusOnTap() {
424+ surfaceCheckbox.checked = true;
425+ verify(surfaceContainer.surface !== null);
426+
427+ compare(surfaceContainer.surface.activeFocus, false);
428+ tap(surfaceContainer);
429+ compare(surfaceContainer.surface.activeFocus, true);
430+ }
431 }
432 }

Subscribers

People subscribed via source and target branches