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: 425 lines (+176/-29)
12 files modified
include/grail-types.h (+9/-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 (+96/-0)
src/grail-gestures.c (+6/-7)
src/grail-gestures.h (+4/-0)
src/grail-inserter.c (+45/-2)
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) Needs Fixing
Review via email: mp+54924@code.launchpad.net

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

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 :

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
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>

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

Subscribers

People subscribed via source and target branches

to all changes: