Merge lp:~aacid/unity-2d/unity-2d_pointer_barrier into lp:unity-2d
- unity-2d_pointer_barrier
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Gerry Boland |
Approved revision: | 974 |
Merged at revision: | 963 |
Proposed branch: | lp:~aacid/unity-2d/unity-2d_pointer_barrier |
Merge into: | lp:unity-2d |
Diff against target: |
1524 lines (+1187/-52) 22 files modified
CMakeLists.txt (+4/-0) data/com.canonical.Unity2d.gschema.xml (+38/-0) debian/control (+1/-0) libunity-2d-private/CMakeLists.txt (+1/-0) libunity-2d-private/Unity2d/plugin.cpp (+4/-0) libunity-2d-private/src/CMakeLists.txt (+5/-0) libunity-2d-private/src/decayedvalue.cpp (+65/-0) libunity-2d-private/src/decayedvalue.h (+45/-0) libunity-2d-private/src/pointerbarrier.cpp (+361/-0) libunity-2d-private/src/pointerbarrier.h (+154/-0) libunity-2d-private/src/pointerbarriermanager.cpp (+84/-0) libunity-2d-private/src/pointerbarriermanager.h (+44/-0) libunity-2d-private/tests/CMakeLists.txt (+4/-0) libunity-2d-private/tests/pointerbarriertest.cpp (+312/-0) shell/Shell.qml (+11/-18) shell/common/visibilityBehaviors/AutoHideBehavior.qml (+6/-12) shell/common/visibilityBehaviors/IntelliHideBehavior.qml (+5/-5) shell/launcher/Launcher.qml (+23/-1) shell/launcher/LauncherLoader.qml (+3/-13) tests/launcher/autohide_show_tests.rb (+6/-0) tests/launcher/autohide_show_tests_common.rb (+5/-3) tests/launcher/autohide_show_tests_rtl.rb (+6/-0) |
To merge this branch: | bzr merge lp:~aacid/unity-2d/unity-2d_pointer_barrier |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gerry Boland (community) | Approve | ||
Review via email: mp+94983@code.launchpad.net |
Commit message
Description of the change
Implementation of Pointer barriers and use in the launcher autohide behaviour
Albert Astals Cid (aacid) wrote : | # |
Gerry Boland (gerboland) wrote : | # |
Setup: 2 monitors, and shell in RTL mode (so launcher is on right of monitor 1, which borders monitor 2)
Steps to repro:
1. On screen 1 I push mouse against barrier, so launcher reveals
2. I push a bit harder so mouse passes through barrier to screen 2
Bug: Launcher stays open.
I also notice you drop the barrier while the launcher is open. Then for the above bug, there's no barrier stopping the mouse passing from screen 2 to screen 1.
Yes this bug is a bit "multi-monitor" :)
Gerry Boland (gerboland) wrote : | # |
Removing intellihide, you'll need to remove reference to it from com.canonical.
Gerry Boland (gerboland) wrote : | # |
Checking with Unity, I noticed 3 differences:
1. barrier extends along whole edge of screen, including panel
2. pushing the bit of the barrier that meets the panel does *not* reveal launcher
3. as you push launcher barrier, a small shadow appears which indicates you should push harder to get launcher to open.
Gerry Boland (gerboland) wrote : | # |
Also in RTL multi-monitor setup described above (https:/
If I push the left edge of screen 2 (which borders the launcher on screen 1), it makes the launcher reveal.
Gerry Boland (gerboland) wrote : | # |
Bug: for hide-mode: 0, no barrier in effect at all
hide-mode 1,2: while launcher visible, no barrier in effect at all
Gerry Boland (gerboland) wrote : | # |
Some minor code style comments (possibly my code to start with!):
In PointerBarrierW
+ if (!m_enabled)
+ return;
Can you add a debug comment explaining that barrier must be horizontal/vertical here:
+ if ((m_p1.x() != m_p2.x()) && (m_p1.y() != m_p2.y()))
+ return;
In PointerBarrierW
You should add yourself as an author to pointerbarrier.h
Gerry Boland (gerboland) wrote : | # |
Functionally this is perfect, nice!
Code-wise, I can find no problems with the math anywhere. There is a little more going on that I had expected, but I can see no way to avoid everything you've done. So again, nice job!
Just some names I think could be clearer:
- "breakp1" could simply be "p1" and so on.
- "trigger" more understandable with "triggerZone" maybe?
- DecayedValue::add maybe clearer with DecayedValue:
I also want to see more tests of this barrier. Could you write a couple of unit tests, which run under a fake X server (xvfb) - as all tests in libunity-
You can use XTest to move the mouse around. The source code of xdotool is a nice place to see it being used.
Gerry Boland (gerboland) wrote : | # |
Works great, and the simplification helps too. Test is good, I'm approving.
Thank you Albert!
Gerry Boland (gerboland) wrote : | # |
Holding off approval until FFe obtained
- 973. By Albert Astals Cid
-
Merge lp:unity-2d
- 974. By Albert Astals Cid
-
Fix docu
Gerry Boland (gerboland) wrote : | # |
FFe obtained, can now merge when tarmac instance happy again.
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2012-03-01 17:42:03 +0000 |
3 | +++ CMakeLists.txt 2012-03-05 14:20:25 +0000 |
4 | @@ -45,6 +45,10 @@ |
5 | pkg_check_modules(PANGO REQUIRED pango) |
6 | pkg_check_modules(DCONFQT REQUIRED dconf-qt) |
7 | |
8 | +# X11_XTest_FOUND is defined by find_package(X11 REQUIRED) |
9 | +if (NOT X11_XTest_FOUND) |
10 | + message(SEND_ERROR "Xtest library not found") |
11 | +endif (NOT X11_XTest_FOUND) |
12 | |
13 | # GSettings schemas |
14 | pkg_check_modules(GLIB REQUIRED glib-2.0) |
15 | |
16 | === modified file 'data/com.canonical.Unity2d.gschema.xml' |
17 | --- data/com.canonical.Unity2d.gschema.xml 2012-02-13 14:59:11 +0000 |
18 | +++ data/com.canonical.Unity2d.gschema.xml 2012-03-05 14:20:25 +0000 |
19 | @@ -31,6 +31,44 @@ |
20 | 2: intellihide; same as auto hide but the launcher will disappear if a window is placed on top of it |
21 | </description> |
22 | </key> |
23 | + <key name="edge-responsiveness" type="d"> |
24 | + <default>2</default> |
25 | + <summary>Responsiveness of the Launcher</summary> |
26 | + <description>How quickly the Launcher will reveal when you push the pointer against the |
27 | + monitor edge |
28 | + </description> |
29 | + </key> |
30 | + <key name="edge-decayrate" type="i"> |
31 | + <default>1500</default> |
32 | + <summary>Decay rate of mouse pressure against barrier</summary> |
33 | + <description>The pressures against the monitor edge are continually added up, and when the sum |
34 | + hits a certain threshold the launcher reveals. To prevent a series of distinct gentle pushes |
35 | + of the pointer against the barrier from causing the launcher to reveal, we substract this |
36 | + parameter - the decay rate - at a steady rate |
37 | + </description> |
38 | + </key> |
39 | + <key name="edge-reveal-pressure" type="i"> |
40 | + <default>2000</default> |
41 | + <summary>Launcher reveal edge pressure</summary> |
42 | + <description>The minimum pressure to press the pointer against the monitor edge to |
43 | + cause the launcher to reveal |
44 | + </description> |
45 | + </key> |
46 | + <key name="edge-stop-velocity" type="i"> |
47 | + <default>6500</default> |
48 | + <summary>Barrier edge stop velocity</summary> |
49 | + <description>The minimum velocity the pointer needs to travel to pass through the barrier without |
50 | + any resistance. Only relevant for multi-monitor setups |
51 | + </description> |
52 | + </key> |
53 | + <key name="edge-overcome-pressure" type="i"> |
54 | + <default>2000</default> |
55 | + <summary>Barrier edge overcome pressure |
56 | + </summary> |
57 | + <description>Minimum pressure the pointer needs to exert on the barrier for the barrier to drop. |
58 | + Only relevant for multi-monitor setups |
59 | + </description> |
60 | + </key> |
61 | </schema> |
62 | <schema path="/com/canonical/unity-2d/panel/" id="com.canonical.Unity2d.Panel" gettext-domain="unity-2d"> |
63 | <key type="as" name="applets"> |
64 | |
65 | === modified file 'debian/control' |
66 | --- debian/control 2012-02-17 13:14:40 +0000 |
67 | +++ debian/control 2012-03-05 14:20:25 +0000 |
68 | @@ -25,6 +25,7 @@ |
69 | libunity-core-5.0-dev (>= 5.2.0), |
70 | libnux-2.0-dev (>= 2.4), |
71 | libxi-dev, |
72 | + libxtst-dev, |
73 | Standards-Version: 3.9.2 |
74 | Vcs-Bzr: https://code.launchpad.net/~unity-2d-team/unity-2d/trunk |
75 | |
76 | |
77 | === modified file 'libunity-2d-private/CMakeLists.txt' |
78 | --- libunity-2d-private/CMakeLists.txt 2011-12-08 19:00:51 +0000 |
79 | +++ libunity-2d-private/CMakeLists.txt 2012-03-05 14:20:25 +0000 |
80 | @@ -11,6 +11,7 @@ |
81 | pkg_check_modules(DEE REQUIRED dee-1.0) |
82 | pkg_check_modules(XINPUT REQUIRED xi) |
83 | pkg_check_modules(GEIS REQUIRED libutouch-geis) |
84 | +pkg_check_modules(XFIXES REQUIRED xfixes) |
85 | |
86 | set(libunity-2d-private_SOVERSION 0) |
87 | set(libunity-2d-private_VERSION ${libunity-2d-private_SOVERSION}.0.0) |
88 | |
89 | === modified file 'libunity-2d-private/Unity2d/plugin.cpp' |
90 | --- libunity-2d-private/Unity2d/plugin.cpp 2012-02-28 12:30:17 +0000 |
91 | +++ libunity-2d-private/Unity2d/plugin.cpp 2012-03-05 14:20:25 +0000 |
92 | @@ -80,6 +80,8 @@ |
93 | #include "unity2dpanel.h" |
94 | #include "strutmanager.h" |
95 | |
96 | +#include "pointerbarrier.h" |
97 | + |
98 | #include <QtDeclarative/qdeclarative.h> |
99 | #include <QDeclarativeEngine> |
100 | #include <QDeclarativeContext> |
101 | @@ -183,6 +185,8 @@ |
102 | |
103 | qmlRegisterType<Unity2dPanel>(uri, 0, 1, "Unity2dPanel"); |
104 | qmlRegisterType<StrutManager>(uri, 0, 1, "StrutManager"); |
105 | + |
106 | + qmlRegisterType<PointerBarrierWrapper>(uri, 0, 1, "PointerBarrier"); |
107 | } |
108 | |
109 | void Unity2dPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri) |
110 | |
111 | === modified file 'libunity-2d-private/src/CMakeLists.txt' |
112 | --- libunity-2d-private/src/CMakeLists.txt 2012-02-28 12:30:17 +0000 |
113 | +++ libunity-2d-private/src/CMakeLists.txt 2012-03-05 14:20:25 +0000 |
114 | @@ -78,6 +78,9 @@ |
115 | inputshaperectangle.cpp |
116 | inputshapemask.cpp |
117 | strutmanager.cpp |
118 | + pointerbarrier.cpp |
119 | + pointerbarriermanager.cpp |
120 | + decayedvalue.cpp |
121 | ) |
122 | |
123 | # Build |
124 | @@ -106,6 +109,7 @@ |
125 | ${DEE_INCLUDE_DIRS} |
126 | ${XINPUT_INCLUDE_DIRS} |
127 | ${GEIS_INCLUDE_DIRS} |
128 | + ${XFIXES_INCLUDE_DIRS} |
129 | ) |
130 | |
131 | add_library(${LIB_NAME} SHARED ${libunity-2d-private_SRCS} listmodelwrapper.h) |
132 | @@ -142,6 +146,7 @@ |
133 | ${DEE_LDFLAGS} |
134 | ${XINPUT_LDFLAGS} |
135 | ${GEIS_LDFLAGS} |
136 | + ${XFIXES_LDFLAGS} |
137 | ) |
138 | |
139 | # Install |
140 | |
141 | === added file 'libunity-2d-private/src/decayedvalue.cpp' |
142 | --- libunity-2d-private/src/decayedvalue.cpp 1970-01-01 00:00:00 +0000 |
143 | +++ libunity-2d-private/src/decayedvalue.cpp 2012-03-05 14:20:25 +0000 |
144 | @@ -0,0 +1,65 @@ |
145 | +/* |
146 | + * Copyright (C) 2012 Canonical, Ltd. |
147 | + * |
148 | + * This program is free software; you can redistribute it and/or modify |
149 | + * it under the terms of the GNU General Public License as published by |
150 | + * the Free Software Foundation; version 3. |
151 | + * |
152 | + * This program is distributed in the hope that it will be useful, |
153 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
154 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
155 | + * GNU General Public License for more details. |
156 | + * |
157 | + * You should have received a copy of the GNU General Public License |
158 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
159 | + */ |
160 | + |
161 | +#include "decayedvalue.h" |
162 | + |
163 | +DecayedValue::DecayedValue() |
164 | + : m_value(0) |
165 | + , m_target(0) |
166 | + , m_decayRate(0) |
167 | +{ |
168 | + m_valueDecayTimer.setInterval(10); |
169 | + connect(&m_valueDecayTimer, SIGNAL(timeout()), this, SLOT(decay())); |
170 | +} |
171 | + |
172 | +bool DecayedValue::addAndCheckExceedingTarget(int i) |
173 | +{ |
174 | + m_value += i; |
175 | + if (!m_valueDecayTimer.isActive()) { |
176 | + m_valueDecayTimer.start(); |
177 | + } |
178 | + if (m_value > m_target) { |
179 | + m_value = 0; |
180 | + m_valueDecayTimer.stop(); |
181 | + return true; |
182 | + } else { |
183 | + return false; |
184 | + } |
185 | +} |
186 | + |
187 | +void DecayedValue::setDecayRate(int decayRate) |
188 | +{ |
189 | + m_decayRate = decayRate; |
190 | +} |
191 | + |
192 | +void DecayedValue::setTarget(int target) |
193 | +{ |
194 | + m_target = target; |
195 | +} |
196 | + |
197 | +void DecayedValue::decay() { |
198 | + const int partial_decay = m_decayRate / 100; |
199 | + |
200 | + m_value -= partial_decay; |
201 | + |
202 | + if (m_value <= 0) |
203 | + { |
204 | + m_value = 0; |
205 | + m_valueDecayTimer.stop(); |
206 | + } |
207 | +} |
208 | + |
209 | +#include "decayedvalue.moc" |
210 | \ No newline at end of file |
211 | |
212 | === added file 'libunity-2d-private/src/decayedvalue.h' |
213 | --- libunity-2d-private/src/decayedvalue.h 1970-01-01 00:00:00 +0000 |
214 | +++ libunity-2d-private/src/decayedvalue.h 2012-03-05 14:20:25 +0000 |
215 | @@ -0,0 +1,45 @@ |
216 | +/* |
217 | + * Copyright (C) 2012 Canonical, Ltd. |
218 | + * |
219 | + * This program is free software; you can redistribute it and/or modify |
220 | + * it under the terms of the GNU General Public License as published by |
221 | + * the Free Software Foundation; version 3. |
222 | + * |
223 | + * This program is distributed in the hope that it will be useful, |
224 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
225 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
226 | + * GNU General Public License for more details. |
227 | + * |
228 | + * You should have received a copy of the GNU General Public License |
229 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
230 | + */ |
231 | + |
232 | +#ifndef DECAYEDVALUE_H |
233 | +#define DECAYEDVALUE_H |
234 | + |
235 | +#include <QObject> |
236 | + |
237 | +#include <QTimer> |
238 | + |
239 | +class DecayedValue : public QObject |
240 | +{ |
241 | + Q_OBJECT |
242 | +public: |
243 | + DecayedValue(); |
244 | + |
245 | + bool addAndCheckExceedingTarget(int i); |
246 | + |
247 | + void setDecayRate(int decayRate); |
248 | + void setTarget(int target); |
249 | + |
250 | +private Q_SLOTS: |
251 | + void decay(); |
252 | + |
253 | +private: |
254 | + int m_value; |
255 | + int m_target; |
256 | + int m_decayRate; |
257 | + QTimer m_valueDecayTimer; |
258 | +}; |
259 | + |
260 | +#endif // DECAYEDVALUE_H |
261 | |
262 | === added file 'libunity-2d-private/src/pointerbarrier.cpp' |
263 | --- libunity-2d-private/src/pointerbarrier.cpp 1970-01-01 00:00:00 +0000 |
264 | +++ libunity-2d-private/src/pointerbarrier.cpp 2012-03-05 14:20:25 +0000 |
265 | @@ -0,0 +1,361 @@ |
266 | +/* |
267 | + * Copyright (C) 2012 Canonical, Ltd. |
268 | + * |
269 | + * This program is free software; you can redistribute it and/or modify |
270 | + * it under the terms of the GNU General Public License as published by |
271 | + * the Free Software Foundation; version 3. |
272 | + * |
273 | + * This program is distributed in the hope that it will be useful, |
274 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
275 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
276 | + * GNU General Public License for more details. |
277 | + * |
278 | + * You should have received a copy of the GNU General Public License |
279 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
280 | + */ |
281 | + |
282 | +// Qt |
283 | +#include <QDebug> |
284 | +#include <QTimer> |
285 | +#include <QX11Info> |
286 | + |
287 | +// libunity-2d |
288 | +#include "pointerbarriermanager.h" |
289 | + |
290 | +// Self |
291 | +#include "pointerbarrier.h" |
292 | + |
293 | +PointerBarrierWrapper::PointerBarrierWrapper(QObject *parent) |
294 | + : QObject(parent) |
295 | + , m_barrier(0) |
296 | + , m_triggerDirection(TriggerFromAnywhere) |
297 | + , m_triggerZoneEnabled(false) |
298 | + , m_threshold(-1) |
299 | + , m_maxVelocityMultiplier(-1) |
300 | + , m_decayRate(-1) |
301 | + , m_triggerPressure(-1) |
302 | + , m_breakPressure(-1) |
303 | + , m_smoothingTimer(new QTimer(this)) |
304 | + , m_lastEventX(0) |
305 | + , m_lastEventY(0) |
306 | + , m_lastEventId(0) |
307 | + , m_smoothingCount(0) |
308 | + , m_smoothingAccumulator(0) |
309 | +{ |
310 | + m_smoothingTimer->setSingleShot(true); |
311 | + m_smoothingTimer->setInterval(75); |
312 | + connect(m_smoothingTimer, SIGNAL(timeout()), this, SLOT(smoother())); |
313 | + |
314 | + PointerBarrierManager::instance()->addBarrier(this); |
315 | +} |
316 | + |
317 | +PointerBarrierWrapper::~PointerBarrierWrapper() |
318 | +{ |
319 | + PointerBarrierManager::instance()->removeBarrier(this); |
320 | + destroyBarrier(); |
321 | +} |
322 | + |
323 | +QPointF PointerBarrierWrapper::p1() const |
324 | +{ |
325 | + return m_p1; |
326 | +} |
327 | + |
328 | +void PointerBarrierWrapper::setP1(const QPointF& p) |
329 | +{ |
330 | + if (p != m_p1) { |
331 | + if (m_barrier != 0) { |
332 | + destroyBarrier(); |
333 | + } |
334 | + |
335 | + m_p1 = p; |
336 | + Q_EMIT p1Changed(p); |
337 | + |
338 | + createBarrier(); |
339 | + } |
340 | +} |
341 | + |
342 | +QPointF PointerBarrierWrapper::p2() const |
343 | +{ |
344 | + return m_p2; |
345 | +} |
346 | + |
347 | +void PointerBarrierWrapper::setP2(const QPointF& p) |
348 | +{ |
349 | + if (p != m_p2) { |
350 | + if (m_barrier != 0) { |
351 | + destroyBarrier(); |
352 | + } |
353 | + |
354 | + m_p2 = p; |
355 | + Q_EMIT p2Changed(p); |
356 | + |
357 | + createBarrier(); |
358 | + } |
359 | +} |
360 | + |
361 | +QPointF PointerBarrierWrapper::triggerZoneP1() const |
362 | +{ |
363 | + return m_triggerZoneP1; |
364 | +} |
365 | + |
366 | +void PointerBarrierWrapper::setTriggerZoneP1(const QPointF& p) |
367 | +{ |
368 | + if (p != m_triggerZoneP1) { |
369 | + m_triggerZoneP1 = p; |
370 | + Q_EMIT triggerZoneP1Changed(p); |
371 | + |
372 | + handleTriggerZoneChanged(); |
373 | + } |
374 | +} |
375 | + |
376 | +QPointF PointerBarrierWrapper::triggerZoneP2() const |
377 | +{ |
378 | + return m_triggerZoneP2; |
379 | +} |
380 | + |
381 | +void PointerBarrierWrapper::setTriggerZoneP2(const QPointF& p) |
382 | +{ |
383 | + if (p != m_triggerZoneP2) { |
384 | + m_triggerZoneP2 = p; |
385 | + Q_EMIT triggerZoneP2Changed(p); |
386 | + |
387 | + handleTriggerZoneChanged(); |
388 | + } |
389 | +} |
390 | + |
391 | +PointerBarrierWrapper::TriggerDirection PointerBarrierWrapper::triggerDirection() const |
392 | +{ |
393 | + return m_triggerDirection; |
394 | +} |
395 | + |
396 | +void PointerBarrierWrapper::setTriggerDirection(TriggerDirection direction) |
397 | +{ |
398 | + if (direction != m_triggerDirection) { |
399 | + m_triggerDirection = direction; |
400 | + Q_EMIT triggerDirectionChanged(direction); |
401 | + } |
402 | +} |
403 | + |
404 | +bool PointerBarrierWrapper::triggerZoneEnabled() const |
405 | +{ |
406 | + return m_triggerZoneEnabled; |
407 | +} |
408 | + |
409 | +void PointerBarrierWrapper::setTriggerZoneEnabled(bool enabled) |
410 | +{ |
411 | + if (m_triggerZoneEnabled != enabled) { |
412 | + m_triggerZoneEnabled = enabled; |
413 | + Q_EMIT triggerZoneEnabledChanged(enabled); |
414 | + |
415 | + handleTriggerZoneChanged(); |
416 | + } |
417 | +} |
418 | + |
419 | +void PointerBarrierWrapper::createBarrier() |
420 | +{ |
421 | + if (m_threshold < 0) { |
422 | + return; |
423 | + } |
424 | + |
425 | + if (!isPointAlignmentCorrect()) { |
426 | + return; |
427 | + } |
428 | + |
429 | + Display *display = QX11Info::display(); |
430 | + |
431 | + m_barrier = XFixesCreatePointerBarrierVelocity(display, |
432 | + DefaultRootWindow(display), |
433 | + m_p1.x(), m_p1.y(), |
434 | + m_p2.x(), m_p2.y(), |
435 | + 0, |
436 | + m_threshold, |
437 | + 0, |
438 | + NULL); |
439 | + Q_ASSERT(m_barrier != 0); |
440 | +} |
441 | + |
442 | +void PointerBarrierWrapper::destroyBarrier() |
443 | +{ |
444 | + if (m_barrier != 0) { |
445 | + XFixesDestroyPointerBarrier(QX11Info::display(), m_barrier); |
446 | + m_barrier = 0; |
447 | + } |
448 | +} |
449 | + |
450 | +void PointerBarrierWrapper::doProcess(XFixesBarrierNotifyEvent *notifyEvent) |
451 | +{ |
452 | + m_lastEventX = notifyEvent->x; |
453 | + m_lastEventY = notifyEvent->y; |
454 | + m_lastEventId = notifyEvent->event_id; |
455 | + m_smoothingAccumulator += notifyEvent->velocity; |
456 | + m_smoothingCount++; |
457 | + |
458 | + /* Gathers events for m_smoothingTimer->interval() miliseconds, then takes average */ |
459 | + if (!m_smoothingTimer->isActive()) { |
460 | + m_smoothingTimer->start(); |
461 | + } |
462 | +} |
463 | + |
464 | +int PointerBarrierWrapper::threshold() const |
465 | +{ |
466 | + return m_threshold; |
467 | +} |
468 | + |
469 | +void PointerBarrierWrapper::setThreshold(int threshold) |
470 | +{ |
471 | + if (m_threshold != threshold) { |
472 | + m_threshold = threshold; |
473 | + destroyBarrier(); |
474 | + createBarrier(); |
475 | + Q_EMIT thresholdChanged(threshold); |
476 | + } |
477 | +} |
478 | + |
479 | +qreal PointerBarrierWrapper::maxVelocityMultiplier() const |
480 | +{ |
481 | + return m_maxVelocityMultiplier; |
482 | +} |
483 | + |
484 | +void PointerBarrierWrapper::setMaxVelocityMultiplier(qreal maxVelocityMultiplier) |
485 | +{ |
486 | + if (maxVelocityMultiplier != m_maxVelocityMultiplier) { |
487 | + m_maxVelocityMultiplier = maxVelocityMultiplier; |
488 | + Q_EMIT maxVelocityMultiplierChanged(maxVelocityMultiplier); |
489 | + |
490 | + updateRealDecayTargetPressures(); |
491 | + } |
492 | +} |
493 | + |
494 | +int PointerBarrierWrapper::decayRate() const |
495 | +{ |
496 | + return m_decayRate; |
497 | +} |
498 | + |
499 | +void PointerBarrierWrapper::setDecayRate(int decayRate) |
500 | +{ |
501 | + if (decayRate != m_decayRate) { |
502 | + m_decayRate = decayRate; |
503 | + Q_EMIT decayRateChanged(decayRate); |
504 | + |
505 | + updateRealDecayTargetPressures(); |
506 | + } |
507 | +} |
508 | + |
509 | +int PointerBarrierWrapper::triggerPressure() const |
510 | +{ |
511 | + return m_triggerPressure; |
512 | +} |
513 | + |
514 | +void PointerBarrierWrapper::setTriggerPressure(int pressure) |
515 | +{ |
516 | + if (m_triggerPressure != pressure) { |
517 | + m_triggerPressure = pressure; |
518 | + Q_EMIT triggerPressureChanged(pressure); |
519 | + |
520 | + updateRealDecayTargetPressures(); |
521 | + } |
522 | +} |
523 | + |
524 | +int PointerBarrierWrapper::breakPressure() const |
525 | +{ |
526 | + return m_breakPressure; |
527 | +} |
528 | + |
529 | +void PointerBarrierWrapper::setBreakPressure(int breakPressure) |
530 | +{ |
531 | + if (m_breakPressure != breakPressure) { |
532 | + m_breakPressure = breakPressure; |
533 | + Q_EMIT breakPressureChanged(breakPressure); |
534 | + |
535 | + updateRealDecayTargetPressures(); |
536 | + } |
537 | +} |
538 | + |
539 | +PointerBarrier PointerBarrierWrapper::barrier() const |
540 | +{ |
541 | + return m_barrier; |
542 | +} |
543 | + |
544 | +void PointerBarrierWrapper::smoother() |
545 | +{ |
546 | + if (m_maxVelocityMultiplier < 0 || m_decayRate < 0 || m_breakPressure < 0) { |
547 | + qWarning() << "PointerBarrierWrapper::smoother: maxVelocityMultiplier, decayRate or breakPressure not set"; |
548 | + return; |
549 | + } |
550 | + |
551 | + if (m_smoothingCount <= 0) { |
552 | + return; |
553 | + } |
554 | + const int velocity = qMin<qreal>(600 * m_maxVelocityMultiplier, m_smoothingAccumulator / m_smoothingCount); |
555 | + |
556 | + bool againstTrigger = false; |
557 | + if (m_triggerZoneEnabled && m_triggerZoneP1.x() == m_triggerZoneP2.x() && m_triggerZoneP1.y() <= m_lastEventY && m_triggerZoneP2.y() >= m_lastEventY) { |
558 | + againstTrigger = m_triggerDirection == TriggerFromAnywhere || |
559 | + (m_triggerDirection == TriggerFromRight && m_lastEventX >= m_triggerZoneP1.x()) || |
560 | + (m_triggerDirection == TriggerFromLeft && m_lastEventX < m_triggerZoneP1.x()); |
561 | + } |
562 | + if (m_triggerZoneEnabled && m_triggerZoneP1.y() == m_triggerZoneP2.y() && m_triggerZoneP1.x() <= m_lastEventX && m_triggerZoneP2.x() >= m_lastEventX) { |
563 | + againstTrigger = m_triggerDirection == TriggerFromAnywhere || |
564 | + (m_triggerDirection == TriggerFromTop && m_lastEventY >= m_triggerZoneP1.y()) || |
565 | + (m_triggerDirection == TriggerFromBottom && m_lastEventY < m_triggerZoneP1.y()); |
566 | + } |
567 | + if (againstTrigger) { |
568 | + if (m_triggerValue.addAndCheckExceedingTarget(velocity)) { |
569 | + Q_EMIT triggered(); |
570 | + } |
571 | + } else { |
572 | + if (m_breakValue.addAndCheckExceedingTarget(velocity)) { |
573 | + Display *display = QX11Info::display(); |
574 | + XFixesBarrierReleasePointer (display, m_barrier, m_lastEventId); |
575 | + |
576 | + Q_EMIT broken(); |
577 | + } |
578 | + } |
579 | + |
580 | + m_smoothingAccumulator = 0; |
581 | + m_smoothingCount = 0; |
582 | +} |
583 | + |
584 | +void PointerBarrierWrapper::updateRealDecayTargetPressures() |
585 | +{ |
586 | + // make the effect half as strong as specified as other values shouldn't scale |
587 | + // as quickly as the max velocity multiplier |
588 | + const float responsiveness_mult = ((m_maxVelocityMultiplier - 1) * .025) + 1; |
589 | + const int realDecayRate = m_decayRate * responsiveness_mult; |
590 | + m_triggerValue.setDecayRate(realDecayRate); |
591 | + m_breakValue.setDecayRate(realDecayRate); |
592 | + m_triggerValue.setTarget(m_triggerPressure * responsiveness_mult); |
593 | + m_breakValue.setTarget(m_breakPressure * responsiveness_mult); |
594 | +} |
595 | + |
596 | +void PointerBarrierWrapper::handleTriggerZoneChanged() |
597 | +{ |
598 | + // Make sure barrier point alignment is still valid |
599 | + if (!isPointAlignmentCorrect()) { |
600 | + destroyBarrier(); |
601 | + } |
602 | + // If there is no barrier try to create one now |
603 | + if (m_barrier == 0) { |
604 | + createBarrier(); |
605 | + } |
606 | +} |
607 | + |
608 | +bool PointerBarrierWrapper::isPointAlignmentCorrect() const |
609 | +{ |
610 | + bool alignmentCorrect = false; |
611 | + |
612 | + // Outer points can't be the same |
613 | + if (m_p1 != m_p2) { |
614 | + // The two points need to be aligned either vertically or horizontally |
615 | + if (m_p1.x() == m_p2.x()) { |
616 | + alignmentCorrect = !m_triggerZoneEnabled || (m_triggerZoneP1.x() == m_p1.x() && m_triggerZoneP2.x() == m_p1.x()); |
617 | + } else if (m_p1.y() == m_p2.y()) { |
618 | + alignmentCorrect = !m_triggerZoneEnabled || (m_triggerZoneP1.y() == m_p1.y() && m_triggerZoneP2.y() == m_p1.y()); |
619 | + } |
620 | + } |
621 | + |
622 | + return alignmentCorrect; |
623 | + |
624 | +} |
625 | + |
626 | +#include <pointerbarrier.moc> |
627 | |
628 | === added file 'libunity-2d-private/src/pointerbarrier.h' |
629 | --- libunity-2d-private/src/pointerbarrier.h 1970-01-01 00:00:00 +0000 |
630 | +++ libunity-2d-private/src/pointerbarrier.h 2012-03-05 14:20:25 +0000 |
631 | @@ -0,0 +1,154 @@ |
632 | +/* |
633 | + * Copyright (C) 2012 Canonical, Ltd. |
634 | + * |
635 | + * This program is free software; you can redistribute it and/or modify |
636 | + * it under the terms of the GNU General Public License as published by |
637 | + * the Free Software Foundation; version 3. |
638 | + * |
639 | + * This program is distributed in the hope that it will be useful, |
640 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
641 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
642 | + * GNU General Public License for more details. |
643 | + * |
644 | + * You should have received a copy of the GNU General Public License |
645 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
646 | + */ |
647 | + |
648 | +#ifndef POINTERBARRIER_H |
649 | +#define POINTERBARRIER_H |
650 | + |
651 | +#include <QObject> |
652 | +#include <QPointF> |
653 | + |
654 | +// X11 |
655 | +#include <X11/extensions/Xfixes.h> |
656 | + |
657 | +#include "decayedvalue.h" |
658 | + |
659 | +struct PointerBarrierWrapperPrivate; |
660 | + |
661 | +class PointerBarrierWrapper : public QObject |
662 | +{ |
663 | + Q_OBJECT |
664 | + Q_PROPERTY(QPointF p1 READ p1 WRITE setP1 NOTIFY p1Changed) |
665 | + Q_PROPERTY(QPointF p2 READ p2 WRITE setP2 NOTIFY p2Changed) |
666 | + Q_PROPERTY(QPointF triggerZoneP1 READ triggerZoneP1 WRITE setTriggerZoneP1 NOTIFY triggerZoneP1Changed) |
667 | + Q_PROPERTY(QPointF triggerZoneP2 READ triggerZoneP2 WRITE setTriggerZoneP2 NOTIFY triggerZoneP2Changed) |
668 | + Q_PROPERTY(TriggerDirection triggerDirection READ triggerDirection WRITE setTriggerDirection NOTIFY triggerDirectionChanged) |
669 | + Q_PROPERTY(bool triggerZoneEnabled READ triggerZoneEnabled WRITE setTriggerZoneEnabled NOTIFY triggerZoneEnabledChanged) |
670 | + Q_PROPERTY(int threshold READ threshold WRITE setThreshold NOTIFY thresholdChanged) |
671 | + Q_PROPERTY(int maxVelocityMultiplier READ maxVelocityMultiplier WRITE setMaxVelocityMultiplier NOTIFY maxVelocityMultiplierChanged) |
672 | + Q_PROPERTY(int decayRate READ decayRate WRITE setDecayRate NOTIFY decayRateChanged) |
673 | + Q_PROPERTY(int triggerPressure READ triggerPressure WRITE setTriggerPressure NOTIFY triggerPressureChanged) |
674 | + Q_PROPERTY(int breakPressure READ breakPressure WRITE setBreakPressure NOTIFY breakPressureChanged) |
675 | + |
676 | +friend class PointerBarrierManager; |
677 | + |
678 | +public: |
679 | + enum TriggerDirection { |
680 | + TriggerFromAnywhere, |
681 | + TriggerFromRight, |
682 | + TriggerFromLeft, |
683 | + TriggerFromTop, |
684 | + TriggerFromBottom |
685 | + }; |
686 | + Q_ENUMS(TriggerDirection) |
687 | + |
688 | + PointerBarrierWrapper(QObject* parent = 0); |
689 | + ~PointerBarrierWrapper(); |
690 | + |
691 | + QPointF p1() const; |
692 | + void setP1(const QPointF &p); |
693 | + |
694 | + QPointF p2() const; |
695 | + void setP2(const QPointF &p); |
696 | + |
697 | + QPointF triggerZoneP1() const; |
698 | + void setTriggerZoneP1(const QPointF &p); |
699 | + |
700 | + QPointF triggerZoneP2() const; |
701 | + void setTriggerZoneP2(const QPointF &p); |
702 | + |
703 | + TriggerDirection triggerDirection() const; |
704 | + void setTriggerDirection(TriggerDirection direction); |
705 | + |
706 | + bool triggerZoneEnabled() const; |
707 | + void setTriggerZoneEnabled(bool enabled); |
708 | + |
709 | + int threshold() const; |
710 | + void setThreshold(int threshold); |
711 | + |
712 | + qreal maxVelocityMultiplier() const; |
713 | + void setMaxVelocityMultiplier(qreal maxVelocityMultiplier); |
714 | + |
715 | + int decayRate() const; |
716 | + void setDecayRate(int decayRate); |
717 | + |
718 | + int triggerPressure() const; |
719 | + void setTriggerPressure(int pressure); |
720 | + |
721 | + int breakPressure() const; |
722 | + void setBreakPressure(int pressure); |
723 | + |
724 | + PointerBarrier barrier() const; |
725 | + |
726 | +Q_SIGNALS: |
727 | + void p1Changed(const QPointF &p1); |
728 | + void p2Changed(const QPointF &p2); |
729 | + void triggerZoneP1Changed(const QPointF &p1); |
730 | + void triggerZoneP2Changed(const QPointF &p2); |
731 | + void triggerDirectionChanged(TriggerDirection direction); |
732 | + void triggerZoneEnabledChanged(bool changed); |
733 | + void thresholdChanged(int threshold); |
734 | + void maxVelocityMultiplierChanged(qreal maxVelocityMultiplier); |
735 | + void decayRateChanged(int decayRate); |
736 | + void triggerPressureChanged(int breakPressure); |
737 | + void breakPressureChanged(int breakPressure); |
738 | + |
739 | + void triggered(); |
740 | + void broken(); |
741 | + |
742 | +private Q_SLOTS: |
743 | + void smoother(); |
744 | + |
745 | +private: |
746 | + Q_DISABLE_COPY(PointerBarrierWrapper); |
747 | + |
748 | + void createBarrier(); |
749 | + void destroyBarrier(); |
750 | + |
751 | + void doProcess(XFixesBarrierNotifyEvent *event); |
752 | + |
753 | + void updateRealDecayTargetPressures(); |
754 | + |
755 | + void handleTriggerZoneChanged(); |
756 | + |
757 | + bool isPointAlignmentCorrect() const; |
758 | + |
759 | + PointerBarrier m_barrier; |
760 | + |
761 | + QPointF m_p1; |
762 | + QPointF m_p2; |
763 | + QPointF m_triggerZoneP1; |
764 | + QPointF m_triggerZoneP2; |
765 | + TriggerDirection m_triggerDirection; |
766 | + bool m_triggerZoneEnabled; |
767 | + int m_threshold; |
768 | + qreal m_maxVelocityMultiplier; |
769 | + int m_decayRate; |
770 | + int m_triggerPressure; |
771 | + int m_breakPressure; |
772 | + |
773 | + QTimer *m_smoothingTimer; |
774 | + |
775 | + int m_lastEventX; |
776 | + int m_lastEventY; |
777 | + int m_lastEventId; |
778 | + int m_smoothingCount; |
779 | + int m_smoothingAccumulator; |
780 | + |
781 | + DecayedValue m_triggerValue; |
782 | + DecayedValue m_breakValue; |
783 | +}; |
784 | + |
785 | +#endif // POINTERBARRIER_H |
786 | |
787 | === added file 'libunity-2d-private/src/pointerbarriermanager.cpp' |
788 | --- libunity-2d-private/src/pointerbarriermanager.cpp 1970-01-01 00:00:00 +0000 |
789 | +++ libunity-2d-private/src/pointerbarriermanager.cpp 2012-03-05 14:20:25 +0000 |
790 | @@ -0,0 +1,84 @@ |
791 | +/* |
792 | + * Copyright (C) 2012 Canonical, Ltd. |
793 | + * |
794 | + * This program is free software; you can redistribute it and/or modify |
795 | + * it under the terms of the GNU General Public License as published by |
796 | + * the Free Software Foundation; version 3. |
797 | + * |
798 | + * This program is distributed in the hope that it will be useful, |
799 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
800 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
801 | + * GNU General Public License for more details. |
802 | + * |
803 | + * You should have received a copy of the GNU General Public License |
804 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
805 | + */ |
806 | + |
807 | +// Special ordering to bypass evil X11 include |
808 | +#include <QDebug> |
809 | + |
810 | +// Self |
811 | +#include "pointerbarriermanager.h" |
812 | + |
813 | +// libunity-2d |
814 | +#include "pointerbarrier.h" |
815 | + |
816 | +// Qt |
817 | +#include <QX11Info> |
818 | + |
819 | +// X |
820 | +#include <X11/extensions/Xfixes.h> |
821 | + |
822 | +PointerBarrierManager *PointerBarrierManager::instance() |
823 | +{ |
824 | + static PointerBarrierManager *bpm = NULL; |
825 | + if (bpm == NULL) bpm = new PointerBarrierManager(); |
826 | + return bpm; |
827 | +} |
828 | + |
829 | +PointerBarrierManager::PointerBarrierManager() |
830 | +{ |
831 | + Display *display = QX11Info::display(); |
832 | + |
833 | + XFixesQueryExtension(display, &m_eventBase, &m_errorBase); |
834 | + |
835 | + Unity2dApplication* application = Unity2dApplication::instance(); |
836 | + if (application == NULL) { |
837 | + /* This can happen for example when using qmlviewer to run the launcher */ |
838 | + qWarning() << "The application is not an Unity2dApplication." |
839 | + "Barriers will not be monitored."; |
840 | + } else { |
841 | + application->installX11EventFilter(this); |
842 | + } |
843 | + |
844 | + /* Enables barrier detection events - only call once!! */ |
845 | + XFixesSelectBarrierInput(display, DefaultRootWindow(display), 0xdeadbeef); |
846 | +} |
847 | + |
848 | +void PointerBarrierManager::addBarrier(PointerBarrierWrapper *barrier) |
849 | +{ |
850 | + m_barriers += barrier; |
851 | +} |
852 | + |
853 | +void PointerBarrierManager::removeBarrier(PointerBarrierWrapper *barrier) |
854 | +{ |
855 | + m_barriers -= barrier; |
856 | +} |
857 | + |
858 | +bool PointerBarrierManager::x11EventFilter(XEvent* event) |
859 | +{ |
860 | + if (event->type - m_eventBase == XFixesBarrierNotify) { |
861 | + XFixesBarrierNotifyEvent *notifyEvent = (XFixesBarrierNotifyEvent *)event; |
862 | + |
863 | + if (notifyEvent->subtype == XFixesBarrierHitNotify) { |
864 | + Q_FOREACH (PointerBarrierWrapper *barrier, m_barriers) { |
865 | + if (barrier->barrier() == notifyEvent->barrier) { |
866 | + barrier->doProcess(notifyEvent); |
867 | + return true; |
868 | + } |
869 | + } |
870 | + } |
871 | + } |
872 | + return false; |
873 | + |
874 | +} |
875 | |
876 | === added file 'libunity-2d-private/src/pointerbarriermanager.h' |
877 | --- libunity-2d-private/src/pointerbarriermanager.h 1970-01-01 00:00:00 +0000 |
878 | +++ libunity-2d-private/src/pointerbarriermanager.h 2012-03-05 14:20:25 +0000 |
879 | @@ -0,0 +1,44 @@ |
880 | +/* |
881 | + * Copyright (C) 2012 Canonical, Ltd. |
882 | + * |
883 | + * This program is free software; you can redistribute it and/or modify |
884 | + * it under the terms of the GNU General Public License as published by |
885 | + * the Free Software Foundation; version 3. |
886 | + * |
887 | + * This program is distributed in the hope that it will be useful, |
888 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
889 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
890 | + * GNU General Public License for more details. |
891 | + * |
892 | + * You should have received a copy of the GNU General Public License |
893 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
894 | + */ |
895 | + |
896 | +#ifndef POINTERBARRIERMANAGER_H |
897 | +#define POINTERBARRIERMANAGER_H |
898 | + |
899 | +#include "unity2dapplication.h" |
900 | + |
901 | +class PointerBarrierWrapper; |
902 | + |
903 | +class PointerBarrierManager : protected AbstractX11EventFilter |
904 | +{ |
905 | +public: |
906 | + static PointerBarrierManager *instance(); |
907 | + |
908 | + void addBarrier(PointerBarrierWrapper *barrier); |
909 | + void removeBarrier(PointerBarrierWrapper *barrier); |
910 | + |
911 | +protected: |
912 | + bool x11EventFilter(XEvent* event); |
913 | + |
914 | +private: |
915 | + Q_DISABLE_COPY(PointerBarrierManager); |
916 | + |
917 | + PointerBarrierManager(); |
918 | + QSet<PointerBarrierWrapper*> m_barriers; |
919 | + int m_eventBase; |
920 | + int m_errorBase; |
921 | +}; |
922 | + |
923 | +#endif // POINTERBARRIERMANAGER_H |
924 | |
925 | === modified file 'libunity-2d-private/tests/CMakeLists.txt' |
926 | --- libunity-2d-private/tests/CMakeLists.txt 2012-01-24 08:38:24 +0000 |
927 | +++ libunity-2d-private/tests/CMakeLists.txt 2012-03-05 14:20:25 +0000 |
928 | @@ -8,6 +8,7 @@ |
929 | ${CMAKE_CURRENT_BINARY_DIR} |
930 | ${GLIB_INCLUDE_DIRS} |
931 | ${QT_QTTEST_INCLUDE_DIR} |
932 | + ${X11_XTest_INCLUDE_PATH} |
933 | ) |
934 | |
935 | set(LIBUNITY_2D_TEST_DIR ${libunity-2d-private_BINARY_DIR}/tests) |
936 | @@ -37,7 +38,10 @@ |
937 | listaggregatormodeltest |
938 | qsortfilterproxymodeltest |
939 | focuspathtest |
940 | + pointerbarriertest |
941 | ) |
942 | + |
943 | +target_link_libraries(pointerbarriertest ${X11_XTest_LIB}) |
944 | |
945 | # unity2dtrtest - FIXME |
946 | #add_test(NAME unity2dtrtest_check |
947 | |
948 | === added file 'libunity-2d-private/tests/pointerbarriertest.cpp' |
949 | --- libunity-2d-private/tests/pointerbarriertest.cpp 1970-01-01 00:00:00 +0000 |
950 | +++ libunity-2d-private/tests/pointerbarriertest.cpp 2012-03-05 14:20:25 +0000 |
951 | @@ -0,0 +1,312 @@ |
952 | +/* |
953 | + * This file is part of unity-2d |
954 | + * |
955 | + * Copyright 2010 Canonical Ltd. |
956 | + * |
957 | + * Authors: |
958 | + * - Aurélien Gâteau <aurelien.gateau@canonical.com> |
959 | + * |
960 | + * This program is free software; you can redistribute it and/or modify |
961 | + * it under the terms of the GNU General Public License as published by |
962 | + * the Free Software Foundation; version 3. |
963 | + * |
964 | + * This program is distributed in the hope that it will be useful, |
965 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
966 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
967 | + * GNU General Public License for more details. |
968 | + * |
969 | + * You should have received a copy of the GNU General Public License |
970 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
971 | + */ |
972 | + |
973 | +// Local |
974 | +#include <unitytestmacro.h> |
975 | +#include <pointerbarrier.h> |
976 | + |
977 | +// Qt |
978 | +#include <QApplication> |
979 | +#include <QSignalSpy> |
980 | +#include <QX11Info> |
981 | +#include <QtTestGui> |
982 | + |
983 | +#include <X11/extensions/XTest.h> |
984 | + |
985 | +class DisableTriggerZoneOnTriggerHelper : public QObject |
986 | +{ |
987 | + Q_OBJECT |
988 | +public: |
989 | + DisableTriggerZoneOnTriggerHelper(PointerBarrierWrapper *barrier) |
990 | + { |
991 | + m_barrier = barrier; |
992 | + connect(barrier, SIGNAL(triggered()), this, SLOT(disable())); |
993 | + } |
994 | + |
995 | +public Q_SLOTS: |
996 | + void disable() |
997 | + { |
998 | + m_barrier->setTriggerZoneEnabled(false); |
999 | + } |
1000 | + |
1001 | +private: |
1002 | + PointerBarrierWrapper *m_barrier; |
1003 | +}; |
1004 | + |
1005 | +class PointerBarrierTest : public QObject |
1006 | +{ |
1007 | + Q_OBJECT |
1008 | +private Q_SLOTS: |
1009 | + void testBreak() |
1010 | + { |
1011 | + Display *display = QX11Info::display(); |
1012 | + PointerBarrierWrapper barrier; |
1013 | + |
1014 | + QSignalSpy brokenSpy(&barrier, SIGNAL(broken())); |
1015 | + QSignalSpy triggeredSpy(&barrier, SIGNAL(triggered())); |
1016 | + |
1017 | + XTestFakeMotionEvent(display, -1, 50, 50, 0); |
1018 | + QCOMPARE(QCursor::pos(), QPoint(50, 50)); |
1019 | + |
1020 | + barrier.setP1(QPointF(100, 0)); |
1021 | + barrier.setP2(QPointF(100, 100)); |
1022 | + barrier.setThreshold(6500); |
1023 | + barrier.setMaxVelocityMultiplier(2); |
1024 | + barrier.setDecayRate(1500); |
1025 | + barrier.setBreakPressure(2000); |
1026 | + |
1027 | + XTestFakeRelativeMotionEvent(display, 300, 0, 0); |
1028 | + // We are stopped by the barrier and instead in 350, 50 we are in 99, 50 |
1029 | + QCOMPARE(QCursor::pos(), QPoint(99, 50)); |
1030 | + |
1031 | + QCOMPARE(brokenSpy.count(), 0); |
1032 | + QCOMPARE(triggeredSpy.count(), 0); |
1033 | + |
1034 | + for (int i = 0; i < 10; ++i) { |
1035 | + XTestFakeRelativeMotionEvent(display, 100, 0, 0); |
1036 | + QTest::qWait(100); |
1037 | + } |
1038 | + // We have broken the barrier and are somewhere else |
1039 | + QVERIFY(QCursor::pos() != QPoint(99, 50)); |
1040 | + QCOMPARE(brokenSpy.count(), 1); |
1041 | + QCOMPARE(triggeredSpy.count(), 0); |
1042 | + } |
1043 | + |
1044 | + void testStopArea() |
1045 | + { |
1046 | + Display *display = QX11Info::display(); |
1047 | + PointerBarrierWrapper barrier; |
1048 | + |
1049 | + QSignalSpy brokenSpy(&barrier, SIGNAL(broken())); |
1050 | + QSignalSpy triggeredSpy(&barrier, SIGNAL(triggered())); |
1051 | + |
1052 | + XTestFakeMotionEvent(display, -1, 50, 150, 0); |
1053 | + QCOMPARE(QCursor::pos(), QPoint(50, 150)); |
1054 | + |
1055 | + barrier.setP1(QPointF(100, 0)); |
1056 | + barrier.setP2(QPointF(100, 100)); |
1057 | + barrier.setThreshold(6500); |
1058 | + barrier.setMaxVelocityMultiplier(2); |
1059 | + barrier.setDecayRate(1500); |
1060 | + barrier.setBreakPressure(2000); |
1061 | + |
1062 | + XTestFakeRelativeMotionEvent(display, 300, 0, 0); |
1063 | + // We are not stopped by the barrier because it's above us |
1064 | + // and are in 350, 150 |
1065 | + QCOMPARE(QCursor::pos(), QPoint(350, 150)); |
1066 | + |
1067 | + QCOMPARE(brokenSpy.count(), 0); |
1068 | + QCOMPARE(triggeredSpy.count(), 0); |
1069 | + } |
1070 | + |
1071 | + void testTrigger() |
1072 | + { |
1073 | + Display *display = QX11Info::display(); |
1074 | + PointerBarrierWrapper barrier; |
1075 | + |
1076 | + QSignalSpy brokenSpy(&barrier, SIGNAL(broken())); |
1077 | + QSignalSpy triggeredSpy(&barrier, SIGNAL(triggered())); |
1078 | + |
1079 | + XTestFakeMotionEvent(display, -1, 50, 50, 0); |
1080 | + QCOMPARE(QCursor::pos(), QPoint(50, 50)); |
1081 | + |
1082 | + barrier.setP1(QPointF(100, 0)); |
1083 | + barrier.setP2(QPointF(100, 100)); |
1084 | + barrier.setTriggerZoneP1(QPointF(100, 0)); |
1085 | + barrier.setTriggerZoneP2(QPointF(100, 100)); |
1086 | + barrier.setTriggerZoneEnabled(true); |
1087 | + barrier.setThreshold(6500); |
1088 | + barrier.setMaxVelocityMultiplier(2); |
1089 | + barrier.setDecayRate(1500); |
1090 | + barrier.setTriggerPressure(2000); |
1091 | + barrier.setBreakPressure(2000); |
1092 | + |
1093 | + XTestFakeRelativeMotionEvent(display, 300, 0, 0); |
1094 | + // We are stopped by the barrier and instead in 350, 50 we are in 99, 50 |
1095 | + QCOMPARE(QCursor::pos(), QPoint(99, 50)); |
1096 | + |
1097 | + QCOMPARE(brokenSpy.count(), 0); |
1098 | + QCOMPARE(triggeredSpy.count(), 0); |
1099 | + |
1100 | + for (int i = 0; i < 10; ++i) { |
1101 | + XTestFakeRelativeMotionEvent(display, 100, 0, 0); |
1102 | + QTest::qWait(100); |
1103 | + } |
1104 | + // We have triggered the barrier and are still there |
1105 | + QCOMPARE(QCursor::pos(), QPoint(99, 50)); |
1106 | + QCOMPARE(brokenSpy.count(), 0); |
1107 | + QVERIFY(triggeredSpy.count() >= 1); |
1108 | + } |
1109 | + |
1110 | + void testTriggerAndBreak() |
1111 | + { |
1112 | + Display *display = QX11Info::display(); |
1113 | + PointerBarrierWrapper barrier; |
1114 | + |
1115 | + QSignalSpy brokenSpy(&barrier, SIGNAL(broken())); |
1116 | + QSignalSpy triggeredSpy(&barrier, SIGNAL(triggered())); |
1117 | + |
1118 | + XTestFakeMotionEvent(display, -1, 50, 50, 0); |
1119 | + QCOMPARE(QCursor::pos(), QPoint(50, 50)); |
1120 | + |
1121 | + barrier.setP1(QPointF(100, 0)); |
1122 | + barrier.setP2(QPointF(100, 100)); |
1123 | + barrier.setTriggerZoneP1(QPointF(100, 0)); |
1124 | + barrier.setTriggerZoneP2(QPointF(100, 100)); |
1125 | + barrier.setTriggerZoneEnabled(true); |
1126 | + barrier.setThreshold(6500); |
1127 | + barrier.setMaxVelocityMultiplier(2); |
1128 | + barrier.setDecayRate(1500); |
1129 | + barrier.setTriggerPressure(2000); |
1130 | + barrier.setBreakPressure(2000); |
1131 | + |
1132 | + DisableTriggerZoneOnTriggerHelper helper(&barrier); |
1133 | + |
1134 | + XTestFakeRelativeMotionEvent(display, 300, 0, 0); |
1135 | + // We are stopped by the barrier and instead in 350, 50 we are in 99, 50 |
1136 | + QCOMPARE(QCursor::pos(), QPoint(99, 50)); |
1137 | + |
1138 | + QCOMPARE(brokenSpy.count(), 0); |
1139 | + QCOMPARE(triggeredSpy.count(), 0); |
1140 | + |
1141 | + for (int i = 0; i < 10; ++i) { |
1142 | + XTestFakeRelativeMotionEvent(display, 100, 0, 0); |
1143 | + QTest::qWait(100); |
1144 | + } |
1145 | + // We have triggered and broken the barrier and somewhere else |
1146 | + QVERIFY(QCursor::pos() != QPoint(99, 50)); |
1147 | + QCOMPARE(brokenSpy.count(), 1); |
1148 | + QCOMPARE(triggeredSpy.count(), 1); |
1149 | + } |
1150 | + |
1151 | + void testTriggerWithoutAndBreak() |
1152 | + { |
1153 | + Display *display = QX11Info::display(); |
1154 | + PointerBarrierWrapper barrier; |
1155 | + |
1156 | + QSignalSpy brokenSpy(&barrier, SIGNAL(broken())); |
1157 | + QSignalSpy triggeredSpy(&barrier, SIGNAL(triggered())); |
1158 | + |
1159 | + XTestFakeMotionEvent(display, -1, 50, 50, 0); |
1160 | + QCOMPARE(QCursor::pos(), QPoint(50, 50)); |
1161 | + |
1162 | + barrier.setP1(QPointF(100, 0)); |
1163 | + barrier.setP2(QPointF(100, 100)); |
1164 | + barrier.setTriggerZoneP1(QPointF(100, 0)); |
1165 | + barrier.setTriggerZoneP2(QPointF(100, 100)); |
1166 | + barrier.setTriggerZoneEnabled(true); |
1167 | + barrier.setThreshold(6500); |
1168 | + barrier.setMaxVelocityMultiplier(2); |
1169 | + barrier.setDecayRate(1500); |
1170 | + barrier.setTriggerPressure(2000); |
1171 | + barrier.setBreakPressure(2000); |
1172 | + |
1173 | + DisableTriggerZoneOnTriggerHelper helper(&barrier); |
1174 | + |
1175 | + XTestFakeRelativeMotionEvent(display, 300, 0, 0); |
1176 | + // We are stopped by the barrier and instead in 350, 50 we are in 99, 50 |
1177 | + QCOMPARE(QCursor::pos(), QPoint(99, 50)); |
1178 | + |
1179 | + QCOMPARE(brokenSpy.count(), 0); |
1180 | + QCOMPARE(triggeredSpy.count(), 0); |
1181 | + |
1182 | + for (int i = 0; i < 10 && barrier.triggerZoneEnabled(); ++i) { |
1183 | + XTestFakeRelativeMotionEvent(display, 100, 0, 0); |
1184 | + QTest::qWait(100); |
1185 | + } |
1186 | + // We have triggered the barrier |
1187 | + QCOMPARE(QCursor::pos(), QPoint(99, 50)); |
1188 | + QCOMPARE(brokenSpy.count(), 0); |
1189 | + QCOMPARE(triggeredSpy.count(), 1); |
1190 | + |
1191 | + // We can push a bit more without breaking the barrier |
1192 | + for (int i = 0; i < 2; ++i) { |
1193 | + XTestFakeRelativeMotionEvent(display, 100, 0, 0); |
1194 | + QTest::qWait(100); |
1195 | + } |
1196 | + QCOMPARE(QCursor::pos(), QPoint(99, 50)); |
1197 | + QCOMPARE(brokenSpy.count(), 0); |
1198 | + QCOMPARE(triggeredSpy.count(), 1); |
1199 | + } |
1200 | + |
1201 | + void testTriggerAndBreakZones() |
1202 | + { |
1203 | + Display *display = QX11Info::display(); |
1204 | + PointerBarrierWrapper barrier; |
1205 | + |
1206 | + QSignalSpy brokenSpy(&barrier, SIGNAL(broken())); |
1207 | + QSignalSpy triggeredSpy(&barrier, SIGNAL(triggered())); |
1208 | + |
1209 | + XTestFakeMotionEvent(display, -1, 50, 25, 0); |
1210 | + QCOMPARE(QCursor::pos(), QPoint(50, 25)); |
1211 | + |
1212 | + barrier.setP1(QPointF(100, 0)); |
1213 | + barrier.setP2(QPointF(100, 200)); |
1214 | + barrier.setTriggerZoneP1(QPointF(100, 50)); |
1215 | + barrier.setTriggerZoneP2(QPointF(100, 150)); |
1216 | + barrier.setTriggerZoneEnabled(true); |
1217 | + barrier.setThreshold(6500); |
1218 | + barrier.setMaxVelocityMultiplier(2); |
1219 | + barrier.setDecayRate(1500); |
1220 | + barrier.setTriggerPressure(2000); |
1221 | + barrier.setBreakPressure(2000); |
1222 | + |
1223 | + DisableTriggerZoneOnTriggerHelper helper(&barrier); |
1224 | + |
1225 | + XTestFakeRelativeMotionEvent(display, 300, 0, 0); |
1226 | + // We are stopped by the barrier and instead in 350, 25 we are in 99, 25 |
1227 | + QCOMPARE(QCursor::pos(), QPoint(99, 25)); |
1228 | + |
1229 | + QCOMPARE(brokenSpy.count(), 0); |
1230 | + QCOMPARE(triggeredSpy.count(), 0); |
1231 | + |
1232 | + for (int i = 0; i < 10; ++i) { |
1233 | + XTestFakeRelativeMotionEvent(display, 100, 0, 0); |
1234 | + QTest::qWait(100); |
1235 | + } |
1236 | + |
1237 | + // We are above the trigger zone so we have only broke the barrier |
1238 | + QVERIFY(QCursor::pos() != QPoint(99, 25)); |
1239 | + QCOMPARE(brokenSpy.count(), 1); |
1240 | + QCOMPARE(triggeredSpy.count(), 0); |
1241 | + |
1242 | + // Go back |
1243 | + XTestFakeMotionEvent(display, -1, 50, 100, 0); |
1244 | + |
1245 | + XTestFakeRelativeMotionEvent(display, 300, 0, 0); |
1246 | + // We are stopped by the barrier and instead in 350, 100 we are in 99, 100 |
1247 | + QCOMPARE(QCursor::pos(), QPoint(99, 100)); |
1248 | + |
1249 | + for (int i = 0; i < 10; ++i) { |
1250 | + XTestFakeRelativeMotionEvent(display, 100, 0, 0); |
1251 | + QTest::qWait(100); |
1252 | + } |
1253 | + |
1254 | + // We are in the trigger zone so we have triggered and broken the barrier |
1255 | + QVERIFY(QCursor::pos() != QPoint(99, 100)); |
1256 | + QCOMPARE(brokenSpy.count(), 2); |
1257 | + QCOMPARE(triggeredSpy.count(), 1); |
1258 | + } |
1259 | +}; |
1260 | + |
1261 | +UAPP_TEST_MAIN(PointerBarrierTest) |
1262 | + |
1263 | +#include "pointerbarriertest.moc" |
1264 | |
1265 | === modified file 'shell/Shell.qml' |
1266 | --- shell/Shell.qml 2012-02-28 12:00:14 +0000 |
1267 | +++ shell/Shell.qml 2012-03-05 14:20:25 +0000 |
1268 | @@ -93,6 +93,13 @@ |
1269 | if (dashLoader.status == Loader.Ready) dashLoader.item.deactivateAllLenses() |
1270 | } |
1271 | } |
1272 | + onGlobalPositionChanged: { |
1273 | + var x = declarativeView.globalPosition.x + (Utils.isLeftToRight() ? 0 : shell.width) |
1274 | + launcherLoader.item.barrierP1 = Qt.point(x, 0) |
1275 | + launcherLoader.item.barrierP2 = Qt.point(x, declarativeView.screen.geometry.height) |
1276 | + launcherLoader.item.barrierTriggerZoneP1 = Qt.point(x, declarativeView.globalPosition.y) |
1277 | + launcherLoader.item.barrierTriggerZoneP2 = Qt.point(x, declarativeView.globalPosition.y + launcherLoader.height) |
1278 | + } |
1279 | } |
1280 | |
1281 | SpreadMonitor { |
1282 | @@ -219,24 +226,10 @@ |
1283 | Binding { |
1284 | target: launcherInputShape |
1285 | property: "rectangle" |
1286 | - value: { |
1287 | - // FIXME: this results in a 1px wide white rectangle on the launcher edge, we should switch |
1288 | - // to cpp-based edge detection, and later XFixes barriers to get rid of that completely |
1289 | - var somewhatShown = Utils.isLeftToRight() ? -launcherLoader.x < launcherLoader.width : launcherLoader.x < shell.width |
1290 | - if (somewhatShown) { |
1291 | - return Qt.rect(launcherLoader.x, |
1292 | - launcherLoader.y, |
1293 | - launcherLoader.width, |
1294 | - launcherLoader.height) |
1295 | - } else { |
1296 | - // The outerEdgeMouseArea is one pixel bigger on each side so use it |
1297 | - // when the launcher is hidden to have that extra pixel in the border |
1298 | - return Qt.rect(launcherLoader.x + launcherLoader.outerEdgeMouseArea.x, |
1299 | - launcherLoader.y, |
1300 | - launcherLoader.outerEdgeMouseArea.width, |
1301 | - launcherLoader.height) |
1302 | - } |
1303 | - } |
1304 | + value: Qt.rect(launcherLoader.x, |
1305 | + launcherLoader.y, |
1306 | + launcherLoader.width, |
1307 | + launcherLoader.height) |
1308 | when: !launcherLoaderXAnimation.running |
1309 | } |
1310 | |
1311 | |
1312 | === modified file 'shell/common/visibilityBehaviors/AutoHideBehavior.qml' |
1313 | --- shell/common/visibilityBehaviors/AutoHideBehavior.qml 2012-03-02 13:48:01 +0000 |
1314 | +++ shell/common/visibilityBehaviors/AutoHideBehavior.qml 2012-03-05 14:20:25 +0000 |
1315 | @@ -18,13 +18,14 @@ |
1316 | |
1317 | import QtQuick 1.0 |
1318 | |
1319 | -// Shows the target when it has the focus or when you move the |
1320 | -// mouse for 500 msec to the edge of the target |
1321 | +// Shows the target when it has the focus or when you trigger the pointer barrier |
1322 | +// in the edge of the target |
1323 | // Hides the target when none of the above conditions are met |
1324 | // and you have not had the mouse over it during more than 1000 msec |
1325 | -// To use this Behavior your target needs to provide two properties |
1326 | +// To use this Behavior your target needs to provide one properties |
1327 | // - containsMouse: Defines if the mouse is inside the target |
1328 | -// - outerEdgeContainsMouse: Defines if the mouse is in the edge of the target |
1329 | +// and one signal |
1330 | +// - barrierTriggered: Defines when the pointer barrier has been triggered |
1331 | |
1332 | BaseBehavior { |
1333 | id: autoHide |
1334 | @@ -51,12 +52,6 @@ |
1335 | onTriggered: shownRegardlessOfFocus = false |
1336 | } |
1337 | |
1338 | - Timer { |
1339 | - id: edgeHitTimer |
1340 | - interval: 500 |
1341 | - onTriggered: shownRegardlessOfFocus = true |
1342 | - } |
1343 | - |
1344 | Connections { |
1345 | target: (autoHide.target !== undefined) ? autoHide.target : null |
1346 | onContainsMouseChanged: { |
1347 | @@ -68,7 +63,6 @@ |
1348 | |
1349 | Connections { |
1350 | target: autoHide.target !== undefined ? autoHide.target : null |
1351 | - onOuterEdgeContainsMouseChanged: edgeHitTimer.running = target.outerEdgeContainsMouse |
1352 | - ignoreUnknownSignals: true |
1353 | + onBarrierTriggered: shownRegardlessOfFocus = true |
1354 | } |
1355 | } |
1356 | |
1357 | === modified file 'shell/common/visibilityBehaviors/IntelliHideBehavior.qml' |
1358 | --- shell/common/visibilityBehaviors/IntelliHideBehavior.qml 2012-03-02 13:48:01 +0000 |
1359 | +++ shell/common/visibilityBehaviors/IntelliHideBehavior.qml 2012-03-05 14:20:25 +0000 |
1360 | @@ -20,14 +20,14 @@ |
1361 | import Unity2d 1.0 |
1362 | import "../utils.js" as Utils |
1363 | |
1364 | -// Shows the target when it has the focus or when you move the |
1365 | -// mouse for 500 msec to the edge of the target or there are no |
1366 | -// windows that intersect with the target |
1367 | +// Shows the target when it has the focus or when you trigger the pointer barrier |
1368 | +// or there are no windows that intersect with the target |
1369 | // Hides the target when none of the above conditions are met |
1370 | // and you have not had the mouse over it during more than 1000 msec |
1371 | -// To use this Behavior your target needs to provide two properties |
1372 | +// To use this Behavior your target needs to provide one properties |
1373 | // - containsMouse: Defines if the mouse is inside the target |
1374 | -// - outerEdgeContainsMouse: Defines if the mouse is in the edge of the target |
1375 | +// and one signal |
1376 | +// - barrierTriggered: Defines when the pointer barrier has been triggered |
1377 | |
1378 | AutoHideBehavior { |
1379 | id: intellihide |
1380 | |
1381 | === modified file 'shell/launcher/Launcher.qml' |
1382 | --- shell/launcher/Launcher.qml 2012-02-27 10:50:43 +0000 |
1383 | +++ shell/launcher/Launcher.qml 2012-03-05 14:20:25 +0000 |
1384 | @@ -25,11 +25,33 @@ |
1385 | id: launcher |
1386 | Accessible.name: "launcher" |
1387 | |
1388 | - property bool outerEdgeContainsMouse |
1389 | + signal barrierTriggered |
1390 | + |
1391 | property bool shown |
1392 | property bool showMenus: true |
1393 | |
1394 | property bool containsMouse: declarativeView.monitoredAreaContainsMouse |
1395 | + property variant barrierP1 |
1396 | + property variant barrierP2 |
1397 | + property variant barrierTriggerZoneP1 |
1398 | + property variant barrierTriggerZoneP2 |
1399 | + |
1400 | + PointerBarrier { |
1401 | + id: barrier |
1402 | + triggerDirection: Utils.isLeftToRight() ? PointerBarrier.TriggerFromRight : PointerBarrier.TriggerFromLeft |
1403 | + triggerZoneEnabled: !shown |
1404 | + p1: barrierP1 |
1405 | + p2: barrierP2 |
1406 | + triggerZoneP1: barrierTriggerZoneP1 |
1407 | + triggerZoneP2: barrierTriggerZoneP2 |
1408 | + threshold: launcher2dConfiguration.edgeStopVelocity |
1409 | + maxVelocityMultiplier: launcher2dConfiguration.edgeResponsiveness |
1410 | + decayRate: launcher2dConfiguration.edgeDecayrate |
1411 | + triggerPressure: launcher2dConfiguration.edgeRevealPressure |
1412 | + breakPressure: launcher2dConfiguration.edgeOvercomePressure |
1413 | + |
1414 | + onTriggered: launcher.barrierTriggered() |
1415 | + } |
1416 | |
1417 | function hideMenu() { |
1418 | if (main.visibleMenu !== undefined) { |
1419 | |
1420 | === modified file 'shell/launcher/LauncherLoader.qml' |
1421 | --- shell/launcher/LauncherLoader.qml 2012-02-10 11:17:36 +0000 |
1422 | +++ shell/launcher/LauncherLoader.qml 2012-03-05 14:20:25 +0000 |
1423 | @@ -26,7 +26,6 @@ |
1424 | source: "Launcher.qml" |
1425 | property variant visibilityController: visibilityController |
1426 | onLoaded: item.focus = true |
1427 | - property alias outerEdgeMouseArea: outerEdge |
1428 | |
1429 | VisibilityController { |
1430 | id: visibilityController |
1431 | @@ -79,16 +78,7 @@ |
1432 | |
1433 | Binding { |
1434 | target: launcherLoader.item |
1435 | - property: "outerEdgeContainsMouse" |
1436 | - value: outerEdge.containsMouse && outerEdge.enabled |
1437 | - } |
1438 | - |
1439 | - MouseArea { |
1440 | - id: outerEdge |
1441 | - anchors.fill: parent |
1442 | - anchors.margins: -1 |
1443 | - hoverEnabled: !visibilityController.shown |
1444 | - enabled: !visibilityController.shown |
1445 | - } |
1446 | - |
1447 | + property: "shown" |
1448 | + value: visibilityController.shown |
1449 | + } |
1450 | } |
1451 | |
1452 | === modified file 'tests/launcher/autohide_show_tests.rb' |
1453 | --- tests/launcher/autohide_show_tests.rb 2012-02-20 14:11:16 +0000 |
1454 | +++ tests/launcher/autohide_show_tests.rb 2012-03-05 14:20:25 +0000 |
1455 | @@ -55,6 +55,12 @@ |
1456 | XDo::Mouse.move(0, 200, 0, true) |
1457 | end |
1458 | |
1459 | + def mouse_push_screen_edge |
1460 | + (1..100).each do |i| |
1461 | + $SUT.execute_shell_command 'xdotool mousemove_relative -- -10 0' |
1462 | + end |
1463 | + end |
1464 | + |
1465 | def move_mouse_to_launcher_inner_border() |
1466 | XDo::Mouse.move(LAUNCHER_WIDTH-1,200) |
1467 | end |
1468 | |
1469 | === modified file 'tests/launcher/autohide_show_tests_common.rb' |
1470 | --- tests/launcher/autohide_show_tests_common.rb 2012-02-20 16:44:00 +0000 |
1471 | +++ tests/launcher/autohide_show_tests_common.rb 2012-03-05 14:20:25 +0000 |
1472 | @@ -114,7 +114,7 @@ |
1473 | # * Open application in position overlapping Launcher |
1474 | # * Verify Launcher hiding |
1475 | # * Move mouse to left of screen to reveal Launcher |
1476 | -# * Verify Launcher shows but not immediately |
1477 | +# * Verify Launcher shows only if we push the barrier |
1478 | # * Move mouse to the right, but still over the Launcher |
1479 | # * Verify Launcher still showing |
1480 | # * Move mouse further right to not overlap Launcher |
1481 | @@ -128,8 +128,8 @@ |
1482 | verify_launcher_hidden(TIMEOUT, 'Launcher visible with window in the way, should be hidden') |
1483 | |
1484 | move_mouse_to_screen_edge() |
1485 | - sleep 0.4 |
1486 | - verify_launcher_hidden(0, 'Launcher should not be visible immediately after mouse moves to the edge, has to wait 0.5 seconds to show') |
1487 | + verify_launcher_hidden(0, 'Launcher should not be visible immediately without pushing the edge') |
1488 | + mouse_push_screen_edge() |
1489 | verify_launcher_visible(TIMEOUT, 'Launcher hiding when mouse at edge of screen') |
1490 | |
1491 | move_mouse_to_launcher_inner_border() |
1492 | @@ -422,6 +422,7 @@ |
1493 | if !tiles.empty? |
1494 | tile = tiles[0] |
1495 | move_mouse_to_screen_edge() |
1496 | + mouse_push_screen_edge() |
1497 | verify_launcher_visible(TIMEOUT, 'Launcher hiding when mouse at edge of screen, should be visible') |
1498 | tile.move_mouse() |
1499 | XDo::Mouse.click(nil, nil, :right) |
1500 | @@ -457,6 +458,7 @@ |
1501 | |
1502 | bfb = @app.LauncherList( :name => 'main' ).LauncherList( :isBfb => true ); |
1503 | move_mouse_to_screen_edge() |
1504 | + mouse_push_screen_edge() |
1505 | verify_launcher_visible(TIMEOUT, 'Launcher hiding when mouse at edge of screen, should be visible') |
1506 | bfb.move_mouse() |
1507 | bfb.tap() |
1508 | |
1509 | === modified file 'tests/launcher/autohide_show_tests_rtl.rb' |
1510 | --- tests/launcher/autohide_show_tests_rtl.rb 2012-02-20 14:11:16 +0000 |
1511 | +++ tests/launcher/autohide_show_tests_rtl.rb 2012-03-05 14:20:25 +0000 |
1512 | @@ -56,6 +56,12 @@ |
1513 | XDo::Mouse.move(XDo::XWindow.display_geometry[0], 200, 0, true) |
1514 | end |
1515 | |
1516 | + def mouse_push_screen_edge |
1517 | + (1..100).each do |i| |
1518 | + $SUT.execute_shell_command 'xdotool mousemove_relative 10 0' |
1519 | + end |
1520 | + end |
1521 | + |
1522 | def move_mouse_to_launcher_inner_border() |
1523 | XDo::Mouse.move(XDo::XWindow.display_geometry[0] - LAUNCHER_WIDTH, 200) |
1524 | end |
There is the issue that it crashes when run inside of VirtualBox, it crashes because the XFixesBarrierNo tifyEvent- >xany.display is set to 0 (happens only inside the VirtualBox VM)