Status: | Merged |
---|---|
Merged at revision: | 214 |
Proposed branch: | lp:~bregma/geis/lp-934207 |
Merge into: | lp:geis |
Diff against target: |
1227 lines (+818/-31) 22 files modified
configure.ac (+4/-4) include/geis/geis.h (+18/-2) libutouch-geis/backend/dbus/geis_dbus_backend.c (+23/-0) libutouch-geis/backend/dbus/geis_dbus_client.c (+24/-0) libutouch-geis/backend/dbus/geis_dbus_client.h (+27/-0) libutouch-geis/backend/grail/geis_grail_backend.c (+131/-4) libutouch-geis/backend/grail/geis_grail_window_grab.c (+13/-1) libutouch-geis/backend/test_fixture/geis_backend_test_fixture.c (+20/-0) libutouch-geis/backend/xcb/geis_xcb_backend.c (+23/-1) libutouch-geis/geis.c (+33/-0) libutouch-geis/geis_backend.c (+22/-0) libutouch-geis/geis_backend.h (+24/-0) libutouch-geis/geis_backend_protected.h (+2/-0) libutouch-geis/geis_event_queue.c (+63/-4) libutouch-geis/geis_event_queue.h (+18/-0) libutouch-geis/geis_frame.c (+0/-8) libutouch-geis/geis_private.h (+19/-0) libutouch-geis/libutouch-geis.ver (+1/-0) testsuite/geis2/Makefile.am (+4/-1) testsuite/geis2/gtest_subscriptions.cpp (+264/-6) testsuite/libutouch-geis/check_event_queue.c (+37/-0) testsuite/libutouch-geis/check_geis_private.c (+48/-0) |
To merge this branch: | bzr merge lp:~bregma/geis/lp-934207 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chase Douglas (community) | Approve | ||
Review via email: mp+97019@code.launchpad.net |
Commit message
Description of the change
Exposes gesture accept and reject functionality if available in back end. Closes lp:934207.
Includes unit tests for both reject and accept.
- 215. By Stephen M. Webb
-
Added remove_if function to GEIS event queues.
- 216. By Stephen M. Webb
-
Added geis_remove_
matching_ event() function. - 217. By Stephen M. Webb
-
Updated integration test to check for rejected events.
- 218. By Stephen M. Webb
-
Added queued event removal on gesture reject.
- 219. By Stephen M. Webb
-
fixed typo in warning message
- 220. By Stephen M. Webb
-
Added check got GESTURE_END in gesture-accept test case.
- 221. By Stephen M. Webb
-
Fixed an edge case in queued events removal.
Stephen M. Webb (bregma) wrote : | # |
* Typo:
Fixed.
* reject needs to remove all matching gesture events from the geis queue.
Since it's impossible to guarantee at the API level that no further event for a rejected gesture will ever come through (event generation is asynchronous over possibly several processes), I figured the application needs to handle this anyway. However, since it is not a big effort to remove these events from the internal GEIS queues, I added this and extended the test case accordingly.
* The accept test case should accept on the begin event, and check if an end event for the gesture is received. This will ensure that the gesture is actually accepted and not rejected.
Sure. Done.
* These tests don't check whether a gesture and its touches are really accepted or rejected. To do this, we need a test that has a subwindow that would receive the touch events if the gesture is rejected, and does not receive touch events if the gesture is accepted. I think this is getting into more testing than this specific functionality requires, but if we hit any bugs where geis accept/reject is not being propagated properly we will need to make these tests.
Yes, I think testing how clients interact with the X server is a little beyond the scope of unit tests for the GEIS API.
Chase Douglas (chasedouglas) wrote : | # |
> * reject needs to remove all matching gesture events from the geis queue.
>
> Since it's impossible to guarantee at the API level that no further event for
> a rejected gesture will ever come through (event generation is asynchronous
> over possibly several processes), I figured the application needs to handle
> this anyway. However, since it is not a big effort to remove these events
> from the internal GEIS queues, I added this and extended the test case
> accordingly.
Grail does guarantee this. It does the same queued event removal that you implemented for geis. This ensures that no further events may propagate up the stack after a rejection.
If we implemented things right, the application should not receive any events after a reject call.
Everything looks good to me now. Let's get this merged and released!
Stephen M. Webb (bregma) wrote : | # |
GEIS is not grail. GEIS was designed to be able to wrap the native gestures on Windows and MacOS (and other targets). GEIS could be used in a client-server mode to comply with the original requirements established last year, and events could be on the wire. It's possible that a future input server could operate in an asynchronous mode.
GEIS was also designed to be extensible through client-programmable recognizers (long term) that could mutate events.
There is no way for the API to guarantee synchronous removal of asynchronous events on gesture rejection unless some sort of complex blacklisting or ongoing detection of events, at considerable cost.
Yes, this particular implementation of the grail back end can minimize outstanding events on a rejected gesture, assuming it is used in client-embedded mode.
Chase Douglas (chasedouglas) wrote : | # |
That's a valid point. In light of that, it's nice that we clean things up :). You're right that we might not be able to guarantee this functionality in all circumstances.
Preview Diff
1 | === modified file 'configure.ac' |
2 | --- configure.ac 2012-03-06 16:38:03 +0000 |
3 | +++ configure.ac 2012-03-13 20:56:18 +0000 |
4 | @@ -101,9 +101,9 @@ |
5 | AC_MSG_RESULT([$with_integration_tests]) |
6 | AS_IF([test "x$with_integration_tests" != xno], |
7 | [AC_LANG_PUSH(C++) |
8 | - AC_CHECK_LIB([gtest], [main], [have_gtest=yes]) |
9 | - AS_IF([test "x$have_gtest" = xyes], |
10 | - [PKG_CHECK_MODULES([XORG_GTEST], |
11 | + AC_CHECK_HEADER([gtest/gtest.h], |
12 | + [AC_SUBST([GTEST_CFLAGS], [-I/usr/src/gtest]) |
13 | + PKG_CHECK_MODULES([XORG_GTEST], |
14 | [xorg-gtest], |
15 | [have_xorg_gtest=yes], |
16 | [AC_MSG_WARN([package 'xorg-gtest' not found: related |
17 | @@ -111,7 +111,7 @@ |
18 | PKG_CHECK_MODULES([EVEMU],[utouch-evemu >= 1.0.5]) |
19 | ]) |
20 | AC_LANG_POP |
21 | - XORG_GTEST_LIBS="$XORG_GTEST_LIBS -lgtest -lpthread"]) |
22 | + XORG_GTEST_LIBS="$XORG_GTEST_LIBS -lpthread"]) |
23 | AM_CONDITIONAL([HAVE_XORG_GTEST],[test "x$have_xorg_gtest" = xyes]) |
24 | |
25 | AC_CONFIG_FILES([Makefile |
26 | |
27 | === modified file 'include/geis/geis.h' |
28 | --- include/geis/geis.h 2012-02-28 15:15:42 +0000 |
29 | +++ include/geis/geis.h 2012-03-13 20:56:18 +0000 |
30 | @@ -2086,16 +2086,32 @@ |
31 | GEIS_API GeisTouchId geis_frame_touchid(GeisFrame frame, GeisSize index); |
32 | |
33 | /** |
34 | + * Marks a gesture as accepted. |
35 | + * |
36 | + * @param[in] geis The GEIS instance. |
37 | + * @param[in] group The gesture group containing the accepted gesture. |
38 | + * @param[in] gesture_id Identifies the gesture. |
39 | + * |
40 | + * @sa geis_frame_id |
41 | + */ |
42 | +GEIS_API GeisStatus geis_gesture_accept(Geis geis, |
43 | + GeisGroup group, |
44 | + GeisGestureId gesture_id); |
45 | + |
46 | +/** |
47 | * Marks a gesture as rejected. |
48 | - * @memberof GeisFrame |
49 | * |
50 | + * @param[in] geis The GEIS instance. |
51 | + * @param[in] group The gesture group containing the rejected gesture. |
52 | * @param[in] gesture_id Identifies the gesture. |
53 | * |
54 | * After you reject a gesture you no longer get its frames. |
55 | * |
56 | * @sa geis_frame_id |
57 | */ |
58 | -GEIS_API void geis_gesture_reject(GeisGestureId gesture_id); |
59 | +GEIS_API GeisStatus geis_gesture_reject(Geis geis, |
60 | + GeisGroup group, |
61 | + GeisGestureId gesture_id); |
62 | |
63 | /* @} */ |
64 | |
65 | |
66 | === modified file 'libutouch-geis/backend/dbus/geis_dbus_backend.c' |
67 | --- libutouch-geis/backend/dbus/geis_dbus_backend.c 2011-10-18 19:30:57 +0000 |
68 | +++ libutouch-geis/backend/dbus/geis_dbus_backend.c 2012-03-13 20:56:18 +0000 |
69 | @@ -221,10 +221,33 @@ |
70 | } |
71 | |
72 | |
73 | +static GeisStatus |
74 | +_geis_dbus_accept_gesture(GeisBackend be, |
75 | + GeisGroup group, |
76 | + GeisGestureId gesture_id) |
77 | +{ |
78 | + GeisDBusBackend gdb = (GeisDBusBackend)be; |
79 | + return geis_dbus_client_accept_gesture(gdb->dbus_client, group, gesture_id); |
80 | +} |
81 | + |
82 | + |
83 | +static GeisStatus |
84 | +_geis_dbus_reject_gesture(GeisBackend be, |
85 | + GeisGroup group, |
86 | + GeisGestureId gesture_id) |
87 | +{ |
88 | + GeisDBusBackend gdb = (GeisDBusBackend)be; |
89 | + return geis_dbus_client_reject_gesture(gdb->dbus_client, group, gesture_id); |
90 | +} |
91 | + |
92 | + |
93 | + |
94 | static struct GeisBackendVtable gdb_vtbl = { |
95 | _geis_dbus_backend_construct, |
96 | _geis_dbus_backend_finalize, |
97 | _geis_dbus_backend_create_token, |
98 | + _geis_dbus_accept_gesture, |
99 | + _geis_dbus_reject_gesture, |
100 | }; |
101 | |
102 | |
103 | |
104 | === modified file 'libutouch-geis/backend/dbus/geis_dbus_client.c' |
105 | --- libutouch-geis/backend/dbus/geis_dbus_client.c 2011-10-18 18:41:30 +0000 |
106 | +++ libutouch-geis/backend/dbus/geis_dbus_client.c 2012-03-13 20:56:18 +0000 |
107 | @@ -681,5 +681,29 @@ |
108 | } |
109 | |
110 | |
111 | +/* |
112 | + * Asks the remote server to accept a gesture. |
113 | + */ |
114 | +GeisStatus |
115 | +geis_dbus_client_accept_gesture(GeisDBusClient client GEIS_UNUSED, |
116 | + GeisGroup group GEIS_UNUSED, |
117 | + GeisGestureId gesture_id GEIS_UNUSED) |
118 | +{ |
119 | + return GEIS_STATUS_SUCCESS; |
120 | +} |
121 | + |
122 | + |
123 | +/* |
124 | + * Asks the remote server to reject a gesture. |
125 | + */ |
126 | +GeisStatus |
127 | +geis_dbus_client_reject_gesture(GeisDBusClient client GEIS_UNUSED, |
128 | + GeisGroup group GEIS_UNUSED, |
129 | + GeisGestureId gesture_id GEIS_UNUSED) |
130 | +{ |
131 | + return GEIS_STATUS_SUCCESS; |
132 | +} |
133 | + |
134 | + |
135 | |
136 | |
137 | |
138 | === modified file 'libutouch-geis/backend/dbus/geis_dbus_client.h' |
139 | --- libutouch-geis/backend/dbus/geis_dbus_client.h 2011-09-08 17:54:35 +0000 |
140 | +++ libutouch-geis/backend/dbus/geis_dbus_client.h 2012-03-13 20:56:18 +0000 |
141 | @@ -93,5 +93,32 @@ |
142 | geis_dbus_client_unsubscribe(GeisDBusClient client, |
143 | GeisSubscription subscription); |
144 | |
145 | +/** |
146 | + * Asks the remote server to accept a gesture. |
147 | + * |
148 | + * @param[in] client The client side of the DBus connection. |
149 | + * @param[in] group The gesture group to which the gesture belongs. |
150 | + * @param[in] gesture_id The gesture to accept. |
151 | + * |
152 | + * @returns GEIS_STATUS_SUCCESS on success, some other value otherwise. |
153 | + */ |
154 | +GeisStatus |
155 | +geis_dbus_client_accept_gesture(GeisDBusClient client, |
156 | + GeisGroup group, |
157 | + GeisGestureId gesture_id); |
158 | + |
159 | +/** |
160 | + * Asks the remote server to reject a gesture. |
161 | + * |
162 | + * @param[in] client The client side of the DBus connection. |
163 | + * @param[in] group The gesture group to which the gesture belongs. |
164 | + * @param[in] gesture_id The gesture to reject. |
165 | + * |
166 | + * @returns GEIS_STATUS_SUCCESS on success, some other value otherwise. |
167 | + */ |
168 | +GeisStatus |
169 | +geis_dbus_client_reject_gesture(GeisDBusClient client, |
170 | + GeisGroup group, |
171 | + GeisGestureId gesture_id); |
172 | |
173 | #endif /* GEIS_DBUS_CLIENT_H_ */ |
174 | |
175 | === modified file 'libutouch-geis/backend/grail/geis_grail_backend.c' |
176 | --- libutouch-geis/backend/grail/geis_grail_backend.c 2012-02-27 19:35:04 +0000 |
177 | +++ libutouch-geis/backend/grail/geis_grail_backend.c 2012-03-13 20:56:18 +0000 |
178 | @@ -1188,6 +1188,15 @@ |
179 | } |
180 | |
181 | |
182 | +static int |
183 | +_grail_be_x_error_handler(Display* display GEIS_UNUSED, |
184 | + XErrorEvent* event GEIS_UNUSED) |
185 | +{ |
186 | + geis_error("error in X detected"); |
187 | + return 0; |
188 | +} |
189 | + |
190 | + |
191 | /** |
192 | * Deconstructs a Grail back end. |
193 | * |
194 | @@ -1205,14 +1214,117 @@ |
195 | geis_demultiplex_fd(gbe->geis, frame_get_fd(gbe->frame)); |
196 | frame_x11_delete(gbe->frame); |
197 | geis_demultiplex_fd(gbe->geis, ConnectionNumber(gbe->display)); |
198 | + |
199 | + XErrorHandler old_x_handler = XSetErrorHandler(_grail_be_x_error_handler); |
200 | XCloseDisplay(gbe->display); |
201 | -} |
202 | - |
203 | + XSetErrorHandler(old_x_handler); |
204 | +} |
205 | + |
206 | + |
207 | +/* |
208 | + * Asks grail to accept an identified gesture. |
209 | + */ |
210 | +GeisStatus |
211 | +_grail_be_accept_gesture(GeisBackend be, |
212 | + GeisGroup group GEIS_UNUSED, |
213 | + GeisGestureId gesture_id) |
214 | +{ |
215 | + GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR; |
216 | + GeisGrailBackend gbe = (GeisGrailBackend)be; |
217 | + unsigned id = gesture_id; |
218 | + UGStatus ugstatus = grail_accept_gesture(gbe->grail, id); |
219 | + if (ugstatus != UGStatusSuccess) |
220 | + { |
221 | + geis_error("accept failed for gesture %u", id); |
222 | + } |
223 | + else |
224 | + { |
225 | + geis_debug("gesture %u accepted", id); |
226 | + status = GEIS_STATUS_SUCCESS; |
227 | + } |
228 | + return status; |
229 | +} |
230 | + |
231 | + |
232 | +/* |
233 | + * Predicate to identify events to remove on rejection. |
234 | + */ |
235 | +static GeisBoolean |
236 | +_grail_be_match_gesture_event(GeisEvent event, void *context) |
237 | +{ |
238 | + GeisGestureId gesture_id = *(GeisGestureId *)context; |
239 | + GeisEventType event_type = geis_event_type(event); |
240 | + if (event_type == GEIS_EVENT_GESTURE_BEGIN |
241 | + || event_type == GEIS_EVENT_GESTURE_UPDATE |
242 | + || event_type == GEIS_EVENT_GESTURE_END) |
243 | + { |
244 | + GeisAttr attr = geis_event_attr_by_name(event, GEIS_EVENT_ATTRIBUTE_GROUPSET); |
245 | + if (!attr) |
246 | + { |
247 | + geis_error("can not get groupset from event"); |
248 | + return GEIS_FALSE; |
249 | + } |
250 | + GeisGroupSet groupset = (GeisGroupSet)geis_attr_value_to_pointer(attr); |
251 | + for (GeisSize i = 0; i < geis_groupset_group_count(groupset); ++i) |
252 | + { |
253 | + GeisGroup group = geis_groupset_group(groupset, i); |
254 | + if (!group) |
255 | + { |
256 | + geis_error("can not get group %zu in groupset of event", i); |
257 | + return GEIS_FALSE; |
258 | + } |
259 | + |
260 | + for (GeisSize j = 0; j < geis_group_frame_count(group); ++j) |
261 | + { |
262 | + GeisFrame frame = geis_group_frame(group, j); |
263 | + if (!frame) |
264 | + { |
265 | + geis_error("can not get frame %zu in group %zu of event", j, i); |
266 | + return GEIS_FALSE; |
267 | + } |
268 | + |
269 | + return gesture_id == geis_frame_id(frame); |
270 | + } |
271 | + } |
272 | + } |
273 | + return GEIS_FALSE; |
274 | +} |
275 | + |
276 | + |
277 | +/* |
278 | + * Asks grail to reject an identified gesture. |
279 | + */ |
280 | +GeisStatus |
281 | +_grail_be_reject_gesture(GeisBackend be, |
282 | + GeisGroup group GEIS_UNUSED, |
283 | + GeisGestureId gesture_id) |
284 | +{ |
285 | + GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR; |
286 | + GeisGrailBackend gbe = (GeisGrailBackend)be; |
287 | + unsigned id = gesture_id; |
288 | + UGStatus ugstatus = grail_reject_gesture(gbe->grail, id); |
289 | + if (ugstatus != UGStatusSuccess) |
290 | + { |
291 | + geis_error("rejection failed for gesture %u", id); |
292 | + } |
293 | + else |
294 | + { |
295 | + geis_debug("gesture %u rejected", id); |
296 | + status = GEIS_STATUS_SUCCESS; |
297 | + } |
298 | + |
299 | + geis_remove_matching_events(gbe->geis, |
300 | + _grail_be_match_gesture_event, |
301 | + &gesture_id); |
302 | + return status; |
303 | +} |
304 | |
305 | static struct GeisBackendVtable gbe_vtbl = { |
306 | _geis_grail_backend_construct, |
307 | _geis_grail_backend_finalize, |
308 | - geis_grail_token_new |
309 | + geis_grail_token_new, |
310 | + _grail_be_accept_gesture, |
311 | + _grail_be_reject_gesture, |
312 | }; |
313 | |
314 | |
315 | @@ -1397,7 +1509,6 @@ |
316 | } |
317 | |
318 | UGStatus ugstatus = UGStatusErrorGeneric; |
319 | - |
320 | GeisBoolean geis_use_atomic_gestures = GEIS_FALSE; |
321 | geis_get_configuration(gbe->geis, |
322 | GEIS_CONFIG_ATOMIC_GESTURES, |
323 | @@ -1633,6 +1744,22 @@ |
324 | { |
325 | UGSubscription ugsub = geis_ugsubscription_get_ugsubscription_at(ugstore, |
326 | i); |
327 | + |
328 | + UFWindowId ufwindow; |
329 | + UGStatus ugstatus; |
330 | + ugstatus = grail_subscription_get_property(ugsub, |
331 | + UGSubscriptionPropertyWindow, |
332 | + &ufwindow); |
333 | + if (ugstatus != UGStatusSuccess) |
334 | + { |
335 | + geis_warning("error %d getting subscription window", ugstatus); |
336 | + } |
337 | + else |
338 | + { |
339 | + Window window_id = frame_x11_get_window_id(ufwindow); |
340 | + geis_grail_window_grab_store_ungrab(gbe->window_grabs, window_id); |
341 | + } |
342 | + |
343 | grail_subscription_deactivate(gbe->grail, ugsub); |
344 | } |
345 | } |
346 | |
347 | === modified file 'libutouch-geis/backend/grail/geis_grail_window_grab.c' |
348 | --- libutouch-geis/backend/grail/geis_grail_window_grab.c 2012-03-06 15:27:17 +0000 |
349 | +++ libutouch-geis/backend/grail/geis_grail_window_grab.c 2012-03-13 20:56:18 +0000 |
350 | @@ -185,7 +185,19 @@ |
351 | --grab->grab_count; |
352 | if (0 == grab->grab_count) |
353 | { |
354 | - /* @todo: ungrab */ |
355 | + XIGrabModifiers mods = { XIAnyModifier, 0 }; |
356 | + Status xstat = XIUngrabTouchBegin(wgs->display, |
357 | + XIAllMasterDevices, |
358 | + window_id, |
359 | + 1, &mods); |
360 | + if (xstat) |
361 | + { |
362 | + geis_error("error %d returned from XIUngrabTouchBegin()", xstat); |
363 | + } |
364 | + else if (mods.status != XIGrabSuccess) |
365 | + { |
366 | + geis_error("status %d returned from XIUnrabTouchBegin()", mods.status); |
367 | + } |
368 | } |
369 | } |
370 | } |
371 | |
372 | === modified file 'libutouch-geis/backend/test_fixture/geis_backend_test_fixture.c' |
373 | --- libutouch-geis/backend/test_fixture/geis_backend_test_fixture.c 2011-11-20 13:40:43 +0000 |
374 | +++ libutouch-geis/backend/test_fixture/geis_backend_test_fixture.c 2012-03-13 20:56:18 +0000 |
375 | @@ -228,10 +228,30 @@ |
376 | } |
377 | |
378 | |
379 | +GeisStatus |
380 | +_gmock_accept_gesture(GeisBackend be GEIS_UNUSED, |
381 | + GeisGroup group GEIS_UNUSED, |
382 | + GeisGestureId gesture_ID GEIS_UNUSED) |
383 | +{ |
384 | + return GEIS_STATUS_SUCCESS; |
385 | +} |
386 | + |
387 | + |
388 | +GeisStatus |
389 | +_gmock_reject_gesture(GeisBackend be GEIS_UNUSED, |
390 | + GeisGroup group GEIS_UNUSED, |
391 | + GeisGestureId gesture_ID GEIS_UNUSED) |
392 | +{ |
393 | + return GEIS_STATUS_SUCCESS; |
394 | +} |
395 | + |
396 | + |
397 | static struct GeisBackendVtable tf_vtbl = { |
398 | _construct, |
399 | _finalize, |
400 | _create_token, |
401 | + _gmock_accept_gesture, |
402 | + _gmock_reject_gesture |
403 | }; |
404 | |
405 | |
406 | |
407 | === modified file 'libutouch-geis/backend/xcb/geis_xcb_backend.c' |
408 | --- libutouch-geis/backend/xcb/geis_xcb_backend.c 2012-01-13 10:06:14 +0000 |
409 | +++ libutouch-geis/backend/xcb/geis_xcb_backend.c 2012-03-13 20:56:18 +0000 |
410 | @@ -105,13 +105,17 @@ |
411 | static void _construct(void *mem, Geis geis); |
412 | static void _finalize(GeisBackend g); |
413 | static GeisBackendToken _create_token(GeisBackend be, GeisBackendTokenInitState); |
414 | +static GeisStatus _gxcb_accept_gesture(GeisBackend, GeisGroup, GeisGestureId); |
415 | +static GeisStatus _gxcb_reject_gesture(GeisBackend, GeisGroup, GeisGestureId); |
416 | static void _fd_callback(int fd, GeisBackendMultiplexorActivity ev, void *ctx); |
417 | |
418 | |
419 | static struct GeisBackendVtable be_vtbl = { |
420 | _construct, |
421 | _finalize, |
422 | - _create_token |
423 | + _create_token, |
424 | + _gxcb_accept_gesture, |
425 | + _gxcb_reject_gesture |
426 | }; |
427 | |
428 | |
429 | @@ -1040,3 +1044,21 @@ |
430 | { |
431 | } |
432 | |
433 | + |
434 | +GeisStatus |
435 | +_gxcb_accept_gesture(GeisBackend be GEIS_UNUSED, |
436 | + GeisGroup group GEIS_UNUSED, |
437 | + GeisGestureId gesture_id GEIS_UNUSED) |
438 | +{ |
439 | + return GEIS_STATUS_UNKNOWN_ERROR; |
440 | +} |
441 | + |
442 | + |
443 | +GeisStatus |
444 | +_gxcb_reject_gesture(GeisBackend be GEIS_UNUSED, |
445 | + GeisGroup group GEIS_UNUSED, |
446 | + GeisGestureId gesture_id GEIS_UNUSED) |
447 | +{ |
448 | + return GEIS_STATUS_UNKNOWN_ERROR; |
449 | +} |
450 | + |
451 | |
452 | === modified file 'libutouch-geis/geis.c' |
453 | --- libutouch-geis/geis.c 2012-02-23 19:42:24 +0000 |
454 | +++ libutouch-geis/geis.c 2012-03-13 20:56:18 +0000 |
455 | @@ -950,6 +950,19 @@ |
456 | |
457 | |
458 | /* |
459 | + * Removes all matching events from all event queues. |
460 | + */ |
461 | +void |
462 | +geis_remove_matching_events(Geis geis, |
463 | + GeisEventMatch matching, |
464 | + void *context) |
465 | +{ |
466 | + geis_event_queue_remove_if(geis->input_event_queue, matching, context); |
467 | + geis_event_queue_remove_if(geis->output_event_queue, matching, context); |
468 | +} |
469 | + |
470 | + |
471 | +/* |
472 | * Registers an application-supplied event callback. |
473 | */ |
474 | void |
475 | @@ -1512,3 +1525,23 @@ |
476 | return device; |
477 | } |
478 | |
479 | + |
480 | +/* |
481 | + * Marks a gesture as accepted. |
482 | + */ |
483 | +GeisStatus |
484 | +geis_gesture_accept(Geis geis, GeisGroup group, GeisGestureId gesture_id) |
485 | +{ |
486 | + return geis_backend_gesture_accept(geis->backend, group, gesture_id); |
487 | +} |
488 | + |
489 | + |
490 | +/* |
491 | + * Marks a gesture as rejected. |
492 | + */ |
493 | +GeisStatus |
494 | +geis_gesture_reject(Geis geis, GeisGroup group, GeisGestureId gesture_id) |
495 | +{ |
496 | + return geis_backend_gesture_reject(geis->backend, group, gesture_id); |
497 | +} |
498 | + |
499 | |
500 | === modified file 'libutouch-geis/geis_backend.c' |
501 | --- libutouch-geis/geis_backend.c 2011-12-19 22:14:48 +0000 |
502 | +++ libutouch-geis/geis_backend.c 2012-03-13 20:56:18 +0000 |
503 | @@ -177,3 +177,25 @@ |
504 | } |
505 | |
506 | |
507 | +GeisStatus |
508 | +geis_backend_gesture_accept(GeisBackend be, |
509 | + GeisGroup group, |
510 | + GeisGestureId gesture_id) |
511 | +{ |
512 | + GeisStatus status = be->be_class->vtbl->accept_gesture(_data_from_be(be), |
513 | + group, |
514 | + gesture_id); |
515 | + return status; |
516 | +} |
517 | + |
518 | + |
519 | +GeisStatus |
520 | +geis_backend_gesture_reject(GeisBackend be, |
521 | + GeisGroup group, |
522 | + GeisGestureId gesture_id) |
523 | +{ |
524 | + GeisStatus status = be->be_class->vtbl->reject_gesture(_data_from_be(be), |
525 | + group, |
526 | + gesture_id); |
527 | + return status; |
528 | +} |
529 | |
530 | === modified file 'libutouch-geis/geis_backend.h' |
531 | --- libutouch-geis/geis_backend.h 2011-06-29 14:40:25 +0000 |
532 | +++ libutouch-geis/geis_backend.h 2012-03-13 20:56:18 +0000 |
533 | @@ -66,4 +66,28 @@ |
534 | GeisBackendToken geis_backend_create_token(GeisBackend be, |
535 | GeisBackendTokenInitState); |
536 | |
537 | +/** |
538 | + * Marks a gesture as accepted by the back end. |
539 | + * |
540 | + * @param[in] be The GEIS back end. |
541 | + * @param[in] group The gesture group containing the accepted gesture. |
542 | + * @param[in] gesture_id Identifies the gesture. |
543 | + */ |
544 | +GeisStatus |
545 | +geis_backend_gesture_accept(GeisBackend be, |
546 | + GeisGroup group, |
547 | + GeisGestureId gesture_id); |
548 | + |
549 | +/** |
550 | + * Marks a gesture as rejected by the back end. |
551 | + * |
552 | + * @param[in] be The GEIS back end. |
553 | + * @param[in] group The gesture group containing the rejected gesture. |
554 | + * @param[in] gesture_id Identifies the gesture. |
555 | + */ |
556 | +GeisStatus |
557 | +geis_backend_gesture_reject(GeisBackend be, |
558 | + GeisGroup group, |
559 | + GeisGestureId gesture_id); |
560 | + |
561 | #endif /* GEIS_BACKEND_H_ */ |
562 | |
563 | === modified file 'libutouch-geis/geis_backend_protected.h' |
564 | --- libutouch-geis/geis_backend_protected.h 2011-10-17 16:52:22 +0000 |
565 | +++ libutouch-geis/geis_backend_protected.h 2012-03-13 20:56:18 +0000 |
566 | @@ -38,6 +38,8 @@ |
567 | void (* construct)(void *mem, Geis geis); |
568 | void (* finalize)(GeisBackend); |
569 | GeisBackendToken (* create_token)(GeisBackend, GeisBackendTokenInitState); |
570 | + GeisStatus (* accept_gesture)(GeisBackend, GeisGroup, GeisGestureId); |
571 | + GeisStatus (* reject_gesture)(GeisBackend, GeisGroup, GeisGestureId); |
572 | } *GeisBackendVtable; |
573 | |
574 | |
575 | |
576 | === modified file 'libutouch-geis/geis_event_queue.c' |
577 | --- libutouch-geis/geis_event_queue.c 2011-02-05 13:49:54 +0000 |
578 | +++ libutouch-geis/geis_event_queue.c 2012-03-13 20:56:18 +0000 |
579 | @@ -1,8 +1,8 @@ |
580 | /** |
581 | * @file geis_event_queue.c |
582 | * @brief internal uTouch Geis event queue implementation |
583 | - * |
584 | - * Copyright 2010 Canonical Ltd. |
585 | + */ |
586 | +/* Copyright 2010, 2012 Canonical Ltd. |
587 | * |
588 | * This library is free software; you can redistribute it and/or modify it under |
589 | * the terms of the GNU Lesser General Public License as published by the Free |
590 | @@ -26,12 +26,19 @@ |
591 | |
592 | typedef struct _GeisEventQueueNode *GeisEventQueueNode; |
593 | |
594 | +/** |
595 | + * A node in a GEIS event queue. The event queue is a singly-linked list. |
596 | + */ |
597 | struct _GeisEventQueueNode |
598 | { |
599 | GeisEventQueueNode eq_next; |
600 | GeisEvent eq_event; |
601 | }; |
602 | |
603 | +/** |
604 | + * A GEIS event queue. The event queue is a singly linked list with a pool of |
605 | + * free nodes. |
606 | + */ |
607 | struct _GeisEventQueue |
608 | { |
609 | GeisEventQueueNode eq_front; |
610 | @@ -135,6 +142,18 @@ |
611 | |
612 | |
613 | /* |
614 | + * Pushes a node into the front of the free pool for a queue. |
615 | + */ |
616 | +static void |
617 | +_geis_event_queue_add_node_to_pool(GeisEventQueue queue, |
618 | + GeisEventQueueNode node) |
619 | +{ |
620 | + node->eq_next = queue->eq_pool; |
621 | + queue->eq_pool = node; |
622 | +} |
623 | + |
624 | + |
625 | +/* |
626 | * Pops the event off the front of the event queue. |
627 | */ |
628 | GeisEvent |
629 | @@ -147,11 +166,51 @@ |
630 | |
631 | GeisEventQueueNode node = queue->eq_front; |
632 | queue->eq_front = node->eq_next; |
633 | - node->eq_next = queue->eq_pool; |
634 | - queue->eq_pool = node; |
635 | + _geis_event_queue_add_node_to_pool(queue, node); |
636 | if (!queue->eq_front) |
637 | queue->eq_back = NULL; |
638 | } |
639 | return event; |
640 | } |
641 | |
642 | + |
643 | +/* |
644 | + * Removes events from a queue of they match a condition. |
645 | + */ |
646 | +void |
647 | +geis_event_queue_remove_if(GeisEventQueue queue, |
648 | + GeisEventMatch matching, |
649 | + void *context) |
650 | +{ |
651 | + GeisEventQueueNode prev = NULL; |
652 | + GeisEventQueueNode node = queue->eq_front; |
653 | + while (node) |
654 | + { |
655 | + if (matching(node->eq_event, context)) |
656 | + { |
657 | + GeisEventQueueNode matching_node = node; |
658 | + node = node->eq_next; |
659 | + |
660 | + if (matching_node == queue->eq_front) |
661 | + { |
662 | + queue->eq_front = matching_node->eq_next; |
663 | + } |
664 | + else |
665 | + { |
666 | + prev->eq_next = matching_node->eq_next; |
667 | + } |
668 | + if (matching_node == queue->eq_back) |
669 | + { |
670 | + queue->eq_back = prev; |
671 | + } |
672 | + geis_event_delete(matching_node->eq_event); |
673 | + _geis_event_queue_add_node_to_pool(queue, matching_node); |
674 | + } |
675 | + else |
676 | + { |
677 | + prev = node; |
678 | + node = node->eq_next; |
679 | + } |
680 | + } |
681 | +} |
682 | + |
683 | |
684 | === modified file 'libutouch-geis/geis_event_queue.h' |
685 | --- libutouch-geis/geis_event_queue.h 2010-12-14 17:11:24 +0000 |
686 | +++ libutouch-geis/geis_event_queue.h 2012-03-13 20:56:18 +0000 |
687 | @@ -83,4 +83,22 @@ |
688 | */ |
689 | GeisEvent geis_event_queue_dequeue(GeisEventQueue queue); |
690 | |
691 | +/** |
692 | + * Prototype for GEIS event matching predicate functions. |
693 | + */ |
694 | +typedef GeisBoolean (*GeisEventMatch)(GeisEvent event, void *context); |
695 | + |
696 | +/** |
697 | + * Removes events from a queue of they match a condition. |
698 | + * |
699 | + * @param[in] queue The event queue. |
700 | + * @param[in] matching A unary predicate function to indicate the events to be |
701 | + * removed. |
702 | + * @param[in] context An application-specific context value to be passed to |
703 | + * the matching function. |
704 | + */ |
705 | +void geis_event_queue_remove_if(GeisEventQueue queue, |
706 | + GeisEventMatch matching, |
707 | + void *context); |
708 | + |
709 | #endif /* GEIS_EVENT_QUEUE_H_ */ |
710 | |
711 | === modified file 'libutouch-geis/geis_frame.c' |
712 | --- libutouch-geis/geis_frame.c 2012-02-09 18:13:15 +0000 |
713 | +++ libutouch-geis/geis_frame.c 2012-03-13 20:56:18 +0000 |
714 | @@ -381,11 +381,3 @@ |
715 | } |
716 | |
717 | |
718 | -/* |
719 | - * Marks a gesture as rejected. |
720 | - */ |
721 | -void |
722 | -geis_gesture_reject(GeisGestureId gesture_id GEIS_UNUSED) |
723 | -{ |
724 | -} |
725 | - |
726 | |
727 | === modified file 'libutouch-geis/geis_private.h' |
728 | --- libutouch-geis/geis_private.h 2012-02-11 00:30:17 +0000 |
729 | +++ libutouch-geis/geis_private.h 2012-03-13 20:56:18 +0000 |
730 | @@ -34,6 +34,7 @@ |
731 | #include "geis_backend_multiplexor.h" |
732 | #include "geis_class.h" |
733 | #include "geis_device.h" |
734 | +#include "geis_event_queue.h" |
735 | #include "geis_filterable.h" |
736 | #include "geis_region.h" |
737 | #include "geis_subscription.h" |
738 | @@ -146,6 +147,24 @@ |
739 | void *context); |
740 | |
741 | /** |
742 | + * Removes all matching events from all event queues. |
743 | + * |
744 | + * @param[in] geis The API instance. |
745 | + * @param[in] matching A unary predicate function to indicate the events to be |
746 | + * removed. |
747 | + * @param[in] context An application-specific context value to be passed to |
748 | + * the matching function. |
749 | + * |
750 | + * Removes any and all queued events that are indicated by the passed matching |
751 | + * function. |
752 | + */ |
753 | +void geis_remove_matching_events(Geis geis, |
754 | + GeisEventMatch matching, |
755 | + void *context); |
756 | + |
757 | + |
758 | + |
759 | +/** |
760 | * @defgroup geis_v2_plugin Plugin Interfaces |
761 | * @ingroup geis_v2 |
762 | * Interfaces for plugin implementors. |
763 | |
764 | === modified file 'libutouch-geis/libutouch-geis.ver' |
765 | --- libutouch-geis/libutouch-geis.ver 2011-11-23 15:17:53 +0000 |
766 | +++ libutouch-geis/libutouch-geis.ver 2012-03-13 20:56:18 +0000 |
767 | @@ -49,6 +49,7 @@ |
768 | geis_frame_matrix; |
769 | geis_frame_touchid; |
770 | geis_frame_touchid_count; |
771 | + geis_gesture_accept; |
772 | geis_gesture_class_attr; |
773 | geis_gesture_class_attr_count; |
774 | geis_gesture_class_id; |
775 | |
776 | === modified file 'testsuite/geis2/Makefile.am' |
777 | --- testsuite/geis2/Makefile.am 2012-03-06 17:30:02 +0000 |
778 | +++ testsuite/geis2/Makefile.am 2012-03-13 20:56:18 +0000 |
779 | @@ -46,12 +46,15 @@ |
780 | gtest_attrs.cpp \ |
781 | gtest_subscriptions.cpp \ |
782 | gtest_evemu_device.h gtest_evemu_device.cpp \ |
783 | - gtest_geis_fixture.h gtest_geis_fixture.cpp |
784 | + gtest_geis_fixture.h gtest_geis_fixture.cpp |
785 | + |
786 | +nodist_gtest_geis2_api_SOURCES = /usr/src/gtest/src/gtest-all.cc |
787 | |
788 | gtest_geis2_api_CPPFLAGS = \ |
789 | --std=c++0x \ |
790 | -I$(top_srcdir) \ |
791 | -I$(top_srcdir)/include \ |
792 | + $(GTEST_CFLAGS) \ |
793 | $(EVEMU_CFLAGS) \ |
794 | $(XORG_GTEST_CFLAGS) |
795 | |
796 | |
797 | === modified file 'testsuite/geis2/gtest_subscriptions.cpp' |
798 | --- testsuite/geis2/gtest_subscriptions.cpp 2012-03-07 18:12:01 +0000 |
799 | +++ testsuite/geis2/gtest_subscriptions.cpp 2012-03-13 20:56:18 +0000 |
800 | @@ -6,10 +6,12 @@ |
801 | |
802 | #include "gtest_evemu_device.h" |
803 | #include "gtest_geis_fixture.h" |
804 | +#include <sys/select.h> |
805 | +#include <sys/time.h> |
806 | |
807 | |
808 | static const std::string TEST_DEVICE_PROP_FILE("touchscreen_a.prop"); |
809 | - |
810 | +static const std::string TEST_DEVICE_EVENTS_FILE("touchscreen_a_rotate90.events"); |
811 | |
812 | /** |
813 | * Tests need to make sure at least one multi-touch device is available. |
814 | @@ -22,7 +24,7 @@ |
815 | : evemu_device_(TEST_DEVICE_PROP_FILE) |
816 | { } |
817 | |
818 | -private: |
819 | +protected: |
820 | Testsuite::EvemuDevice evemu_device_; |
821 | }; |
822 | |
823 | @@ -67,8 +69,11 @@ |
824 | GEIS_GESTURE_ATTRIBUTE_TOUCHES, GEIS_FILTER_OP_GT, 1, |
825 | NULL); |
826 | EXPECT_EQ(fs, GEIS_STATUS_SUCCESS) << "can not add class to filter 1"; |
827 | + fs = geis_subscription_add_filter(sub1, filter1); |
828 | + EXPECT_EQ(fs, GEIS_STATUS_SUCCESS) << "can not subscribe filter 1"; |
829 | + geis_filter_delete(filter1); |
830 | |
831 | - GeisFilter filter2 = geis_filter_new(geis_, "root window 2"); |
832 | + GeisFilter filter2 = geis_filter_new(geis2, "root window 2"); |
833 | EXPECT_TRUE(filter2 != NULL) << "can not create filter 2"; |
834 | |
835 | fs = geis_filter_add_term(filter2, |
836 | @@ -77,11 +82,9 @@ |
837 | GEIS_GESTURE_ATTRIBUTE_TOUCHES, GEIS_FILTER_OP_GT, 1, |
838 | NULL); |
839 | EXPECT_EQ(fs, GEIS_STATUS_SUCCESS) << "can not add class to filter 2"; |
840 | - |
841 | - fs = geis_subscription_add_filter(sub1, filter1); |
842 | - EXPECT_EQ(fs, GEIS_STATUS_SUCCESS) << "can not subscribe filter 1"; |
843 | fs = geis_subscription_add_filter(sub2, filter2); |
844 | EXPECT_EQ(fs, GEIS_STATUS_SUCCESS) << "can not subscribe filter 2"; |
845 | + geis_filter_delete(filter2); |
846 | |
847 | EXPECT_EQ(GEIS_STATUS_SUCCESS, geis_subscription_activate(sub1)) |
848 | << "can not activate subscription 1"; |
849 | @@ -93,3 +96,258 @@ |
850 | geis_delete(geis2); |
851 | } |
852 | |
853 | +/** |
854 | + * Regression test 1 for lp:934207: gesture rejection |
855 | + */ |
856 | +TEST_F(GeisSubscriptionTests, reject_gesture) |
857 | +{ |
858 | + GeisGestureClass rotate_class = NULL; |
859 | + GeisGestureId rejected_gesture_id = 0; |
860 | + bool gesture_rejected = false; |
861 | + GeisSubscription sub = geis_subscription_new(geis_, |
862 | + "subscription", |
863 | + GEIS_SUBSCRIPTION_NONE); |
864 | + EXPECT_TRUE(sub != NULL) << "can not create subscription"; |
865 | + GeisFilter filter = geis_filter_new(geis_, "root window"); |
866 | + EXPECT_TRUE(filter != NULL) << "can not create filter"; |
867 | + GeisStatus fs = geis_filter_add_term(filter, |
868 | + GEIS_FILTER_CLASS, |
869 | + GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, GEIS_GESTURE_ROTATE, |
870 | + GEIS_GESTURE_ATTRIBUTE_TOUCHES, GEIS_FILTER_OP_GT, 1, |
871 | + NULL); |
872 | + EXPECT_EQ(fs, GEIS_STATUS_SUCCESS) << "can not add class to filter"; |
873 | + fs = geis_subscription_add_filter(sub, filter); |
874 | + EXPECT_EQ(fs, GEIS_STATUS_SUCCESS) << "can not subscribe filter"; |
875 | + geis_filter_delete(filter); |
876 | + EXPECT_EQ(GEIS_STATUS_SUCCESS, geis_subscription_activate(sub)) |
877 | + << "can not activate subscription"; |
878 | + |
879 | + GeisStatus dispatch_status= geis_dispatch_events(geis_); |
880 | + while (dispatch_status == GEIS_STATUS_CONTINUE |
881 | + || dispatch_status == GEIS_STATUS_SUCCESS) |
882 | + { |
883 | + GeisEvent event; |
884 | + GeisStatus event_status = geis_next_event(geis_, &event); |
885 | + while (event_status == GEIS_STATUS_CONTINUE |
886 | + || event_status == GEIS_STATUS_SUCCESS) |
887 | + { |
888 | + switch (geis_event_type(event)) |
889 | + { |
890 | + case GEIS_EVENT_INIT_COMPLETE: |
891 | + evemu_device_.play(TEST_DEVICE_EVENTS_FILE); |
892 | + break; |
893 | + |
894 | + case GEIS_EVENT_CLASS_AVAILABLE: |
895 | + { |
896 | + GeisAttr attr = geis_event_attr_by_name(event, |
897 | + GEIS_EVENT_ATTRIBUTE_CLASS); |
898 | + EXPECT_TRUE(attr != NULL) << "event is missing class attr"; |
899 | + GeisGestureClass gesture_class = (GeisGestureClass)geis_attr_value_to_pointer(attr); |
900 | + for (GeisSize i = 0; i < geis_gesture_class_attr_count(gesture_class); ++i) |
901 | + { |
902 | + GeisAttr attr2 = geis_gesture_class_attr(gesture_class, i); |
903 | + if (0 == strcmp(geis_attr_name(attr2), GEIS_CLASS_ATTRIBUTE_NAME)) |
904 | + { |
905 | + if (0 == strcmp(geis_attr_value_to_string(attr2), |
906 | + GEIS_GESTURE_ROTATE)) |
907 | + { |
908 | + rotate_class = gesture_class; |
909 | + } |
910 | + } |
911 | + } |
912 | + break; |
913 | + } |
914 | + |
915 | + case GEIS_EVENT_GESTURE_BEGIN: |
916 | + case GEIS_EVENT_GESTURE_UPDATE: |
917 | + { |
918 | + GeisAttr attr = geis_event_attr_by_name(event, |
919 | + GEIS_EVENT_ATTRIBUTE_GROUPSET); |
920 | + EXPECT_TRUE(attr != NULL) << "event is missing groupset attr"; |
921 | + GeisGroupSet groupset = (GeisGroupSet)geis_attr_value_to_pointer(attr); |
922 | + EXPECT_TRUE(groupset != NULL) << "event is missing groupset"; |
923 | + for (GeisSize i = 0; i < geis_groupset_group_count(groupset); ++i) |
924 | + { |
925 | + GeisGroup group = geis_groupset_group(groupset, i); |
926 | + EXPECT_TRUE(group != NULL) << "group " << i |
927 | + << " not found in groupset"; |
928 | + |
929 | + for (GeisSize j = 0; j < geis_group_frame_count(group); ++j) |
930 | + { |
931 | + GeisFrame frame = geis_group_frame(group, j); |
932 | + EXPECT_TRUE(frame != NULL) << "frame " << j |
933 | + << " not found in group"; |
934 | + |
935 | + if (geis_frame_is_class(frame, rotate_class)) |
936 | + { |
937 | + if (!gesture_rejected) |
938 | + { |
939 | + rejected_gesture_id = geis_frame_id(frame); |
940 | + GeisStatus gs = geis_gesture_reject(geis_, |
941 | + group, |
942 | + rejected_gesture_id); |
943 | + EXPECT_EQ(gs, GEIS_STATUS_SUCCESS) << "rejection failed"; |
944 | + gesture_rejected = true; |
945 | + } |
946 | + else |
947 | + { |
948 | + EXPECT_NE(geis_frame_id(frame), rejected_gesture_id) |
949 | + << "gesture events after gesture rejected"; |
950 | + } |
951 | + } |
952 | + } |
953 | + } |
954 | + break; |
955 | + } |
956 | + |
957 | + default: |
958 | + break; |
959 | + } |
960 | + |
961 | + geis_event_delete(event); |
962 | + |
963 | + event_status = geis_next_event(geis_, &event); |
964 | + } |
965 | + |
966 | + fd_set read_fds; |
967 | + FD_ZERO(&read_fds); |
968 | + FD_SET(geis_fd(), &read_fds); |
969 | + timeval tmo = { 5, 0 }; |
970 | + int sstat = select(geis_fd() + 1, &read_fds, NULL, NULL, &tmo); |
971 | + EXPECT_GT(sstat, -1) << "error in select"; |
972 | + if (sstat == 0) |
973 | + break; |
974 | + dispatch_status = geis_dispatch_events(geis_); |
975 | + } |
976 | + |
977 | + EXPECT_EQ(gesture_rejected, true) << "gesture was never rejected"; |
978 | + geis_subscription_delete(sub); |
979 | +} |
980 | + |
981 | + |
982 | +/** |
983 | + * Regression test 2 for lp:934207: gesture acceptance |
984 | + */ |
985 | +TEST_F(GeisSubscriptionTests, accept_gesture) |
986 | +{ |
987 | + GeisGestureClass rotate_class = NULL; |
988 | + bool gesture_accepted = false; |
989 | + bool gesture_ended = false; |
990 | + GeisSubscription sub = geis_subscription_new(geis_, |
991 | + "subscription", |
992 | + GEIS_SUBSCRIPTION_NONE); |
993 | + EXPECT_TRUE(sub != NULL) << "can not create subscription"; |
994 | + GeisFilter filter = geis_filter_new(geis_, "root window"); |
995 | + EXPECT_TRUE(filter != NULL) << "can not create filter"; |
996 | + GeisStatus fs = geis_filter_add_term(filter, |
997 | + GEIS_FILTER_CLASS, |
998 | + GEIS_CLASS_ATTRIBUTE_NAME, GEIS_FILTER_OP_EQ, GEIS_GESTURE_ROTATE, |
999 | + GEIS_GESTURE_ATTRIBUTE_TOUCHES, GEIS_FILTER_OP_GT, 1, |
1000 | + NULL); |
1001 | + EXPECT_EQ(fs, GEIS_STATUS_SUCCESS) << "can not add class to filter"; |
1002 | + fs = geis_subscription_add_filter(sub, filter); |
1003 | + EXPECT_EQ(fs, GEIS_STATUS_SUCCESS) << "can not subscribe filter"; |
1004 | + geis_filter_delete(filter); |
1005 | + EXPECT_EQ(GEIS_STATUS_SUCCESS, geis_subscription_activate(sub)) |
1006 | + << "can not activate subscription"; |
1007 | + |
1008 | + GeisStatus dispatch_status= geis_dispatch_events(geis_); |
1009 | + while (dispatch_status == GEIS_STATUS_CONTINUE |
1010 | + || dispatch_status == GEIS_STATUS_SUCCESS) |
1011 | + { |
1012 | + GeisEvent event; |
1013 | + GeisStatus event_status = geis_next_event(geis_, &event); |
1014 | + while (event_status == GEIS_STATUS_CONTINUE |
1015 | + || event_status == GEIS_STATUS_SUCCESS) |
1016 | + { |
1017 | + switch (geis_event_type(event)) |
1018 | + { |
1019 | + case GEIS_EVENT_INIT_COMPLETE: |
1020 | + evemu_device_.play(TEST_DEVICE_EVENTS_FILE); |
1021 | + break; |
1022 | + |
1023 | + case GEIS_EVENT_CLASS_AVAILABLE: |
1024 | + { |
1025 | + GeisAttr attr = geis_event_attr_by_name(event, |
1026 | + GEIS_EVENT_ATTRIBUTE_CLASS); |
1027 | + EXPECT_TRUE(attr != NULL) << "event is missing class attr"; |
1028 | + GeisGestureClass gesture_class = (GeisGestureClass)geis_attr_value_to_pointer(attr); |
1029 | + for (GeisSize i = 0; i < geis_gesture_class_attr_count(gesture_class); ++i) |
1030 | + { |
1031 | + GeisAttr attr2 = geis_gesture_class_attr(gesture_class, i); |
1032 | + if (0 == strcmp(geis_attr_name(attr2), GEIS_CLASS_ATTRIBUTE_NAME)) |
1033 | + { |
1034 | + if (0 == strcmp(geis_attr_value_to_string(attr2), |
1035 | + GEIS_GESTURE_ROTATE)) |
1036 | + { |
1037 | + rotate_class = gesture_class; |
1038 | + } |
1039 | + } |
1040 | + } |
1041 | + break; |
1042 | + } |
1043 | + |
1044 | + case GEIS_EVENT_GESTURE_BEGIN: |
1045 | + case GEIS_EVENT_GESTURE_UPDATE: |
1046 | + { |
1047 | + GeisAttr attr = geis_event_attr_by_name(event, |
1048 | + GEIS_EVENT_ATTRIBUTE_GROUPSET); |
1049 | + EXPECT_TRUE(attr != NULL) << "event is missing groupset attr"; |
1050 | + GeisGroupSet groupset = (GeisGroupSet)geis_attr_value_to_pointer(attr); |
1051 | + EXPECT_TRUE(groupset != NULL) << "event is missing groupset"; |
1052 | + for (GeisSize i = 0; i < geis_groupset_group_count(groupset); ++i) |
1053 | + { |
1054 | + GeisGroup group = geis_groupset_group(groupset, i); |
1055 | + EXPECT_TRUE(group != NULL) << "group " << i |
1056 | + << " not found in groupset"; |
1057 | + |
1058 | + for (GeisSize j = 0; j < geis_group_frame_count(group); ++j) |
1059 | + { |
1060 | + GeisFrame frame = geis_group_frame(group, j); |
1061 | + EXPECT_TRUE(frame != NULL) << "frame " << j |
1062 | + << " not found in group"; |
1063 | + |
1064 | + if (!gesture_accepted && geis_frame_is_class(frame, rotate_class)) |
1065 | + { |
1066 | + GeisStatus gs = geis_gesture_accept(geis_, |
1067 | + group, |
1068 | + geis_frame_id(frame)); |
1069 | + EXPECT_EQ(gs, GEIS_STATUS_SUCCESS) << "aceptance failed"; |
1070 | + gesture_accepted = true; |
1071 | + } |
1072 | + } |
1073 | + } |
1074 | + break; |
1075 | + } |
1076 | + |
1077 | + case GEIS_EVENT_GESTURE_END: |
1078 | + gesture_ended = true; |
1079 | + goto end_of_outer_loop; |
1080 | + break; |
1081 | + |
1082 | + default: |
1083 | + break; |
1084 | + } |
1085 | + |
1086 | + geis_event_delete(event); |
1087 | + |
1088 | + event_status = geis_next_event(geis_, &event); |
1089 | + } |
1090 | + |
1091 | + fd_set read_fds; |
1092 | + FD_ZERO(&read_fds); |
1093 | + FD_SET(geis_fd(), &read_fds); |
1094 | + timeval tmo = { 5, 0 }; |
1095 | + int sstat = select(geis_fd() + 1, &read_fds, NULL, NULL, &tmo); |
1096 | + EXPECT_GT(sstat, -1) << "error in select"; |
1097 | + if (sstat == 0) |
1098 | + break; |
1099 | + dispatch_status = geis_dispatch_events(geis_); |
1100 | + } |
1101 | +end_of_outer_loop: |
1102 | + |
1103 | + EXPECT_EQ(gesture_accepted, true) << "gesture was never accepted"; |
1104 | + EXPECT_EQ(gesture_ended, true) << "gesture did not end"; |
1105 | + geis_subscription_delete(sub); |
1106 | +} |
1107 | + |
1108 | |
1109 | === modified file 'testsuite/libutouch-geis/check_event_queue.c' |
1110 | --- testsuite/libutouch-geis/check_event_queue.c 2010-12-20 18:06:36 +0000 |
1111 | +++ testsuite/libutouch-geis/check_event_queue.c 2012-03-13 20:56:18 +0000 |
1112 | @@ -68,6 +68,42 @@ |
1113 | } |
1114 | END_TEST |
1115 | |
1116 | +/* verify event_queue remove_if */ |
1117 | +static GeisBoolean |
1118 | +_is_event_type(GeisEvent event, void* context) |
1119 | +{ |
1120 | + GeisEventType event_type = *(GeisEventType*)context; |
1121 | + return geis_event_type(event) == event_type; |
1122 | +} |
1123 | + |
1124 | +START_TEST(remove_if) |
1125 | +{ |
1126 | + GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR; |
1127 | + GeisEvent event1 = geis_event_new(GEIS_EVENT_GESTURE_BEGIN); |
1128 | + status = geis_event_queue_enqueue(g_queue, event1); |
1129 | + fail_unless(status == GEIS_STATUS_SUCCESS, "failure at enqueue(event1)"); |
1130 | + |
1131 | + GeisEvent event2 = geis_event_new(GEIS_EVENT_USER_DEFINED); |
1132 | + status = geis_event_queue_enqueue(g_queue, event2); |
1133 | + fail_unless(status == GEIS_STATUS_SUCCESS, "failure at enqueue(event2)"); |
1134 | + |
1135 | + GeisEvent event3 = geis_event_new(GEIS_EVENT_GESTURE_END); |
1136 | + status = geis_event_queue_enqueue(g_queue, event3); |
1137 | + fail_unless(status == GEIS_STATUS_SUCCESS, "failure at enqueue(event3)"); |
1138 | + |
1139 | + GeisEventType event_type = GEIS_EVENT_USER_DEFINED; |
1140 | + geis_event_queue_remove_if(g_queue, _is_event_type, &event_type); |
1141 | + |
1142 | + event_type = GEIS_EVENT_GESTURE_BEGIN; |
1143 | + geis_event_queue_remove_if(g_queue, _is_event_type, &event_type); |
1144 | + |
1145 | + event_type = GEIS_EVENT_GESTURE_END; |
1146 | + geis_event_queue_remove_if(g_queue, _is_event_type, &event_type); |
1147 | + |
1148 | + fail_unless(geis_event_queue_is_empty(g_queue), "queue is not empty"); |
1149 | +} |
1150 | +END_TEST |
1151 | + |
1152 | /* boilerplate */ |
1153 | Suite * |
1154 | make_event_queue_suite() |
1155 | @@ -81,6 +117,7 @@ |
1156 | TCase *usage = tcase_create("event-queue-operation"); |
1157 | tcase_add_checked_fixture(usage, construct_event_queue, destroy_event_queue); |
1158 | tcase_add_test(usage, enqueue_dequeue); |
1159 | + tcase_add_test(usage, remove_if); |
1160 | suite_add_tcase(s, usage); |
1161 | |
1162 | return s; |
1163 | |
1164 | === modified file 'testsuite/libutouch-geis/check_geis_private.c' |
1165 | --- testsuite/libutouch-geis/check_geis_private.c 2011-09-02 02:04:05 +0000 |
1166 | +++ testsuite/libutouch-geis/check_geis_private.c 2012-03-13 20:56:18 +0000 |
1167 | @@ -79,6 +79,53 @@ |
1168 | } |
1169 | END_TEST |
1170 | |
1171 | +/* Check selective queue removal. */ |
1172 | +static GeisBoolean |
1173 | +_is_event_type(GeisEvent event, void* context) |
1174 | +{ |
1175 | + GeisEventType event_type = *(GeisEventType*)context; |
1176 | + return geis_event_type(event) == event_type; |
1177 | +} |
1178 | + |
1179 | +START_TEST(remove_matching) |
1180 | +{ |
1181 | + GeisStatus status; |
1182 | + |
1183 | + /* empty the event queue */ |
1184 | + while (GEIS_STATUS_CONTINUE == geis_dispatch_events(g_geis)) |
1185 | + ; |
1186 | + GeisEvent event_out; |
1187 | + while (GEIS_STATUS_CONTINUE == geis_next_event(g_geis, &event_out)) |
1188 | + geis_event_delete(event_out); |
1189 | + |
1190 | + /* push 3 controlled events into the queue */ |
1191 | + GeisEvent event_in_1 = geis_event_new(GEIS_EVENT_GESTURE_BEGIN); |
1192 | + geis_post_event(g_geis, event_in_1); |
1193 | + GeisEvent event_in_2 = geis_event_new(GEIS_EVENT_USER_DEFINED); |
1194 | + geis_post_event(g_geis, event_in_2); |
1195 | + GeisEvent event_in_3 = geis_event_new(GEIS_EVENT_GESTURE_END); |
1196 | + geis_post_event(g_geis, event_in_3); |
1197 | + |
1198 | + /* remove the middle event */ |
1199 | + GeisEventType event_type = GEIS_EVENT_USER_DEFINED; |
1200 | + geis_remove_matching_events(g_geis, _is_event_type, &event_type); |
1201 | + |
1202 | + /* verify it's no longer in the queue */ |
1203 | + status = geis_dispatch_events(g_geis); |
1204 | + fail_unless(status == GEIS_STATUS_SUCCESS, |
1205 | + "unexpected status from geis_dispatch_events"); |
1206 | + for (status = geis_next_event(g_geis, &event_out); |
1207 | + status != GEIS_STATUS_EMPTY; |
1208 | + status = geis_next_event(g_geis, &event_out)) |
1209 | + { |
1210 | + fail_if(GEIS_EVENT_USER_DEFINED == geis_event_type(event_out), |
1211 | + "event was not successfully removed"); |
1212 | + geis_event_delete(event_out); |
1213 | + } |
1214 | + |
1215 | +} |
1216 | +END_TEST |
1217 | + |
1218 | START_TEST(multiplex_fd) |
1219 | { |
1220 | int pfd[2]; |
1221 | @@ -151,6 +198,7 @@ |
1222 | TCase *usage = tcase_create("backend-event-posting"); |
1223 | tcase_add_checked_fixture(usage, construct_geis, destroy_geis); |
1224 | tcase_add_test(usage, backend_post); |
1225 | + tcase_add_test(usage, remove_matching); |
1226 | tcase_add_test(usage, multiplex_fd); |
1227 | suite_add_tcase(s, usage); |
1228 |
* Typo:
geis_warning("error %d gettubg subscription window", ugstatus);
* Does geis have a queue of gesture events, or when you call geis_next_event(), does it only then go get an event from grail? If geis has a queue of grail events, reject needs to remove all matching gesture events from the geis queue.
To go along with this, I would like to see the reject test expanded so that it checks if any further gesture events are received for a rejected gesture.
* The accept test case should accept on the begin event, and check if an end event for the gesture is received. This will ensure that the gesture is actually accepted and not rejected.
* These tests don't check whether a gesture and its touches are really accepted or rejected. To do this, we need a test that has a subwindow that would receive the touch events if the gesture is rejected, and does not receive touch events if the gesture is accepted. I think this is getting into more testing than this specific functionality requires, but if we hit any bugs where geis accept/reject is not being propagated properly we will need to make these tests.