Merge lp:~dandrader/unity8/runningAppsEndClose into lp:unity8
- runningAppsEndClose
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Michał Sawicz |
Approved revision: | 555 |
Merged at revision: | 565 |
Proposed branch: | lp:~dandrader/unity8/runningAppsEndClose |
Merge into: | lp:unity8 |
Prerequisite: | lp:~dandrader/unity8/gestureTestsBaseClass |
Diff against target: |
531 lines (+437/-1) 10 files modified
Dash/Apps/RunningApplicationsGrid.qml (+17/-0) plugins/Ubuntu/Gestures/CMakeLists.txt (+1/-0) plugins/Ubuntu/Gestures/PressedOutsideNotifier.cpp (+119/-0) plugins/Ubuntu/Gestures/PressedOutsideNotifier.h (+62/-0) plugins/Ubuntu/Gestures/plugin.cpp (+2/-0) tests/plugins/Ubuntu/Gestures/CMakeLists.txt (+1/-0) tests/plugins/Ubuntu/Gestures/tst_PressedOutsideNotifier.cpp (+150/-0) tests/plugins/Ubuntu/Gestures/tst_PressedOutsideNotifier.qml (+62/-0) tests/qmltests/CMakeLists.txt (+3/-1) tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml (+20/-0) |
To merge this branch: | bzr merge lp:~dandrader/unity8/runningAppsEndClose |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Albert Astals Cid (community) | Approve | ||
Michał Sawicz | Pending | ||
Review via email: mp+196257@code.launchpad.net |
This proposal supersedes a proposal from 2013-11-20.
Commit message
Dash: disable close mode when you click outside app thumbnails
To leave the termination mode you can now just mouse/touch press anywhere
outside the running applications' thumbnails
The other way, which still works, is long-pressing a thumbnail once more.
Description of the change
Fixes bug 1193414.
InverseMouseArea is not fit for this job (e.g. doesn't work with touches when in topMostMode), thus I created a simple, light-weight, PressedOutsideN
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal | # |
tst_PressedOuts
BUT... Isn't InverseMouseArea supposed to do the same thing?
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> tst_PressedOuts
Fixed.
> BUT... Isn't InverseMouseArea supposed to do the same thing?
Kind-of, but it's hindered by all the promises its API makes (it's a bit of a mess IMHO) and doesn't really work for that case. Have you read the description?
e.g.: It would have, for instance, to monitor touch events and translate them to mouse events himself because it's a Inverse*Mouse*Area. When its topMost property is on it listens for input events at a level before QQuickWindow is able to synthesize touch events out of mouse events.
Thus instead of trying to have it working for our case it's easier to come up with something concise and simple designed to fit perfectly with our needs. Since we're not a library, we're free to do this kind of things, which is good.
I don't see the point in striving to use InverseMouseArea just for the sake of using it because it already exists. If it's about improving InverseMouseArea itself, I'm not too hopeful.
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
> e.g.: It would have, for instance, to monitor touch events and translate them
> to mouse events himself because it's a Inverse*Mouse*Area. When its topMost
> property is on it listens for input events at a level before QQuickWindow is
> able to synthesize touch events out of mouse events.
But didn't you have a patch for Qt to fix that?
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> > e.g.: It would have, for instance, to monitor touch events and translate
> them
> > to mouse events himself because it's a Inverse*Mouse*Area. When its topMost
> > property is on it listens for input events at a level before QQuickWindow is
> > able to synthesize touch events out of mouse events.
>
> But didn't you have a patch for Qt to fix that?
No. That's a different topic. But maybe InverseMouseArea does it to workaround that bug.
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
> > > e.g.: It would have, for instance, to monitor touch events and translate
> > them
> > > to mouse events himself because it's a Inverse*Mouse*Area. When its
> topMost
> > > property is on it listens for input events at a level before QQuickWindow
> is
> > > able to synthesize touch events out of mouse events.
> >
> > But didn't you have a patch for Qt to fix that?
>
> No. That's a different topic. But maybe InverseMouseArea does it to workaround
> that bug.
Oh, it was my understanding that you where making the synthezised events go properly through the event stack again and thus they'd be caught by the InverseMouseArea and everything would just work.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> > > > e.g.: It would have, for instance, to monitor touch events and translate
> > > them
> > > > to mouse events himself because it's a Inverse*Mouse*Area. When its
> > topMost
> > > > property is on it listens for input events at a level before
> QQuickWindow
> > is
> > > > able to synthesize touch events out of mouse events.
> > >
> > > But didn't you have a patch for Qt to fix that?
> >
> > No. That's a different topic. But maybe InverseMouseArea does it to
> workaround
> > that bug.
>
> Oh, it was my understanding that you where making the synthezised events go
> properly through the event stack again and thus they'd be caught by the
> InverseMouseArea and everything would just work.
A topMost InverseMouseArea listens for events at QGuiApplication level (a bad idea, IMHO). synthesized mouse events from QQuickWindow will never to that high up, and they shouldn't.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> > > > > e.g.: It would have, for instance, to monitor touch events and
> translate
> > > > them
> > > > > to mouse events himself because it's a Inverse*Mouse*Area. When its
> > > topMost
> > > > > property is on it listens for input events at a level before
> > QQuickWindow
> > > is
> > > > > able to synthesize touch events out of mouse events.
> > > >
> > > > But didn't you have a patch for Qt to fix that?
> > >
> > > No. That's a different topic. But maybe InverseMouseArea does it to
> > workaround
> > > that bug.
> >
> > Oh, it was my understanding that you where making the synthezised events go
> > properly through the event stack again and thus they'd be caught by the
> > InverseMouseArea and everything would just work.
>
> A topMost InverseMouseArea listens for events at QGuiApplication level (a bad
> idea, IMHO). synthesized mouse events from QQuickWindow will never to that
> high up, and they shouldn't.
And even if it listened at the right level (rootItem), it still wouldn't work if there a touch-aware item in the scene that accepts the touches. In that situation QQuickWindow wound't synthesize mouse events out of the touch events because there's no need to.
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
ok, in my opinion we should still fix InverseMouseArea to do what we want, i mean, what about all the other people out there that want to do exactly this? InverseMouseArea is supposed to do it, so why not fix it and then use it?
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> And even if it listened at the right level (rootItem), it still wouldn't work
> if there a touch-aware item in the scene that accepts the touches. In that
> situation QQuickWindow wound't synthesize mouse events out of the touch events
> because there's no need to.
Ah, and for listening at the "right level", that's when you would need my fix.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> ok, in my opinion we should still fix InverseMouseArea to do what we want, i
> mean, what about all the other people out there that want to do exactly this?
> InverseMouseArea is supposed to do it, so why not fix it and then use it?
Can't we do both?
1 - fix our UI *now*, which is what matters to the final user and people trying to sell our phone demoing it.
2 - Fix InverseMouseArea, so that application developer have better building blocks to build their ubuntu apps.
The thing is that item 2 requires much work because InverseMouseArea is meant to cover much more cases and has a more complex API. And we might have to sit around until my QQuickItem event dispatch fix is available in ubuntu repos, translating into even more time.
Item 1 is what the bug that this patch fixes is all about.
Item 2 is a bonus.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:538
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:539
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:539
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:539
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:539
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal | # |
Please split out the unrelated refactoring changes into a separate MP.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
> Please split out the unrelated refactoring changes into a separate MP.
And there it is:
https:/
Michał Sawicz (saviq) wrote : | # |
This is starting to grow on me, as we really have bad experience because of the IMA issues.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:551
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:551
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:552
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:553
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:553
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
I think you should restore the code that hides the [x] when changing scope, wihtout it i can:
* Long press in running app icon
* [x] appears
* Press inside the running icon and swipe right to home scope
* Wait there a few seconds
* Swipe back to the Apps scope
* See how the [x]-disappear animation triggers
Daniel d'Andrada (dandrader) wrote : | # |
> I think you should restore the code that hides the [x] when changing scope,
> wihtout it i can:
> * Long press in running app icon
> * [x] appears
> * Press inside the running icon and swipe right to home scope
> * Wait there a few seconds
> * Swipe back to the Apps scope
> * See how the [x]-disappear animation triggers
Yeah, I've noticed that but decided to remove that code anyhow for the sake of making the code simpler.
Specially since in the new architecture Dash "scope views", the only way to communicate to them is through plain models (for better or worse) and that canEnableTermin
But, anyway, the user experience is what matters in the end and so I've put it back.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:554
http://
Executed test runs:
SUCCESS: http://
ABORTED: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
i was wondering if we can't just hijack the touch event by returning true at some point in the evenFilter and save us from all that timer stuff which looks a bit hacky
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:555
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
> i was wondering if we can't just hijack the touch event by returning true at
> some point in the evenFilter and save us from all that timer stuff which looks
> a bit hacky
The point is to not interfere with the normal event processing. We're just monitoring it, not filtering it out. But I do agree that that timer is not the best thing in the world, thus the big comment.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'Dash/Apps/RunningApplicationsGrid.qml' |
2 | --- Dash/Apps/RunningApplicationsGrid.qml 2013-10-02 11:01:49 +0000 |
3 | +++ Dash/Apps/RunningApplicationsGrid.qml 2013-11-29 11:22:23 +0000 |
4 | @@ -17,6 +17,8 @@ |
5 | import QtQuick 2.0 |
6 | import "../../Components" |
7 | |
8 | +import Ubuntu.Gestures 0.1 |
9 | + |
10 | ResponsiveFlowView { |
11 | id: root |
12 | clip: true |
13 | @@ -100,4 +102,19 @@ |
14 | move: Transition { |
15 | NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.OutCubic } |
16 | } |
17 | + |
18 | + MouseArea { |
19 | + anchors.fill: parent |
20 | + z: -1 // behind all RunningApplicationTiles |
21 | + enabled: root.terminationModeEnabled |
22 | + onPressed: { root.terminationModeEnabled = false; } |
23 | + } |
24 | + |
25 | + PressedOutsideNotifier { |
26 | + anchors.fill: parent |
27 | + enabled: root.terminationModeEnabled |
28 | + onPressedOutside: { |
29 | + root.terminationModeEnabled = false; |
30 | + } |
31 | + } |
32 | } |
33 | |
34 | === modified file 'plugins/Ubuntu/Gestures/CMakeLists.txt' |
35 | --- plugins/Ubuntu/Gestures/CMakeLists.txt 2013-10-22 15:56:37 +0000 |
36 | +++ plugins/Ubuntu/Gestures/CMakeLists.txt 2013-11-29 11:22:23 +0000 |
37 | @@ -6,6 +6,7 @@ |
38 | AxisVelocityCalculator.cpp |
39 | Direction.cpp |
40 | DirectionalDragArea.cpp |
41 | + PressedOutsideNotifier.cpp |
42 | TimeSource.cpp |
43 | ) |
44 | |
45 | |
46 | === added file 'plugins/Ubuntu/Gestures/PressedOutsideNotifier.cpp' |
47 | --- plugins/Ubuntu/Gestures/PressedOutsideNotifier.cpp 1970-01-01 00:00:00 +0000 |
48 | +++ plugins/Ubuntu/Gestures/PressedOutsideNotifier.cpp 2013-11-29 11:22:23 +0000 |
49 | @@ -0,0 +1,119 @@ |
50 | +/* |
51 | + * Copyright (C) 2013 Canonical, Ltd. |
52 | + * |
53 | + * This program is free software; you can redistribute it and/or modify |
54 | + * it under the terms of the GNU General Public License as published by |
55 | + * the Free Software Foundation; version 3. |
56 | + * |
57 | + * This program is distributed in the hope that it will be useful, |
58 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
59 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
60 | + * GNU General Public License for more details. |
61 | + * |
62 | + * You should have received a copy of the GNU General Public License |
63 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
64 | + */ |
65 | + |
66 | +#include "PressedOutsideNotifier.h" |
67 | + |
68 | +#include <QMouseEvent> |
69 | + |
70 | +PressedOutsideNotifier::PressedOutsideNotifier(QQuickItem *parent) |
71 | + : QQuickItem(parent) |
72 | +{ |
73 | + connect(this, &QQuickItem::enabledChanged, |
74 | + this, &PressedOutsideNotifier::setupOrTearDownEventFiltering); |
75 | + |
76 | + m_signalEmissionTimer.setSingleShot(true); |
77 | + m_signalEmissionTimer.setInterval(0); // times out on the next iteration of the event loop |
78 | + connect(&m_signalEmissionTimer, &QTimer::timeout, |
79 | + this, &PressedOutsideNotifier::pressedOutside); |
80 | +} |
81 | + |
82 | +bool PressedOutsideNotifier::eventFilter(QObject *watched, QEvent *event) |
83 | +{ |
84 | + Q_UNUSED(watched); |
85 | + Q_ASSERT(watched == m_filteredWindow); |
86 | + |
87 | + // We are already going to emit pressedOutside() anyway, thus no need |
88 | + // for new checks. |
89 | + // This case takes place when a QTouchEvent comes in and isn't handled by any item, |
90 | + // causing QQuickWindow to synthesize a QMouseEvent out of it, which would |
91 | + // be filtered by us as well and count as a second press, which is wrong. |
92 | + if (m_signalEmissionTimer.isActive()) { |
93 | + return false; |
94 | + } |
95 | + |
96 | + switch (event->type()) { |
97 | + case QEvent::MouseButtonPress: { |
98 | + QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event); |
99 | + QPointF p = mapFromScene(mouseEvent->windowPos()); |
100 | + if (!contains(p)) { |
101 | + m_signalEmissionTimer.start(); |
102 | + } |
103 | + break; |
104 | + } |
105 | + case QEvent::TouchBegin: |
106 | + processFilteredTouchBegin(static_cast<QTouchEvent*>(event)); |
107 | + default: |
108 | + break; |
109 | + } |
110 | + |
111 | + // let the event be handled further |
112 | + return false; |
113 | +} |
114 | + |
115 | +void PressedOutsideNotifier::itemChange(ItemChange change, const ItemChangeData &value) |
116 | +{ |
117 | + if (change == QQuickItem::ItemSceneChange) { |
118 | + setupOrTearDownEventFiltering(); |
119 | + } |
120 | + |
121 | + QQuickItem::itemChange(change, value); |
122 | +} |
123 | + |
124 | +void PressedOutsideNotifier::setupOrTearDownEventFiltering() |
125 | +{ |
126 | + if (isEnabled() && window()) { |
127 | + setupEventFiltering(); |
128 | + } else if (m_filteredWindow) { |
129 | + tearDownEventFiltering(); |
130 | + } |
131 | +} |
132 | + |
133 | +void PressedOutsideNotifier::setupEventFiltering() |
134 | +{ |
135 | + QQuickWindow *currentWindow = window(); |
136 | + Q_ASSERT(currentWindow != nullptr); |
137 | + |
138 | + if (currentWindow == m_filteredWindow) |
139 | + return; |
140 | + |
141 | + if (m_filteredWindow) { |
142 | + m_filteredWindow->removeEventFilter(this); |
143 | + } |
144 | + |
145 | + currentWindow->installEventFilter(this); |
146 | + m_filteredWindow = currentWindow; |
147 | +} |
148 | + |
149 | +void PressedOutsideNotifier::tearDownEventFiltering() |
150 | +{ |
151 | + m_filteredWindow->removeEventFilter(this); |
152 | + m_filteredWindow.clear(); |
153 | +} |
154 | + |
155 | +void PressedOutsideNotifier::processFilteredTouchBegin(QTouchEvent *event) |
156 | +{ |
157 | + const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints(); |
158 | + for (int i = 0; i < touchPoints.count(); ++i) { |
159 | + const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i); |
160 | + if (touchPoint.state() == Qt::TouchPointPressed) { |
161 | + QPointF p = mapFromScene(touchPoint.pos()); |
162 | + if (!contains(p)) { |
163 | + m_signalEmissionTimer.start(); |
164 | + return; |
165 | + } |
166 | + } |
167 | + } |
168 | +} |
169 | |
170 | === added file 'plugins/Ubuntu/Gestures/PressedOutsideNotifier.h' |
171 | --- plugins/Ubuntu/Gestures/PressedOutsideNotifier.h 1970-01-01 00:00:00 +0000 |
172 | +++ plugins/Ubuntu/Gestures/PressedOutsideNotifier.h 2013-11-29 11:22:23 +0000 |
173 | @@ -0,0 +1,62 @@ |
174 | +/* |
175 | + * Copyright (C) 2013 Canonical, Ltd. |
176 | + * |
177 | + * This program is free software; you can redistribute it and/or modify |
178 | + * it under the terms of the GNU General Public License as published by |
179 | + * the Free Software Foundation; version 3. |
180 | + * |
181 | + * This program is distributed in the hope that it will be useful, |
182 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
183 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
184 | + * GNU General Public License for more details. |
185 | + * |
186 | + * You should have received a copy of the GNU General Public License |
187 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
188 | + */ |
189 | + |
190 | +#ifndef PRESSED_OUTSIDE_NOTIFIER_H |
191 | +#define PRESSED_OUTSIDE_NOTIFIER_H |
192 | + |
193 | +#include <QQuickItem> |
194 | + |
195 | +#include <QQuickWindow> |
196 | +#include <QPointer> |
197 | +#include <QTimer> |
198 | + |
199 | +#include "UbuntuGesturesGlobal.h" |
200 | + |
201 | +/* |
202 | + Notifies when a point, mouse or touch, is pressed outside its area. |
203 | + |
204 | + Only enable it while needed. |
205 | + */ |
206 | +class UBUNTUGESTURES_EXPORT PressedOutsideNotifier : public QQuickItem { |
207 | + Q_OBJECT |
208 | + |
209 | +public: |
210 | + PressedOutsideNotifier(QQuickItem * parent = nullptr); |
211 | + |
212 | + // From QObject |
213 | + bool eventFilter(QObject *watched, QEvent *event) override; |
214 | + |
215 | +Q_SIGNALS: |
216 | + void pressedOutside(); |
217 | + |
218 | +protected: |
219 | + void itemChange(ItemChange change, const ItemChangeData &value) override; |
220 | + |
221 | +private Q_SLOTS: |
222 | + void setupOrTearDownEventFiltering(); |
223 | + |
224 | +private: |
225 | + void setupEventFiltering(); |
226 | + void tearDownEventFiltering(); |
227 | + void processFilteredTouchBegin(QTouchEvent *event); |
228 | + |
229 | + QPointer<QQuickWindow> m_filteredWindow; |
230 | + |
231 | + // Emits pressedOutside() signal on timeout |
232 | + QTimer m_signalEmissionTimer; |
233 | +}; |
234 | + |
235 | +#endif // PRESSED_OUTSIDE_NOTIFIER_H |
236 | |
237 | === modified file 'plugins/Ubuntu/Gestures/plugin.cpp' |
238 | --- plugins/Ubuntu/Gestures/plugin.cpp 2013-06-17 13:45:28 +0000 |
239 | +++ plugins/Ubuntu/Gestures/plugin.cpp 2013-11-29 11:22:23 +0000 |
240 | @@ -18,6 +18,7 @@ |
241 | #include "AxisVelocityCalculator.h" |
242 | #include "Direction.h" |
243 | #include "DirectionalDragArea.h" |
244 | +#include "PressedOutsideNotifier.h" |
245 | |
246 | #include <qqml.h> |
247 | |
248 | @@ -32,4 +33,5 @@ |
249 | qmlRegisterSingletonType<Direction>(uri, 0, 1, "Direction", directionSingleton); |
250 | qmlRegisterType<DirectionalDragArea>(uri, 0, 1, "DirectionalDragArea"); |
251 | qmlRegisterType<AxisVelocityCalculator>(uri, 0, 1, "AxisVelocityCalculator"); |
252 | + qmlRegisterType<PressedOutsideNotifier>(uri, 0, 1, "PressedOutsideNotifier"); |
253 | } |
254 | |
255 | === modified file 'tests/plugins/Ubuntu/Gestures/CMakeLists.txt' |
256 | --- tests/plugins/Ubuntu/Gestures/CMakeLists.txt 2013-11-22 11:28:28 +0000 |
257 | +++ tests/plugins/Ubuntu/Gestures/CMakeLists.txt 2013-11-29 11:22:23 +0000 |
258 | @@ -45,5 +45,6 @@ |
259 | endmacro(add_gesture_test) |
260 | |
261 | add_gesture_ui_test(DirectionalDragArea) |
262 | +add_gesture_ui_test(PressedOutsideNotifier) |
263 | add_gesture_test(Damper) |
264 | add_gesture_test(AxisVelocityCalculator) |
265 | |
266 | === added file 'tests/plugins/Ubuntu/Gestures/tst_PressedOutsideNotifier.cpp' |
267 | --- tests/plugins/Ubuntu/Gestures/tst_PressedOutsideNotifier.cpp 1970-01-01 00:00:00 +0000 |
268 | +++ tests/plugins/Ubuntu/Gestures/tst_PressedOutsideNotifier.cpp 2013-11-29 11:22:23 +0000 |
269 | @@ -0,0 +1,150 @@ |
270 | +/* |
271 | + * Copyright (C) 2013 Canonical, Ltd. |
272 | + * |
273 | + * This program is free software; you can redistribute it and/or modify |
274 | + * it under the terms of the GNU General Public License as published by |
275 | + * the Free Software Foundation; version 3. |
276 | + * |
277 | + * This program is distributed in the hope that it will be useful, |
278 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
279 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
280 | + * GNU General Public License for more details. |
281 | + * |
282 | + * You should have received a copy of the GNU General Public License |
283 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
284 | + */ |
285 | + |
286 | +#include "GestureTest.h" |
287 | + |
288 | +#include <PressedOutsideNotifier.h> |
289 | + |
290 | +#include <QQuickItem> |
291 | +#include <QQuickView> |
292 | +#include <QtTest> |
293 | + |
294 | +class tst_PressedOutsideNotifier: public GestureTest |
295 | +{ |
296 | + Q_OBJECT |
297 | +public: |
298 | + tst_PressedOutsideNotifier(); |
299 | +private Q_SLOTS: |
300 | + void init(); // called right before each and every test function is executed |
301 | + |
302 | + void touchOutsideAreaTriggersSignal(); |
303 | + void touchInsideAreaHasNoEffect(); |
304 | + void mousePressOutsideAreaTriggersSignal(); |
305 | + void mousePresssInsideAreaHasNoEffect(); |
306 | + void nothingHappensWhileDisabled(); |
307 | + |
308 | +private: |
309 | + QQuickItem *m_blueRect; |
310 | + PressedOutsideNotifier *m_notifier; |
311 | +}; |
312 | + |
313 | +tst_PressedOutsideNotifier::tst_PressedOutsideNotifier() |
314 | + : GestureTest(QStringLiteral("tst_PressedOutsideNotifier.qml")) |
315 | +{ |
316 | +} |
317 | + |
318 | +void tst_PressedOutsideNotifier::init() |
319 | +{ |
320 | + GestureTest::init(); |
321 | + |
322 | + m_blueRect = m_view->rootObject()->findChild<QQuickItem*>("blueRect"); |
323 | + Q_ASSERT(m_blueRect != nullptr); |
324 | + |
325 | + m_notifier = |
326 | + m_view->rootObject()->findChild<PressedOutsideNotifier*>("pressedOutsideNotifier"); |
327 | + Q_ASSERT(m_notifier != nullptr); |
328 | +} |
329 | + |
330 | +void tst_PressedOutsideNotifier::touchOutsideAreaTriggersSignal() |
331 | +{ |
332 | + // half-way towards the top-left corner of the blueRect. |
333 | + // Therefore, still outside it. |
334 | + QPoint touch0 = QPoint(m_blueRect->x() * 0.5, m_blueRect->y() * 0.5); |
335 | + |
336 | + QSignalSpy pressedOutsideSpy(m_notifier, SIGNAL(pressedOutside())); |
337 | + |
338 | + QTest::touchEvent(m_view, m_device) |
339 | + .press(0, touch0); |
340 | + |
341 | + qApp->processEvents(); |
342 | + |
343 | + QCOMPARE(pressedOutsideSpy.count(), 1); |
344 | + |
345 | + QTest::touchEvent(m_view, m_device) |
346 | + .release(0, touch0); |
347 | +} |
348 | + |
349 | +void tst_PressedOutsideNotifier::touchInsideAreaHasNoEffect() |
350 | +{ |
351 | + QPoint touch0 = QPoint(m_blueRect->x() + m_blueRect->width()*0.5, |
352 | + m_blueRect->y() + m_blueRect->height()*0.5); |
353 | + |
354 | + QSignalSpy pressedOutsideSpy(m_notifier, SIGNAL(pressedOutside())); |
355 | + |
356 | + QTest::touchEvent(m_view, m_device) |
357 | + .press(0, touch0); |
358 | + |
359 | + qApp->processEvents(); |
360 | + |
361 | + QCOMPARE(pressedOutsideSpy.count(), 0); |
362 | + |
363 | + QTest::touchEvent(m_view, m_device) |
364 | + .release(0, touch0); |
365 | +} |
366 | + |
367 | +void tst_PressedOutsideNotifier::mousePressOutsideAreaTriggersSignal() |
368 | +{ |
369 | + QPoint mousePos= QPoint(m_blueRect->x() * 0.5, m_blueRect->y() * 0.5); |
370 | + |
371 | + QSignalSpy pressedOutsideSpy(m_notifier, SIGNAL(pressedOutside())); |
372 | + |
373 | + QTest::mousePress(m_view, Qt::LeftButton, 0 /*modifiers*/, mousePos); |
374 | + |
375 | + qApp->processEvents(); |
376 | + |
377 | + QCOMPARE(pressedOutsideSpy.count(), 1); |
378 | + |
379 | + QTest::mouseRelease(m_view, Qt::LeftButton, 0 /*modifiers*/, mousePos); |
380 | +} |
381 | + |
382 | +void tst_PressedOutsideNotifier::mousePresssInsideAreaHasNoEffect() |
383 | +{ |
384 | + QPoint mousePos = QPoint(m_blueRect->x() + m_blueRect->width()*0.5, |
385 | + m_blueRect->y() + m_blueRect->height()*0.5); |
386 | + |
387 | + QSignalSpy pressedOutsideSpy(m_notifier, SIGNAL(pressedOutside())); |
388 | + |
389 | + QTest::mousePress(m_view, Qt::LeftButton, 0 /*modifiers*/, mousePos); |
390 | + |
391 | + qApp->processEvents(); |
392 | + |
393 | + QCOMPARE(pressedOutsideSpy.count(), 0); |
394 | + |
395 | + QTest::mouseRelease(m_view, Qt::LeftButton, 0 /*modifiers*/, mousePos); |
396 | +} |
397 | + |
398 | +void tst_PressedOutsideNotifier::nothingHappensWhileDisabled() |
399 | +{ |
400 | + QPoint touch0 = QPoint(m_blueRect->x() * 0.5, m_blueRect->y() * 0.5); |
401 | + |
402 | + QSignalSpy pressedOutsideSpy(m_notifier, SIGNAL(pressedOutside())); |
403 | + |
404 | + m_notifier->setEnabled(false); |
405 | + |
406 | + QTest::touchEvent(m_view, m_device) |
407 | + .press(0, touch0); |
408 | + |
409 | + qApp->processEvents(); |
410 | + |
411 | + QCOMPARE(pressedOutsideSpy.count(), 0); |
412 | + |
413 | + QTest::touchEvent(m_view, m_device) |
414 | + .release(0, touch0); |
415 | +} |
416 | + |
417 | +QTEST_MAIN(tst_PressedOutsideNotifier) |
418 | + |
419 | +#include "tst_PressedOutsideNotifier.moc" |
420 | |
421 | === added file 'tests/plugins/Ubuntu/Gestures/tst_PressedOutsideNotifier.qml' |
422 | --- tests/plugins/Ubuntu/Gestures/tst_PressedOutsideNotifier.qml 1970-01-01 00:00:00 +0000 |
423 | +++ tests/plugins/Ubuntu/Gestures/tst_PressedOutsideNotifier.qml 2013-11-29 11:22:23 +0000 |
424 | @@ -0,0 +1,62 @@ |
425 | +/* |
426 | + * Copyright (C) 2013 Canonical, Ltd. |
427 | + * |
428 | + * This program is free software; you can redistribute it and/or modify |
429 | + * it under the terms of the GNU General Public License as published by |
430 | + * the Free Software Foundation; version 3. |
431 | + * |
432 | + * This program is distributed in the hope that it will be useful, |
433 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
434 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
435 | + * GNU General Public License for more details. |
436 | + * |
437 | + * You should have received a copy of the GNU General Public License |
438 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
439 | + */ |
440 | + |
441 | +import QtQuick 2.0 |
442 | +import Ubuntu.Components 0.1 |
443 | +import Ubuntu.Gestures 0.1 |
444 | + |
445 | +/* |
446 | + NB: If you change positions or sizes here make sure |
447 | + tst_PressedOutsideNotifier.cpp is updated accordingly |
448 | + */ |
449 | + |
450 | +Rectangle { |
451 | + width: units.gu(60) |
452 | + height: units.gu(60) |
453 | + color: "white" |
454 | + |
455 | + Rectangle { |
456 | + id: blueRect |
457 | + objectName: "blueRect" |
458 | + color: "blue" |
459 | + x: units.gu(20) |
460 | + y: units.gu(20) |
461 | + width: units.gu(20) |
462 | + height: units.gu(20) |
463 | + |
464 | + Timer { |
465 | + id: resetColorTimer |
466 | + interval: 300 |
467 | + repeat: false |
468 | + onTriggered: { |
469 | + blueRect.color = "blue"; |
470 | + } |
471 | + } |
472 | + |
473 | + function blinkRed() { |
474 | + blueRect.color = "red"; |
475 | + resetColorTimer.start(); |
476 | + } |
477 | + |
478 | + PressedOutsideNotifier { |
479 | + objectName: "pressedOutsideNotifier" |
480 | + anchors.fill: parent |
481 | + onPressedOutside: { |
482 | + blueRect.blinkRed(); |
483 | + } |
484 | + } |
485 | + } |
486 | +} |
487 | |
488 | === modified file 'tests/qmltests/CMakeLists.txt' |
489 | --- tests/qmltests/CMakeLists.txt 2013-11-19 09:43:35 +0000 |
490 | +++ tests/qmltests/CMakeLists.txt 2013-11-29 11:22:23 +0000 |
491 | @@ -46,7 +46,9 @@ |
492 | add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}) |
493 | add_qml_test(Dash FilterGrids IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRENT_SOURCE_DIR}/plugins |
494 | ${CMAKE_BINARY_DIR}/tests/mocks) |
495 | -add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks) |
496 | +add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} |
497 | + ${CMAKE_BINARY_DIR}/tests/mocks |
498 | + ${CMAKE_BINARY_DIR}/plugins) |
499 | add_qml_test(Dash/Apps AppPreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks) |
500 | add_qml_test(Dash/Movie MoviePreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks) |
501 | add_qml_test(Greeter Lockscreen IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS} |
502 | |
503 | === modified file 'tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml' |
504 | --- tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml 2013-10-25 07:59:15 +0000 |
505 | +++ tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml 2013-11-29 11:22:23 +0000 |
506 | @@ -239,5 +239,25 @@ |
507 | return findChild(runningApplicationsGrid, "runningAppTile Calendar") |
508 | != undefined |
509 | } |
510 | + |
511 | + // While in termination mode, if you click outside any of the tiles, the |
512 | + // termination mode is disabled (i.e. we switch back to activation mode). |
513 | + function test_clickOutsideTilesDisablesTerminationMode() { |
514 | + runningApplicationsGrid.terminationModeEnabled = true |
515 | + |
516 | + var calendarTile = findChild(runningApplicationsGrid, "runningAppTile Calendar") |
517 | + verify(calendarTile != undefined) |
518 | + |
519 | + verify(runningApplicationsGrid.terminationModeEnabled); |
520 | + |
521 | + // Click on the bottom right corner of the grid, where there's no |
522 | + // RunningApplicationTile lying around |
523 | + mouseClick(runningApplicationsGrid, |
524 | + runningApplicationsGrid.width - 1, runningApplicationsGrid.height - 1); |
525 | + |
526 | + wait(0) // spin event loop to ensure that any pending signal emission went through |
527 | + |
528 | + verify(!runningApplicationsGrid.terminationModeEnabled); |
529 | + } |
530 | } |
531 | } |
FAILED: Continuous integration, rev:537 jenkins. qa.ubuntu. com/job/ unity8- ci/1685/ jenkins. qa.ubuntu. com/job/ generic- mediumtests- trusty/ 930/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- trusty- touch/914/ console jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- trusty/ 335/console jenkins. qa.ubuntu. com/job/ unity8- trusty- amd64-ci/ 208/console jenkins. qa.ubuntu. com/job/ unity8- trusty- armhf-ci/ 209/console jenkins. qa.ubuntu. com/job/ unity8- trusty- i386-ci/ 208/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- amd64/930/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- armhf/914/ console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/1685/ rebuild
http://