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