Merge lp:~oif-team/grail/trunk.touch into lp:grail

Proposed by Henrik Rydberg
Status: Superseded
Proposed branch: lp:~oif-team/grail/trunk.touch
Merge into: lp:grail
Diff against target: 474 lines (+199/-35)
12 files modified
include/grail-types.h (+28/-0)
src/Makefile.am (+1/-0)
src/gestures-drag.c (+4/-8)
src/gestures-pinch.c (+2/-6)
src/gestures-rotate.c (+2/-6)
src/gestures-touch.c (+94/-0)
src/grail-gestures.c (+6/-7)
src/grail-gestures.h (+4/-0)
src/grail-inserter.c (+51/-8)
src/grail-inserter.h (+3/-0)
src/grail-recognizer.c (+2/-0)
src/grail-recognizer.h (+2/-0)
To merge this branch: bzr merge lp:~oif-team/grail/trunk.touch
Reviewer Review Type Date Requested Status
Chase Douglas (community) Approve
Stephen M. Webb Pending
Review via email: mp+55215@code.launchpad.net

This proposal supersedes a proposal from 2011-03-26.

This proposal has been superseded by a proposal from 2011-03-28.

Description of the change

This patchset introduces gesture touch events.

To post a comment you must log in.
Revision history for this message
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal

I'm guessing the functionality is correct, but the header file is missing the TOUCH event attributes (just like there are separate DRAG, PINCH, ROTATE, etc. attributes).

review: Needs Fixing
Revision history for this message
Henrik Rydberg (rydberg) wrote : Posted in a previous version of this proposal

Seems like a mid-air collision - it seems they are present now.

Revision history for this message
Henrik Rydberg (rydberg) wrote : Posted in a previous version of this proposal

Removed a stale variable and fixed one whitespace error, looks all good to me now.

Revision history for this message
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal

In the grail-types.h file there's an old comment that should be removed:

+/* touch event types use drag properties */

I now seem unable to trigger any non-touch gestures when a touch gesture is performed, though...

review: Needs Fixing
Revision history for this message
Stephen M. Webb (bregma) wrote : Posted in a previous version of this proposal

The code looks OK stylistically and seems to work as I expected through geistest (once installed correctly). I do not have a problem with this.

review: Approve
Revision history for this message
Henrik Rydberg (rydberg) wrote :

There were some confusion as to what was a bug and what was expected behavior, but hopefully that is all straightened out now. This version seem to solve the known issues. Also see 744391 for another bugfix that goes on top of these.

Revision history for this message
Chase Douglas (chasedouglas) wrote :

Still has the touch types comment that should be removed :).

review: Needs Fixing
lp:~oif-team/grail/trunk.touch updated
133. By Henrik Rydberg

Introduce touch gesture events

Touch gesture events follow the same logic as drags, except they
cannot be held back but are emitted immediately.

Signed-off-by: Henrik Rydberg <email address hidden>

134. By Henrik Rydberg

Decouple timeout from discard

Move the actual gesture discard from the recognition phase
to the instantiation phase.

Signed-off-by: Henrik Rydberg <email address hidden>

135. By Henrik Rydberg

Do not timeout gestures overlapping touch gestures

The notion of listening to touch gestures implies that the
touches of those gestures never timeout. Hence, any pending
gesture that overlaps those touches should not timeout.

Signed-off-by: Henrik Rydberg <email address hidden>

136. By Henrik Rydberg

Never active gestures below activation threshold

Currently, all gestures activate after a certain time, such that
the smallest change result in gesture events. This was designed
to minimize disruption in pointer movement. Since grail no longer
handles pointers, the logic can be simplified to only activate when
the threshold is reached.

Signed-off-by: Henrik Rydberg <email address hidden>

137. By Henrik Rydberg

Do not treat single finger activation differently

Single-finger drags should no longer behave differently from
any other drag gesture. Fixed with this patch.

Signed-off-by: Henrik Rydberg <email address hidden>

138. By Henrik Rydberg

Do not hold back active gestures

Gestures that has once been sent should never be held back. The
current code would under some circumstance hold the gesture end
event and later discard it. This oneliner solves the problem, which
has been around since 241c5ec, Aug 2010. LP: #744391.

Signed-off-by: Henrik Rydberg <email address hidden>

Revision history for this message
Chase Douglas (chasedouglas) wrote :

All my comments have been addressed, and it appears to be working properly through gesturetest and geistest (with the new and improved utouch-geis :).

review: Approve

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/grail-types.h'
2--- include/grail-types.h 2010-08-19 20:36:11 +0000
3+++ include/grail-types.h 2011-03-28 20:03:33 +0000
4@@ -59,11 +59,20 @@
5
6 #define GRAIL_TYPE_SYSFLAG1 26 /* reserved system flag */
7
8+#define GRAIL_TYPE_TOUCH1 32 /* one-finger touch */
9+#define GRAIL_TYPE_TOUCH2 33 /* two-finger touch */
10+#define GRAIL_TYPE_TOUCH3 34 /* three-finger touch */
11+#define GRAIL_TYPE_TOUCH4 35 /* four-finger touch */
12+#define GRAIL_TYPE_TOUCH5 36 /* five-finger touch */
13+#define GRAIL_TYPE_ETOUCH 37 /* three-finger environment touch */
14+#define GRAIL_TYPE_MTOUCH 38 /* four-finger meta touch */
15+
16 #define GRAIL_MAIN_DRAG 0
17 #define GRAIL_MAIN_PINCH 1
18 #define GRAIL_MAIN_ROTATE 2
19 #define GRAIL_MAIN_TAP 3
20 #define GRAIL_MAIN_SYSFLAG 4
21+#define GRAIL_MAIN_TOUCH 5
22
23 #define GRAIL_PROP_DRAG_DX 0 /* horizontal position delta */
24 #define GRAIL_PROP_DRAG_DY 1 /* vertical position delta */
25@@ -160,5 +169,24 @@
26 #define GRAIL_PROP_TAP_X_T4 20
27 #define GRAIL_PROP_TAP_Y_T4 21
28
29+#define GRAIL_PROP_TOUCH_X1 0 /* bounding box x1 */
30+#define GRAIL_PROP_TOUCH_Y1 1 /* bounding box y1 */
31+#define GRAIL_PROP_TOUCH_X2 2 /* bounding box x2 */
32+#define GRAIL_PROP_TOUCH_Y2 3 /* bounding box y2 */
33+#define GRAIL_PROP_TOUCH_ID_T0 4 /* first touch id */
34+#define GRAIL_PROP_TOUCH_X_T0 5 /* first touch horizontal position */
35+#define GRAIL_PROP_TOUCH_Y_T0 6 /* first touch vertical position */
36+#define GRAIL_PROP_TOUCH_ID_T1 7
37+#define GRAIL_PROP_TOUCH_X_T1 8
38+#define GRAIL_PROP_TOUCH_Y_T1 9
39+#define GRAIL_PROP_TOUCH_ID_T2 10
40+#define GRAIL_PROP_TOUCH_X_T2 11
41+#define GRAIL_PROP_TOUCH_Y_T2 12
42+#define GRAIL_PROP_TOUCH_ID_T3 13
43+#define GRAIL_PROP_TOUCH_X_T3 14
44+#define GRAIL_PROP_TOUCH_Y_T3 15
45+#define GRAIL_PROP_TOUCH_ID_T4 16
46+#define GRAIL_PROP_TOUCH_X_T4 17
47+#define GRAIL_PROP_TOUCH_Y_T4 18
48
49 #endif
50
51=== modified file 'src/Makefile.am'
52--- src/Makefile.am 2011-01-02 12:08:42 +0000
53+++ src/Makefile.am 2011-03-28 20:03:33 +0000
54@@ -17,6 +17,7 @@
55 grail-inserter.h \
56 grail-gestures.c \
57 grail-gestures.h \
58+ gestures-touch.c \
59 gestures-drag.c \
60 gestures-pinch.c \
61 gestures-rotate.c \
62
63=== modified file 'src/gestures-drag.c'
64--- src/gestures-drag.c 2011-03-17 09:48:13 +0000
65+++ src/gestures-drag.c 2011-03-28 20:03:33 +0000
66@@ -70,10 +70,8 @@
67 }
68 if ((move->timeout & fm_mask) == fm_mask) {
69 if (state->active) {
70- gin_gid_discard(ge, state->gid);
71- state->active = 0;
72+ gin_gid_timeout(ge, state->gid);
73 }
74- return 0;
75 }
76 if (!state->active) {
77 int type = getype[move->ntouch];
78@@ -84,7 +82,7 @@
79 }
80 if (!(move->tickle & mask))
81 return 0;
82- if (!move->single && !(move->active & fm_mask))
83+ if (!(move->active & fm_mask))
84 return 0;
85 set_props(ge->gin, state, move, frame);
86 gru_event(ge, state->gid, move, state->prop, state->nprop);
87@@ -107,10 +105,8 @@
88 }
89 if ((move->timeout & fm_mask) == fm_mask) {
90 if (state->active) {
91- gin_gid_discard(ge, state->gid);
92- state->active = 0;
93+ gin_gid_timeout(ge, state->gid);
94 }
95- return 0;
96 }
97 if (!state->active) {
98 if (move->ntouch == 4) {
99@@ -131,7 +127,7 @@
100 }
101 if (!(move->tickle & mask))
102 return 0;
103- if (!move->single && !(move->active & fm_mask))
104+ if (!(move->active & fm_mask))
105 return 0;
106 set_props(ge->gin, state, move, frame);
107 gru_event(ge, state->gid, move, state->prop, state->nprop);
108
109=== modified file 'src/gestures-pinch.c'
110--- src/gestures-pinch.c 2011-03-17 09:48:13 +0000
111+++ src/gestures-pinch.c 2011-03-28 20:03:33 +0000
112@@ -64,10 +64,8 @@
113 }
114 if ((move->timeout & fm_mask) == fm_mask) {
115 if (state->active) {
116- gin_gid_discard(ge, state->gid);
117- state->active = 0;
118+ gin_gid_timeout(ge, state->gid);
119 }
120- return 0;
121 }
122 if (!(move->tickle & mask))
123 return 0;
124@@ -102,10 +100,8 @@
125 }
126 if ((move->timeout & fm_mask) == fm_mask) {
127 if (state->active) {
128- gin_gid_discard(ge, state->gid);
129- state->active = 0;
130+ gin_gid_timeout(ge, state->gid);
131 }
132- return 0;
133 }
134 if (!(move->tickle & mask))
135 return 0;
136
137=== modified file 'src/gestures-rotate.c'
138--- src/gestures-rotate.c 2011-02-24 22:51:33 +0000
139+++ src/gestures-rotate.c 2011-03-28 20:03:33 +0000
140@@ -63,10 +63,8 @@
141 }
142 if ((move->timeout & fm_mask) == fm_mask) {
143 if (state->active) {
144- gin_gid_discard(ge, state->gid);
145- state->active = 0;
146+ gin_gid_timeout(ge, state->gid);
147 }
148- return 0;
149 }
150 if (!(move->tickle & mask))
151 return 0;
152@@ -101,10 +99,8 @@
153 }
154 if ((move->timeout & fm_mask) == fm_mask) {
155 if (state->active) {
156- gin_gid_discard(ge, state->gid);
157- state->active = 0;
158+ gin_gid_timeout(ge, state->gid);
159 }
160- return 0;
161 }
162 if (!(move->tickle & mask))
163 return 0;
164
165=== added file 'src/gestures-touch.c'
166--- src/gestures-touch.c 1970-01-01 00:00:00 +0000
167+++ src/gestures-touch.c 2011-03-28 20:03:33 +0000
168@@ -0,0 +1,94 @@
169+/*****************************************************************************
170+ *
171+ * grail - Gesture Recognition And Instantiation Library
172+ *
173+ * Copyright (C) 2010 Canonical Ltd.
174+ * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
175+ *
176+ * This program is free software: you can redistribute it and/or modify it
177+ * under the terms of the GNU General Public License as published by the
178+ * Free Software Foundation, either version 3 of the License, or (at your
179+ * option) any later version.
180+ *
181+ * This program is distributed in the hope that it will be useful, but
182+ * WITHOUT ANY WARRANTY; without even the implied warranty of
183+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
184+ * General Public License for more details.
185+ *
186+ * You should have received a copy of the GNU General Public License along
187+ * with this program. If not, see <http://www.gnu.org/licenses/>.
188+ *
189+ ****************************************************************************/
190+
191+#include "grail-recognizer.h"
192+#include <math.h>
193+#include <stdio.h>
194+
195+static const int getype[DIM_TOUCH + 1] = {
196+ -1,
197+ GRAIL_TYPE_TOUCH1,
198+ GRAIL_TYPE_TOUCH2,
199+ GRAIL_TYPE_TOUCH3,
200+ GRAIL_TYPE_TOUCH4,
201+ GRAIL_TYPE_TOUCH5,
202+};
203+
204+int gru_touch(struct grail *ge,
205+ const struct utouch_frame *frame)
206+{
207+ struct gesture_recognizer *gru = ge->gru;
208+ struct combo_model *state = &gru->touch;
209+ struct move_model *move = &gru->move;
210+ if (frame->slot_revision != frame->prev->slot_revision) {
211+ if (state->active) {
212+ gru_end(ge, state->gid, move,
213+ state->prop, state->nprop);
214+ state->active = 0;
215+ }
216+ }
217+ if (!state->active) {
218+ int type = getype[move->ntouch];
219+ if (type <= 0)
220+ return 0;
221+ state->gid = gin_gid_begin(ge, type, -PRIO_GESTURE, frame);
222+ state->active = 1;
223+ }
224+ state->nprop = gin_add_contact_props(ge->gin, state->prop, frame);
225+ gru_event(ge, state->gid, move, state->prop, state->nprop);
226+ return 1;
227+}
228+
229+int gru_wintouch(struct grail *ge,
230+ const struct utouch_frame *frame)
231+{
232+ struct gesture_recognizer *gru = ge->gru;
233+ struct combo_model *state = &gru->wintouch;
234+ struct move_model *move = &gru->move;
235+ if (frame->slot_revision != frame->prev->slot_revision) {
236+ if (state->active && out_of_bounds(state, move)) {
237+ gru_end(ge, state->gid, move,
238+ state->prop, state->nprop);
239+ state->active = 0;
240+ }
241+ }
242+ if (!state->active) {
243+ if (move->ntouch == 4) {
244+ state->gid = gin_gid_begin(ge, GRAIL_TYPE_MTOUCH,
245+ -PRIO_META, frame);
246+ state->mintouch = 1;
247+ state->maxtouch = 4;
248+ state->active = 1;
249+ } else if (move->ntouch == 3) {
250+ state->gid = gin_gid_begin(ge, GRAIL_TYPE_ETOUCH,
251+ -PRIO_ENV, frame);
252+ state->mintouch = 1;
253+ state->maxtouch = 3;
254+ state->active = 1;
255+ } else {
256+ return 0;
257+ }
258+ }
259+ state->nprop = gin_add_contact_props(ge->gin, state->prop, frame);
260+ gru_event(ge, state->gid, move, state->prop, state->nprop);
261+ return 1;
262+}
263
264=== modified file 'src/grail-gestures.c'
265--- src/grail-gestures.c 2011-03-17 09:48:13 +0000
266+++ src/grail-gestures.c 2011-03-28 20:03:33 +0000
267@@ -133,15 +133,14 @@
268 m->tickle &= ~(1 << i);
269 if (m->active & (1 << i))
270 return;
271- fm->action_delta = x - fm->original;
272- if (t - fm->original_ms > fm->hold_ms &&
273- fabs(fm->action_delta) > fm->bar) {
274- m->active |= (1 << i);
275+ fm->action_delta = 0;
276+ if (fabs(x - fm->original) > fm->bar) {
277+ if (t - fm->original_ms > fm->hold_ms) {
278+ m->active |= (1 << i);
279+ fm->action_delta = x - fm->original;
280+ }
281 } else if (t - fm->original_ms > fm->bar_ms) {
282- m->active |= (1 << i);
283 m->timeout |= (1 << i);
284- } else {
285- fm->action_delta = 0;
286 }
287 }
288
289
290=== modified file 'src/grail-gestures.h'
291--- src/grail-gestures.h 2011-02-24 22:51:17 +0000
292+++ src/grail-gestures.h 2011-03-28 20:03:33 +0000
293@@ -77,6 +77,8 @@
294 grail_prop_t prop[DIM_GRAIL_PROP];
295 };
296
297+int gru_touch(struct grail *ge,
298+ const struct utouch_frame *frame);
299 int gru_drag(struct grail *ge,
300 const struct utouch_frame *frame);
301 int gru_pinch(struct grail *ge,
302@@ -90,6 +92,8 @@
303 return m->ntouch < s->mintouch || m->ntouch > s->maxtouch;
304 }
305
306+int gru_wintouch(struct grail *ge,
307+ const struct utouch_frame *frame);
308 int gru_windrag(struct grail *ge,
309 const struct utouch_frame *frame);
310 int gru_winpinch(struct grail *ge,
311
312=== modified file 'src/grail-inserter.c'
313--- src/grail-inserter.c 2011-03-17 09:48:13 +0000
314+++ src/grail-inserter.c 2011-03-28 20:03:33 +0000
315@@ -38,6 +38,18 @@
316 return -1;
317 }
318
319+static int mask_overlap(const grail_mask_t *a, const grail_mask_t *b,
320+ int bytes)
321+{
322+ int i;
323+
324+ for (i = 0; i < bytes; i++)
325+ if (a[i] & b[i])
326+ return 1;
327+
328+ return 0;
329+}
330+
331 // todo: spanning tree for multi-user case
332 static void setup_new_gestures(struct grail *ge,
333 const struct utouch_frame *frame)
334@@ -114,33 +126,50 @@
335 void gin_frame_end(struct grail *ge, const struct utouch_frame *frame)
336 {
337 struct gesture_inserter *gin = ge->gin;
338- int i, hold = 0, discard = 0;
339+ grail_mask_t keep[DIM_TOUCH_BYTES];
340+ int i, hold[2] = { 0, 0 }, discard[2] = { 0, 0 };
341
342+ memset(keep, 0, sizeof(keep));
343 setup_new_gestures(ge, frame);
344
345 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
346 struct slot_state *s = &gin->state[i];
347 if (!s->nclient)
348 continue;
349- if (s->priority > hold)
350- hold = s->priority;
351+ if (s->priority > hold[s->slice])
352+ hold[s->slice] = s->priority;
353 if (s->status != GRAIL_STATUS_UPDATE)
354 continue;
355- if (s->priority > discard)
356- discard = s->priority;
357+ if (s->priority > discard[s->slice])
358+ discard[s->slice] = s->priority;
359 }
360
361 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
362 struct slot_state *s = &gin->state[i];
363- if (!s->nclient || s->priority < discard)
364+ if (!s->nclient || s->priority < discard[s->slice])
365 gin_gid_discard(ge, s->id);
366 }
367
368 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
369 struct slot_state *s = &gin->state[i];
370+ if (s->slice == 1)
371+ grail_mask_set_mask(keep, s->span, sizeof(keep));
372+ }
373+
374+ grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
375+ struct slot_state *s = &gin->state[i];
376+ if (!s->timeout)
377+ continue;
378+ if (mask_overlap(keep, s->span, sizeof(keep)))
379+ continue;
380+ gin_gid_discard(ge, s->id);
381+ }
382+
383+ grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
384+ struct slot_state *s = &gin->state[i];
385 struct gesture_event ev;
386 grail_mask_set(gin->types, s->type);
387- if (s->priority < hold)
388+ if (s->priority < hold[s->slice])
389 continue;
390 while (!gebuf_empty(&s->buf)) {
391 gebuf_get(&s->buf, &ev);
392@@ -166,7 +195,14 @@
393 return -1;
394 s = &gin->state[i];
395 s->type = type;
396- s->priority = priority;
397+ if (priority < 0) {
398+ s->priority = -priority;
399+ s->slice = 1;
400+ } else {
401+ s->priority = priority;
402+ s->slice = 0;
403+ }
404+ s->timeout = 0;
405 s->id = gin->gestureid++ & MAX_GESTURE_ID;
406 s->status = GRAIL_STATUS_BEGIN;
407 s->nclient = 0;
408@@ -193,6 +229,13 @@
409 grail_mask_set(gin->unused, i);
410 }
411
412+void gin_gid_timeout(struct grail *ge, int gid)
413+{
414+ int i = find_gslot(ge->gin, gid);
415+ if (i >= 0)
416+ ge->gin->state[i].timeout = 1;
417+}
418+
419 void gin_gid_event(struct grail *ge, int gid,
420 float x, float y, int ntouch,
421 const grail_prop_t *prop, int nprop,
422
423=== modified file 'src/grail-inserter.h'
424--- src/grail-inserter.h 2011-03-17 09:48:13 +0000
425+++ src/grail-inserter.h 2011-03-28 20:03:33 +0000
426@@ -37,6 +37,8 @@
427 struct slot_state {
428 int type;
429 int priority;
430+ int slice;
431+ int timeout;
432 int id;
433 int status;
434 int nclient;
435@@ -78,6 +80,7 @@
436 int gin_gid_begin(struct grail *ge, int type, int priority,
437 const struct utouch_frame *frame);
438 void gin_gid_discard(struct grail *ge, int gid);
439+void gin_gid_timeout(struct grail *ge, int gid);
440
441 void gin_gid_event(struct grail *ge, int gid,
442 float x, float y, int ntouch,
443
444=== modified file 'src/grail-recognizer.c'
445--- src/grail-recognizer.c 2011-01-02 12:08:08 +0000
446+++ src/grail-recognizer.c 2011-03-28 20:03:33 +0000
447@@ -47,9 +47,11 @@
448 if (!ge->gin || !ge->gru)
449 return;
450 gru_motion(ge, frame);
451+ gru_touch(ge, frame);
452 gru_drag(ge, frame);
453 gru_pinch(ge, frame);
454 gru_rotate(ge, frame);
455+ gru_wintouch(ge, frame);
456 gru_windrag(ge, frame);
457 gru_winpinch(ge, frame);
458 gru_winrotate(ge, frame);
459
460=== modified file 'src/grail-recognizer.h'
461--- src/grail-recognizer.h 2011-02-24 22:49:22 +0000
462+++ src/grail-recognizer.h 2011-03-28 20:03:33 +0000
463@@ -27,9 +27,11 @@
464
465 struct gesture_recognizer {
466 struct move_model move;
467+ struct combo_model touch;
468 struct combo_model drag;
469 struct combo_model pinch;
470 struct combo_model rotate;
471+ struct combo_model wintouch;
472 struct combo_model windrag;
473 struct combo_model winpinch;
474 struct combo_model winrotate;

Subscribers

People subscribed via source and target branches

to all changes: