Merge lp:~oif-team/grail/grail2 into lp:grail

Proposed by Henrik Rydberg
Status: Superseded
Proposed branch: lp:~oif-team/grail/grail2
Merge into: lp:grail
Diff against target: 2575 lines (+1969/-148)
36 files modified
AUTHORS (+1/-0)
configure.ac (+7/-0)
docs/gestures.txt (+18/-0)
docs/pivot.txt (+144/-0)
include/grail-bits.h (+1/-2)
include/grail-types.h (+1/-2)
include/grail.h (+247/-49)
src/Makefile.am (+4/-1)
src/evbuf.h (+16/-23)
src/gebuf.h (+1/-2)
src/gestures-drag.c (+1/-2)
src/gestures-pinch.c (+1/-2)
src/gestures-rotate.c (+1/-2)
src/gestures-tapping.c (+1/-2)
src/grail-api.c (+10/-7)
src/grail-bits.c (+1/-2)
src/grail-event.c (+1/-27)
src/grail-frame.c (+372/-0)
src/grail-gestures.c (+1/-2)
src/grail-gestures.h (+1/-2)
src/grail-impl.h (+40/-3)
src/grail-init.c (+240/-0)
src/grail-inserter.c (+1/-2)
src/grail-inserter.h (+1/-2)
src/grail-legacy.c (+65/-0)
src/grail-recognizer.c (+1/-2)
src/grail-recognizer.h (+1/-2)
src/grailbuf.h (+1/-2)
test/Makefile.am (+1/-0)
test/check-grail.c (+2/-0)
test/check-transform.c (+137/-0)
tools/Makefile.am (+12/-4)
tools/grail-gesture.c (+1/-4)
tools/grail-test-mtdev.c (+256/-0)
tools/grail-transform.c (+374/-0)
utouch-grail.sym.in (+6/-0)
To merge this branch: bzr merge lp:~oif-team/grail/grail2
Reviewer Review Type Date Requested Status
Open Input Framework Team Pending
Review via email: mp+55291@code.launchpad.net

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

Description of the change

Rebased grail2 starter kit, this could go in trunk now.

To post a comment you must log in.
lp:~oif-team/grail/grail2 updated
139. By Chase Douglas

Merge send-key-events branch for better semi-mt support.

140. By Henrik Rydberg

Do not discard a started gesture

Not all discarding code paths were taking the notion of a started
gesture into account. Specifically, switching to a gesture of higher
priority would leave the old gesture without a finish. Fixed with
this patch.

Note that timeout implies not sent, so all discarding code paths
are now covered.

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

141. By Henrik Rydberg

Glue touch gestures as well

All motion-activated gestures are held for a short (glue) time
to allow for direct transition to multi-finger gesture types.
The touch gestures were mistakenly implemented without this.
Fixed with this patch. LP: #748282

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

142. By Chase Douglas

Merge branch to remove the EWMA move filter

143. By Jussi Pakkanen

Merged visibility fixes.

144. By Jussi Pakkanen

Merged C++ header fix.

145. By Jussi Pakkanen

Merge Pkg-config fix.

146. By Henrik Rydberg

Fixup remaining C++ and public function declarations

The grail-bits.h file can be included on its own, so it needs
the same handling. To save files in public name space, move the
visibility declarations to grail-bits.h, and include it as a main
file from grail.h.

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

147. By Jussi Pakkanen

Merged Clang cleanups.

148. By Henrik Rydberg

Expose utouch-frame through grail API

Start a gentle API change by exposing utouch-frame through grail,
and deprecating the grail_contact struct. Old programs compile and
run fine. To only use the new api, compile with -DGRAIL_NO_LEGACY_API.

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

149. By Henrik Rydberg

Prepare for gesture frame additions

Rename internal variables and fix makefile to make room for new
targets.

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

150. By Henrik Rydberg

Introduce gesture frames

This patch extends the API with parallel new/delete functions,
aiming to eventually replace the open/close function. The new
functions give access to the grail gesture frames, containing
gestural transform information. This information is useful in its
own right, and will eventually replace the internal recognizer.

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

151. By Henrik Rydberg

Document the gesture frame logic

Add some notes on the math of the gesture frame computations.

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

152. By Henrik Rydberg

Add gesture transform unit tests

Start the gesture frame test suite with some basic coordinate
mapping tests.

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

153. By Henrik Rydberg

Introduce test-mtdev

A new tool (test-mtdev) is added, showing the usage of gesture frames.

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

154. By Henrik Rydberg

Introduce the grail transform tool

This tool tests the transform capabilities of grail. Similar to a
map application, one can use a single finger, two fingers, a whole
hand or two hands to move the rectangle around, scale and rotate it.

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

155. By Henrik Rydberg

Update copyright information

The license information was always right, but the copyright information
for this particular project was never quite right. Corrected with this
patch. No functional changes.

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=== added file 'AUTHORS'
2--- AUTHORS 1970-01-01 00:00:00 +0000
3+++ AUTHORS 2011-03-29 08:01:03 +0000
4@@ -0,0 +1,1 @@
5+Henrik Rydberg <rydberg@bitmath.org>
6
7=== modified file 'configure.ac'
8--- configure.ac 2011-03-17 09:47:52 +0000
9+++ configure.ac 2011-03-29 08:01:03 +0000
10@@ -26,6 +26,13 @@
11 PKG_CHECK_MODULES([EVEMU], [utouch-evemu >= 1.0.5])
12 PKG_CHECK_MODULES([FRAME], [utouch-frame >= 1.0])
13
14+AC_ARG_WITH([xi], AS_HELP_STRING([--with-xi], [Build with XI2.1 support]))
15+AM_CONDITIONAL([HAVE_XI], [test "x$with_xi" != "x"])
16+
17+AS_IF([test "x$with_xi" = "xyes"], [
18+ PKG_CHECK_MODULES(XINPUT, x11 xext [xi >= 1.4.1.99.1] [inputproto >= 2.0.99.1])
19+ AC_DEFINE([HAVE_XI], [1], [XI2.1 support])
20+])
21 # Check for TDD tools
22 PKG_CHECK_MODULES([CHECK], [check >= 0.9.8],
23 [have_check=yes],
24
25=== added file 'docs/gestures.txt'
26--- docs/gestures.txt 1970-01-01 00:00:00 +0000
27+++ docs/gestures.txt 2011-03-29 08:01:03 +0000
28@@ -0,0 +1,18 @@
29+The gesture transformation from a multi-finger action is overstated and to
30+a certain extent arbitrary. This document describes how it is performed in
31+grail2.
32+
33+All two-finger transformations are extracted. These are all exact, in the
34+sense that continusouly transforming the original finger position, frame
35+per frame, will exactly follow the actual finger position.
36+
37+In addition to two-finger transformations, one global gesture is also
38+extracted. The rotation and scaling is taken from the pair with the longest
39+distance between contacts. This approximates the behavior of a region, such
40+that complex transformations could be happening inside the region, but at a
41+distance, the behavior should look like it was performed with two fingers.
42+
43+The pivot of the global gesture is extracted using least squares, using the
44+same principle as for contact pairs; the pivot is the point which, after
45+rotation and scaling, leaves the transformed contacts as close to the
46+actual positions as possible.
47
48=== added file 'docs/pivot.txt'
49--- docs/pivot.txt 1970-01-01 00:00:00 +0000
50+++ docs/pivot.txt 2011-03-29 08:01:03 +0000
51@@ -0,0 +1,144 @@
52+The pivot, p, is defined as the point, within the convex hull of the
53+contacts, which, after rotation and scaling, leaves the transformed
54+contacts as close to the actual positions as possible.
55+
56+Let r_i be the starting points and s_i the actual ending points in a
57+transformation. Let D be the scaling, and R the rotation. Then, minimizing
58+
59+L(p) = sum_i |D R (r_i - p) + p - s_i|^2 / N
60+
61+yields the pivot. Let
62+
63+rm = sum_i r_i / N,
64+p = rm + u,
65+q_i = s_i - rm - D R (r_i - rm),
66+
67+and we get
68+
69+L(p) = sum_i |(1 - D R) u - q_i|^2 / N.
70+
71+With
72+
73+L0 = sum_i norm2(q_i) / N,
74+T = (1 - D R)' (1 - D R),
75+m = sum_i q_i / N,
76+
77+we can write this as
78+
79+L(p) = L0 + u' T u - 2 m' (1 - D R) u.
80+
81+To handle the constraint, we can approximate the hull with a circle
82+centered at rm. If we pick the average radius, P, the constraint becomes
83+
84+|u| < P.
85+
86+Relaxing the expression (h >= 0) yields
87+
88+L(p, h) = L0 + u' T u - 2 m' (1 - D R) u + h (|u|^2 - P^2),
89+
90+leading to the linear equation
91+
92+(T + h) u = (1 - D R)' m.
93+
94+Further,
95+
96+sm = sum_i s_i / N,
97+m = sum_i (s_i - rm - D R (r_i - rm)) / N = sm - rm,
98+
99+thus m is the average displacement. In words, the pivot is the average
100+position plus a correction depending on the average displacement.
101+
102+*
103+
104+Some algebra solves the equation,
105+
106+D' = D,
107+[D, R] = 0,
108+R = S + C,
109+S' = -S,
110+C' = C,
111+R + R' = 2 C,
112+T = (1 - D R)' (1 - D R) = 1 + D^2 - 2 D C,
113+
114+which is a simple diagonal scaling operator. With
115+
116+a = 1 - D C,
117+b = D S,
118+
119+we can write this as
120+
121+T = (1 - DC)^2 + D^2(1 - C^2) = (1 - DC)^2 + D^2 S^2 = a^2 + b^2.
122+
123+Similarly, we can write
124+
125+(1 - D R)' = ((a, b), (-b, a)),
126+
127+and thusly,
128+
129+u = Q(h) m,
130+
131+with
132+
133+Q(h) = ((a, b), (-b, a)) / (a^2 + b^2 + h).
134+
135+When D R = 1, it follows that a^2 + b^2 = 0, and the relaxation ensures
136+that u is finite.
137+
138+*
139+
140+The drag is found by minimizing
141+
142+E(d) = sum_i | D R (r_i - p) + p + d - s_i |^2 / N,
143+E(d) = d^2 + 2 d' ((1 - D R) u - m) + E0,
144+
145+which leads to the linear equation
146+
147+d = m - (1 - D R) u.
148+
149+Explicitly,
150+
151+d = m - (a ux - b uy, a uy + b ux).
152+
153+Inserting the expression for u yields, after some algebra,
154+
155+d = m (1 - (a^2 + b^2) / (a^2 + b^2 + h)).
156+
157+When h = 0, d = 0, as expected.
158+
159+When a^2 + b^2 = 0, d = m, also as expected.
160+
161+For constrained cases, the drag is a fraction of the average displacement.
162+
163+*
164+
165+Time to look at measures for the relaxation parameter. Since d depends on
166+h, we can write the correction u(h) in terms of d instead. After som
167+algebra,
168+
169+|u(h)| = (|m| - |d|) / sqrt(a^2 + b^2).
170+
171+Conversely, d(h) can be written in terms of the constrained u(h) as
172+
173+d(h) = m (1 - sqrt(a^2 + b^2) |u(h)| / |m|).
174+
175+Since |u(0)| = |m| / sqrt(a^2 + b^2), we obtain
176+
177+d(h) = m (1 - |u(h)| / |u(0)|).
178+
179+*
180+
181+We can now write down an explicit recipe for determining the pivot (p) and
182+drag (d), given the transformation parameters a and b.
183+
184+w = (a mx + b my, a my - b mx).
185+
186+If |w| = 0, then u = 0. Consequently p = rm, d = m, and we are done. Else,
187+
188+u = w |m|^2 / |w|^2,
189+
190+t = P / |u|.
191+
192+If t >= 1, then p = rm + u, d = 0, and we are done. Else,
193+
194+p = rm + t u,
195+d = (1 - t) m.
196
197=== modified file 'include/grail-bits.h'
198--- include/grail-bits.h 2010-08-06 20:30:20 +0000
199+++ include/grail-bits.h 2011-03-29 08:01:03 +0000
200@@ -2,8 +2,7 @@
201 *
202 * grail - Gesture Recognition And Instantiation Library
203 *
204- * Copyright (C) 2010 Canonical Ltd.
205- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
206+ * Copyright (C) 2010-2011 Canonical Ltd.
207 *
208 * This program is free software: you can redistribute it and/or modify it
209 * under the terms of the GNU General Public License as published by the
210
211=== modified file 'include/grail-types.h'
212--- include/grail-types.h 2011-03-28 20:04:07 +0000
213+++ include/grail-types.h 2011-03-29 08:01:03 +0000
214@@ -2,8 +2,7 @@
215 *
216 * grail - Gesture Recognition And Instantiation Library
217 *
218- * Copyright (C) 2010 Canonical Ltd.
219- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
220+ * Copyright (C) 2010-2011 Canonical Ltd.
221 *
222 * This program is free software: you can redistribute it and/or modify it
223 * under the terms of the GNU General Public License as published by the
224
225=== modified file 'include/grail.h'
226--- include/grail.h 2010-08-19 20:35:45 +0000
227+++ include/grail.h 2011-03-29 08:01:03 +0000
228@@ -2,8 +2,7 @@
229 *
230 * grail - Gesture Recognition And Instantiation Library
231 *
232- * Copyright (C) 2010 Canonical Ltd.
233- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
234+ * Copyright (C) 2010-2011 Canonical Ltd.
235 *
236 * This program is free software: you can redistribute it and/or modify it
237 * under the terms of the GNU General Public License as published by the
238@@ -25,8 +24,11 @@
239
240 #include <grail-bits.h>
241 #include <grail-types.h>
242+#include <utouch/frame.h>
243 #include <linux/input.h>
244
245+#define GRAIL_VERSION 0x00011000
246+
247 #define DIM_GRAIL_TYPE 64
248 #define DIM_GRAIL_TYPE_BYTES ((DIM_GRAIL_TYPE + 7) >> 3)
249
250@@ -37,8 +39,28 @@
251 #define GRAIL_STATUS_UPDATE 1
252 #define GRAIL_STATUS_END 2
253
254-typedef float grail_prop_t; /* gesture properties */
255-typedef __u64 grail_time_t; /* time in milliseconds */
256+#define GRAIL_EXPECT_X 0x0001
257+#define GRAIL_EXPECT_Y 0x0002
258+#define GRAIL_EXPECT_SCALE 0x0004
259+#define GRAIL_EXPECT_ANGLE 0x0008
260+#define GRAIL_EXPECT_MASK 0x000f
261+
262+typedef float grail_prop_t; /* gesture properties */
263+typedef utouch_frame_time_t grail_time_t; /* time in milliseconds */
264+typedef struct grail *grail_handle; /* the grail instance handle */
265+
266+/**
267+ * struct grail_get_version - get grail library version
268+ *
269+ * Report the version of the grail library, which can be different from
270+ * the value of GRAIL_VERSION in this header file.
271+ *
272+ * This function allows for fallback options from major interface
273+ * extensions within the same ABI version. For the normal cases of ABI
274+ * agnostic or backwards incompatible changes, this function is not
275+ * needed.
276+ */
277+unsigned int grail_get_version(void);
278
279 /**
280 * struct grail_coord - coordinate in bounding box units
281@@ -49,32 +71,63 @@
282 float x, y;
283 };
284
285-/**
286- * struct grail_contact - MT event information in bounding box units
287- * @id: Contact tracking id
288- * @tool_type: Tool type (ABS_MT_TOOL_TYPE)
289- * @pos: Position of contact (bbox units)
290- * @touch_major: Major axis of contact shape (bbox units)
291- * @touch_minor: Minor axis of contact shape (bbox units)
292- * @width_major: Major axis of perimeter (bbox units)
293- * @width_minor: Minor axis of perimeter (bbox units)
294- * @angle: Angle of orientation (vertical: 0 horizontal: +-M_PI_2)
295- * @pressure: Pressure of contact (min: 0 max: 1)
296- *
297- * Depending on the native support of the underlying device, some or all of
298- * the listed properties may be computed.
299- */
300-struct grail_contact {
301- int id;
302- int tool_type;
303- struct grail_coord pos;
304- float touch_major;
305- float touch_minor;
306- float width_major;
307- float width_minor;
308- float angle;
309- float pressure;
310-};
311+grail_handle grail_new_raw(utouch_frame_handle fh,
312+ unsigned int num_frames,
313+ void *select,
314+ unsigned int version,
315+ unsigned int control_size,
316+ unsigned int frame_size,
317+ unsigned int slot_size);
318+
319+/**
320+ * grail_new - allocate and initialize a new grail instance
321+ * @fh: utouch frame handle to use
322+ * @num_frames: number of frames in cyclic buffer
323+ * @select: client selection callback
324+ *
325+ * Initialize the internal grail structures.
326+ *
327+ * Returns zero in case of failure.
328+ */
329+#define grail_new(fh, num_frames, select) \
330+ grail_new_raw(fh, num_frames, select, \
331+ GRAIL_VERSION, \
332+ sizeof(struct grail_control), \
333+ sizeof(struct grail_frame), \
334+ sizeof(struct grail_element))
335+
336+/**
337+ * grail_delete - destroy and delete grail instance
338+ * @ge: grail instance in use
339+ *
340+ * Deallocates all internal memory structures.
341+ */
342+void grail_delete(grail_handle ge);
343+
344+/**
345+ * grail_get_control - get mutable control structure
346+ * @ge: the grail device in use
347+ *
348+ * Return the control struct of the grail instance.
349+ *
350+ * The control pointer is ABI agnostic, owned by the grail instance, and
351+ * has grail scope.
352+ */
353+struct grail_control *grail_get_control(grail_handle ge);
354+
355+/**
356+ * grail_pump_frame - insert touch frames into grail
357+ * @ge: the grail device in use
358+ * @frame: the touch frame to insert
359+ *
360+ * Insert a new touch frame into the grail engine. If the frame induces a
361+ * new gesture frame, a pointer to the frame is returned.
362+ *
363+ * The grail frame pointer is ABI agnostic, owned by the grail instance, and
364+ * has grail scope.
365+ */
366+const struct grail_frame *grail_pump_frame(grail_handle ge,
367+ const struct utouch_frame *frame);
368
369 /**
370 * struct grail_client_id - Gesture client information
371@@ -102,6 +155,139 @@
372 };
373
374 /**
375+ * struct grail_control - control parameters of grail
376+ * @glue_ms: minimum time to hold activation (ms)
377+ * @thresh_drag: minimum moveness for drag
378+ * @thresh_scale: maximum moveness for rotate and scale
379+ * @bar_x: minimum horizontal distance to activate (surface width fraction)
380+ * @bar_y: minimum vertical distance to activate (surface height fraction)
381+ * @bar_scale: minimum scaling to activate (fraction)
382+ * @bar_angle: minimum angle to activate (radians)
383+ * @drop_x_ms: horizontal expect timeout (ms)
384+ * @drop_y_ms: vertical expect timeout (ms)
385+ * @drop_scale_ms: scaling expect timeout (ms)
386+ * @drop_angle_ms: rotation expect timeout (ms)
387+ *
388+ * The parameters are used to tune the behavior of the gesture recognition.
389+ *
390+ * The moveness is a number between zero and one denoting the
391+ * character of the current transform. Zero means pure rotate and
392+ * scale, one means pure drag.
393+ *
394+ * Later versions of this struct may grow in size, but will remain
395+ * binary compatible with older versions.
396+ */
397+struct grail_control {
398+ float glue_ms;
399+ float thresh_drag;
400+ float thresh_scale;
401+ float bar_x;
402+ float bar_y;
403+ float bar_scale;
404+ float bar_angle;
405+ float drop_x_ms;
406+ float drop_y_ms;
407+ float drop_scale_ms;
408+ float drop_angle_ms;
409+};
410+
411+/**
412+ * struct grail_frame - frame of ongoing elementary transformations
413+ * @prev: pointer to the previous gesture frame
414+ * @touch: pointer to the touch frame triggering this gesture frame
415+ * @num_ongoing: number of elements in the ongoing array
416+ * @ongoing: array of ongoing transformation elements
417+ * @slots: array of all transformation slots
418+ *
419+ * A gesture frame consists of one or several touch frames glued
420+ * together into a stable transition, combined with information on
421+ * ongoing elementary gestural transformations. The array of ongoing
422+ * elements contains all elements with a nonzero expect mask.
423+ *
424+ * Later versions of this struct may grow in size, but will remain
425+ * binary compatible with older versions.
426+ */
427+struct grail_frame {
428+ const struct grail_frame *prev;
429+ const struct utouch_frame *touch;
430+ unsigned int num_ongoing;
431+ struct grail_element **ongoing;
432+ struct grail_element **slots;
433+};
434+
435+/**
436+ * struct grail_element - elementary gesture transformation
437+ * @prev: respective element of previous frame
438+ * @slot: the transformation slot occupied by this element
439+ * @id: unique identifier of the ongoing transformation
440+ * @num_touches: number of contacts of this element
441+ * @touches: array of contacts of this element
442+ * @start_time: start time of this element
443+ * @expect_mask: bitmask of expected gestures (grail main types)
444+ * @active_mask: bitmask of activated gestures (grail main types)
445+ * @center: gesture center position (surface units)
446+ * @velocity: current center velocity (surface units per second)
447+ * @radius: gesture radius from center (surface units)
448+ * @transform: the transformation matrix of the gesture
449+ * @pivot: current center of rotate and scale (surface units)
450+ * @drag: accumulated transformation displacement (surface units)
451+ * @scale: accumulated scale (dimensionless)
452+ * @angle: accumulated rotation angle (radians)
453+ *
454+ * The grail element describes the ongoing gestural transformation of
455+ * a particular set of contacts. The expect mask describes which
456+ * gestural transformations may become active during the course of
457+ * events, and the active mask describes which have passed their
458+ * respective activation threshold. The set of expected gestures can
459+ * change over time, for instance by exclusion or timeout.
460+ *
461+ * Applications handling rotation, either by transformation matrix or
462+ * angle, should use the drag displacement. For other applications,
463+ * the center displacement may be used instead, as to not lose
464+ * movement accuracy.
465+ *
466+ * Later versions of this struct may grow in size, but will remain
467+ * binary compatible with older versions.
468+ */
469+struct grail_element {
470+ const struct grail_element *prev;
471+ int slot;
472+ int id;
473+ int num_touches;
474+ const struct utouch_contact **touches;
475+ grail_time_t start_time;
476+ unsigned int expect_mask;
477+ unsigned int active_mask;
478+ struct grail_coord center;
479+ struct grail_coord velocity;
480+ float radius2;
481+ float transform[6];
482+ float moveness;
483+ struct grail_coord pivot;
484+ struct grail_coord drag;
485+ float scale2;
486+ float angle;
487+};
488+
489+/**
490+ * grail_element_transform - transform coordinates using element
491+ * @slot: the transformation element to use
492+ * @q: the grail coordinate to fill
493+ * @x: the grail coordinate to transform
494+ *
495+ * Performs the 3x3 transform *q = T *p, where T is the element
496+ * transform.
497+ */
498+static inline void grail_element_transform(const struct grail_element *slot,
499+ struct grail_coord *q,
500+ const struct grail_coord *p)
501+{
502+ const float *T = slot->transform;
503+ q->x = T[0] * p->x + T[1] * p->y + T[2];
504+ q->y = T[3] * p->x + T[4] * p->y + T[5];
505+}
506+
507+/**
508 * struct grail_event - Gesture event
509 * @type: The gesture type
510 * @id: Unique identifier foof the gesture instance
511@@ -227,19 +413,6 @@
512 const struct grail_coord *max);
513
514 /**
515- * grail_filter_abs_events - filter kernel motion events
516- * @ge: the grail device in use
517- * @usage: When true, filter kernel motion events.
518- *
519- * Single-finger pointer events are treated as pointer gestures in
520- * grail. When filter_motion_events is non-zero, the kernel events
521- * corresponding to pointer movement are removed from the event
522- * stream.
523- *
524- */
525-void grail_filter_abs_events(struct grail *ge, int usage);
526-
527-/**
528 * grail_get_units - get device coordinate ranges
529 * @ge: the grail device in use
530 * @min: minimum x and y coordinates
531@@ -255,15 +428,40 @@
532 struct grail_coord *min, struct grail_coord *max);
533
534 /**
535- * grail_get_contacts - get current contact state
536+ * grail_get_contact_frame - get current contact frame
537 * @ge: the grail device in use
538- * @touch: array of contacts to be filled in
539- * @max_touch: maximum number of contacts supported by the array
540- *
541- * Extract the contact state as currently seen by grail.
542- *
543+ *
544+ * Return the contact frame current being processed. If called from
545+ * within a gesture callback, it is guaranteed to return the frame
546+ * corresponding to the gesture.
547+ *
548+ * The returned pointer can be NULL if no input has yet been extracted
549+ * through the grail instance.
550+ *
551+ * The frame pointer is ABI agnostic, owned by the grail instance, and
552+ * has grail scope.
553 */
554+const struct utouch_frame *grail_get_contact_frame(const struct grail *ge);
555+
556+#ifndef GRAIL_NO_LEGACY_API
557+
558+struct grail_contact {
559+ int id;
560+ int tool_type;
561+ struct grail_coord pos;
562+ float touch_major;
563+ float touch_minor;
564+ float width_major;
565+ float width_minor;
566+ float angle;
567+ float pressure;
568+};
569+
570+void grail_filter_abs_events(struct grail *ge, int usage);
571+
572 int grail_get_contacts(const struct grail *ge,
573 struct grail_contact *touch, int max_touch);
574
575 #endif
576+
577+#endif
578
579=== modified file 'src/Makefile.am'
580--- src/Makefile.am 2011-03-28 20:04:07 +0000
581+++ src/Makefile.am 2011-03-29 08:01:03 +0000
582@@ -26,7 +26,10 @@
583 grail-recognizer.h \
584 grail-event.c \
585 grail-impl.h \
586- grail-api.c
587+ grail-api.c \
588+ grail-legacy.c \
589+ grail-init.c \
590+ grail-frame.c
591
592 AM_CFLAGS = $(CWARNFLAGS)
593
594
595=== modified file 'src/evbuf.h'
596--- src/evbuf.h 2011-02-24 22:50:31 +0000
597+++ src/evbuf.h 2011-03-29 08:01:03 +0000
598@@ -1,28 +1,21 @@
599 /*****************************************************************************
600 *
601- * mtdev - Multitouch Protocol Translation Library (MIT license)
602- *
603- * Copyright (C) 2010 Canonical Ltd.
604- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
605- *
606- * Permission is hereby granted, free of charge, to any person obtaining a
607- * copy of this software and associated documentation files (the "Software"),
608- * to deal in the Software without restriction, including without limitation
609- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
610- * and/or sell copies of the Software, and to permit persons to whom the
611- * Software is furnished to do so, subject to the following conditions:
612- *
613- * The above copyright notice and this permission notice (including the next
614- * paragraph) shall be included in all copies or substantial portions of the
615- * Software.
616- *
617- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
618- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
619- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
620- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
621- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
622- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
623- * DEALINGS IN THE SOFTWARE.
624+ * grail - Gesture Recognition And Instantiation Library
625+ *
626+ * Copyright (C) 2010-2011 Canonical Ltd.
627+ *
628+ * This program is free software: you can redistribute it and/or modify it
629+ * under the terms of the GNU General Public License as published by the
630+ * Free Software Foundation, either version 3 of the License, or (at your
631+ * option) any later version.
632+ *
633+ * This program is distributed in the hope that it will be useful, but
634+ * WITHOUT ANY WARRANTY; without even the implied warranty of
635+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
636+ * General Public License for more details.
637+ *
638+ * You should have received a copy of the GNU General Public License along
639+ * with this program. If not, see <http://www.gnu.org/licenses/>.
640 *
641 ****************************************************************************/
642
643
644=== modified file 'src/gebuf.h'
645--- src/gebuf.h 2011-01-02 12:08:08 +0000
646+++ src/gebuf.h 2011-03-29 08:01:03 +0000
647@@ -2,8 +2,7 @@
648 *
649 * grail - Gesture Recognition And Instantiation Library
650 *
651- * Copyright (C) 2010 Canonical Ltd.
652- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
653+ * Copyright (C) 2010-2011 Canonical Ltd.
654 *
655 * This program is free software: you can redistribute it and/or modify it
656 * under the terms of the GNU General Public License as published by the
657
658=== modified file 'src/gestures-drag.c'
659--- src/gestures-drag.c 2011-03-28 20:04:18 +0000
660+++ src/gestures-drag.c 2011-03-29 08:01:03 +0000
661@@ -2,8 +2,7 @@
662 *
663 * grail - Gesture Recognition And Instantiation Library
664 *
665- * Copyright (C) 2010 Canonical Ltd.
666- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
667+ * Copyright (C) 2010-2011 Canonical Ltd.
668 *
669 * This program is free software: you can redistribute it and/or modify it
670 * under the terms of the GNU General Public License as published by the
671
672=== modified file 'src/gestures-pinch.c'
673--- src/gestures-pinch.c 2011-03-28 20:04:11 +0000
674+++ src/gestures-pinch.c 2011-03-29 08:01:03 +0000
675@@ -2,8 +2,7 @@
676 *
677 * grail - Gesture Recognition And Instantiation Library
678 *
679- * Copyright (C) 2010 Canonical Ltd.
680- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
681+ * Copyright (C) 2010-2011 Canonical Ltd.
682 *
683 * This program is free software: you can redistribute it and/or modify it
684 * under the terms of the GNU General Public License as published by the
685
686=== modified file 'src/gestures-rotate.c'
687--- src/gestures-rotate.c 2011-03-28 20:04:11 +0000
688+++ src/gestures-rotate.c 2011-03-29 08:01:03 +0000
689@@ -2,8 +2,7 @@
690 *
691 * grail - Gesture Recognition And Instantiation Library
692 *
693- * Copyright (C) 2010 Canonical Ltd.
694- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
695+ * Copyright (C) 2010-2011 Canonical Ltd.
696 *
697 * This program is free software: you can redistribute it and/or modify it
698 * under the terms of the GNU General Public License as published by the
699
700=== modified file 'src/gestures-tapping.c'
701--- src/gestures-tapping.c 2011-03-24 21:46:18 +0000
702+++ src/gestures-tapping.c 2011-03-29 08:01:03 +0000
703@@ -2,8 +2,7 @@
704 *
705 * grail - Gesture Recognition And Instantiation Library
706 *
707- * Copyright (C) 2010 Canonical Ltd.
708- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
709+ * Copyright (C) 2010-2011 Canonical Ltd.
710 *
711 * This program is free software: you can redistribute it and/or modify it
712 * under the terms of the GNU General Public License as published by the
713
714=== modified file 'src/grail-api.c'
715--- src/grail-api.c 2011-03-17 09:46:39 +0000
716+++ src/grail-api.c 2011-03-29 08:01:03 +0000
717@@ -2,8 +2,7 @@
718 *
719 * grail - Gesture Recognition And Instantiation Library
720 *
721- * Copyright (C) 2010 Canonical Ltd.
722- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
723+ * Copyright (C) 2010-2011 Canonical Ltd.
724 *
725 * This program is free software: you can redistribute it and/or modify it
726 * under the terms of the GNU General Public License as published by the
727@@ -20,9 +19,9 @@
728 *
729 ****************************************************************************/
730
731+#include "grail-impl.h"
732 #include "grail-inserter.h"
733 #include "grail-recognizer.h"
734-#include "grail-impl.h"
735 #include <string.h>
736 #include <stdio.h>
737 #include <unistd.h>
738@@ -34,10 +33,9 @@
739 #define DIM_FRAMES 100
740 #define FRAME_RATE 100
741
742-void grail_filter_abs_events(struct grail *ge, int usage)
743+unsigned int grail_get_version(void)
744 {
745- struct grail_impl *x = ge->impl;
746- x->filter_abs = usage;
747+ return GRAIL_VERSION;
748 }
749
750 int grail_open(struct grail *ge, int fd)
751@@ -151,6 +149,11 @@
752 max->y = s->max_y;
753 }
754
755+const struct utouch_frame *grail_get_contact_frame(const struct grail *ge)
756+{
757+ return ge->impl->touch;
758+}
759+
760 static void flush_events(struct grail *ge)
761 {
762 struct grail_impl *impl = ge->impl;
763@@ -226,7 +229,7 @@
764 struct grail_impl *impl = ge->impl;
765 struct grail_event gev;
766
767- ge->impl->frame = frame;
768+ ge->impl->touch = frame;
769
770 if (frame->num_active && !frame->prev->num_active) {
771 impl->ongoing = 1;
772
773=== modified file 'src/grail-bits.c'
774--- src/grail-bits.c 2010-08-06 20:30:20 +0000
775+++ src/grail-bits.c 2011-03-29 08:01:03 +0000
776@@ -2,8 +2,7 @@
777 *
778 * grail - Gesture Recognition And Instantiation Library
779 *
780- * Copyright (C) 2010 Canonical Ltd.
781- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
782+ * Copyright (C) 2010-2011 Canonical Ltd.
783 *
784 * This program is free software: you can redistribute it and/or modify it
785 * under the terms of the GNU General Public License as published by the
786
787=== modified file 'src/grail-event.c'
788--- src/grail-event.c 2011-03-17 09:48:13 +0000
789+++ src/grail-event.c 2011-03-29 08:01:03 +0000
790@@ -2,8 +2,7 @@
791 *
792 * grail - Gesture Recognition And Instantiation Library
793 *
794- * Copyright (C) 2010 Canonical Ltd.
795- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
796+ * Copyright (C) 2010-2011 Canonical Ltd.
797 *
798 * This program is free software: you can redistribute it and/or modify it
799 * under the terms of the GNU General Public License as published by the
800@@ -117,28 +116,3 @@
801 grailbuf_put(&impl->gbuf, &gev);
802 }
803 }
804-
805-int grail_get_contacts(const struct grail *ge,
806- struct grail_contact *touch, int max_touch)
807-{
808- const struct gesture_inserter *gin = ge->gin;
809- const struct utouch_frame *frame = ge->impl->frame;
810- int i;
811- if (frame->num_active < max_touch)
812- max_touch = frame->num_active;
813- for (i = 0; i < max_touch; i++) {
814- struct grail_contact *t = &touch[i];
815- const struct utouch_contact *ct = frame->active[i];
816- t->id = ct->id;
817- t->tool_type = ct->tool_type;
818- t->pos.x = ct->x;
819- t->pos.y = ct->y;
820- t->touch_major = ct->touch_major;
821- t->touch_minor = ct->touch_minor;
822- t->width_major = ct->width_major;
823- t->width_minor = ct->width_minor;
824- t->angle = ct->orientation;
825- t->pressure = ct->pressure;
826- }
827- return max_touch;
828-}
829
830=== added file 'src/grail-frame.c'
831--- src/grail-frame.c 1970-01-01 00:00:00 +0000
832+++ src/grail-frame.c 2011-03-29 08:01:03 +0000
833@@ -0,0 +1,372 @@
834+/*****************************************************************************
835+ *
836+ * grail - Gesture Recognition And Instantiation Library
837+ *
838+ * Copyright (C) 2010-2011 Canonical Ltd.
839+ *
840+ * This program is free software: you can redistribute it and/or modify it
841+ * under the terms of the GNU General Public License as published by the
842+ * Free Software Foundation, either version 3 of the License, or (at your
843+ * option) any later version.
844+ *
845+ * This program is distributed in the hope that it will be useful, but
846+ * WITHOUT ANY WARRANTY; without even the implied warranty of
847+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
848+ * General Public License for more details.
849+ *
850+ * You should have received a copy of the GNU General Public License along
851+ * with this program. If not, see <http://www.gnu.org/licenses/>.
852+ *
853+ ****************************************************************************/
854+
855+#include "grail-impl.h"
856+#include <stdlib.h>
857+#include <string.h>
858+#include <math.h>
859+
860+static void set_center_velocity_and_radius(struct grail_impl *impl,
861+ struct grail_element *slot)
862+{
863+ const struct utouch_contact **tc = slot->touches;
864+ double x, y, vx, vy, r2, dx, dy;
865+ int i;
866+
867+ switch (slot->num_touches) {
868+ case 1:
869+ x = tc[0]->x;
870+ y = tc[0]->y;
871+ vx = tc[0]->vx;
872+ vy = tc[0]->vy;
873+ r2 = 0;
874+ break;
875+ case 2:
876+ dx = 0.5 * (tc[1]->x - tc[0]->x);
877+ dy = 0.5 * (tc[1]->y - tc[0]->y);
878+ x = tc[0]->x + dx;
879+ y = tc[0]->y + dy;
880+ vx = 0.5 * (tc[0]->vx + tc[1]->vx);
881+ vy = 0.5 * (tc[0]->vy + tc[1]->vy);
882+ r2 = dx * dx + dy * dy;
883+ break;
884+ default:
885+ x = y = vx = vy = r2 = 0;
886+ for (i = 0; i < slot->num_touches; i++) {
887+ x += tc[i]->x;
888+ y += tc[i]->y;
889+ vx += tc[i]->vx;
890+ vy += tc[i]->vy;
891+ }
892+ x /= slot->num_touches;
893+ y /= slot->num_touches;
894+ vx /= slot->num_touches;
895+ vy /= slot->num_touches;
896+ for (i = 0; i < slot->num_touches; i++) {
897+ dx = tc[i]->x - x;
898+ dy = tc[i]->y - y;
899+ r2 += dx * dx + dy * dy;
900+ }
901+ r2 /= slot->num_touches;
902+ break;
903+ }
904+
905+ slot->center.x = x;
906+ slot->center.y = y;
907+ slot->velocity.x = 1000 * vx;
908+ slot->velocity.y = 1000 * vy;
909+ slot->radius2 = r2;
910+}
911+
912+static void set_moveness_pivot_and_drag(struct grail_impl *impl,
913+ struct grail_element *slot,
914+ double ds, double dc)
915+{
916+ const struct grail_element *pslot = slot->prev;
917+ double mx = slot->center.x - pslot->center.x;
918+ double my = slot->center.y - pslot->center.y;
919+ float *T = slot->transform;
920+
921+ slot->moveness = 1;
922+ slot->pivot = pslot->center;
923+
924+ if (slot->num_touches > 1) {
925+ double wx = (1 - dc) * mx + ds * my;
926+ double wy = (1 - dc) * my - ds * mx;
927+ double w2 = wx * wx + wy * wy;
928+ if (w2 > 0) {
929+ double s = sqrt(pslot->radius2 / w2);
930+ double q = (mx * mx + my * my) / w2;
931+ if (s < q) {
932+ slot->moveness = 1 - s / q;
933+ slot->pivot.x += s * wx;
934+ slot->pivot.y += s * wy;
935+ } else {
936+ slot->moveness = 0;
937+ slot->pivot.x += q * wx;
938+ slot->pivot.y += q * wy;
939+ }
940+ }
941+ }
942+
943+ mx *= slot->moveness;
944+ my *= slot->moveness;
945+
946+ T[0] = dc;
947+ T[1] = ds;
948+ T[2] = (1 - dc) * slot->pivot.x - ds * slot->pivot.y + mx;
949+ T[3] = -ds;
950+ T[4] = dc;
951+ T[5] = (1 - dc) * slot->pivot.y + ds * slot->pivot.x + my;
952+
953+ slot->drag.x = pslot->drag.x + mx;
954+ slot->drag.y = pslot->drag.y + my;
955+}
956+
957+static void start_slot(struct grail_impl *impl,
958+ struct grail_element *slot,
959+ const struct utouch_frame *touch)
960+{
961+ float *T = slot->transform;
962+
963+ slot->id = impl->seqid++ & GRAIL_ID_MAX;
964+ slot->expect_mask = GRAIL_EXPECT_MASK;
965+ slot->active_mask = 0;
966+ slot->start_time = touch->time;
967+ set_center_velocity_and_radius(impl, slot);
968+ T[0] = T[4] = 1;
969+ T[1] = T[2] = T[3] = T[5] = 0;
970+ slot->pivot = slot->center;
971+ slot->drag.x = 0;
972+ slot->drag.y = 0;
973+ slot->scale2 = 1;
974+ slot->angle = 0;
975+}
976+
977+static void update_slot(struct grail_impl *impl,
978+ struct grail_element *slot,
979+ double ds, double dc)
980+{
981+ const struct grail_element *pslot = slot->prev;
982+
983+ slot->id = pslot->id;
984+ slot->expect_mask = pslot->expect_mask;
985+ slot->active_mask = pslot->active_mask;
986+ slot->start_time = pslot->start_time;
987+
988+ set_center_velocity_and_radius(impl, slot);
989+ set_moveness_pivot_and_drag(impl, slot, ds, dc);
990+
991+ slot->scale2 = pslot->scale2 * (ds * ds + dc * dc);
992+ slot->angle = pslot->angle + ds / dc; /* atan2(ds, dc) */
993+}
994+
995+static void stop_slot(struct grail_impl *impl,
996+ struct grail_element *slot)
997+{
998+ slot->id = -1;
999+ slot->expect_mask = 0;
1000+ slot->num_touches = 0;
1001+}
1002+
1003+static void set_slot_one(struct grail_impl *impl,
1004+ struct grail_element *slot,
1005+ const struct utouch_frame *touch,
1006+ const struct utouch_contact *t1)
1007+{
1008+ const struct grail_element *pslot = slot->prev;
1009+ const struct utouch_contact *p1 = pslot->touches[0];
1010+
1011+ if (!t1->active) {
1012+ stop_slot(impl, slot);
1013+ return;
1014+ }
1015+
1016+ slot->touches[0] = t1;
1017+ slot->num_touches = 1;
1018+
1019+ if (pslot->num_touches != slot->num_touches || t1->id != p1->id) {
1020+ start_slot(impl, slot, touch);
1021+ return;
1022+ }
1023+
1024+ update_slot(impl, slot, 0, 1);
1025+}
1026+
1027+static void set_slot_two(struct grail_impl *impl,
1028+ struct grail_element *slot,
1029+ const struct utouch_frame *touch,
1030+ const struct utouch_contact *t1,
1031+ const struct utouch_contact *t2)
1032+{
1033+ const struct grail_element *pslot = slot->prev;
1034+ const struct utouch_contact *p1 = pslot->touches[0];
1035+ const struct utouch_contact *p2 = pslot->touches[1];
1036+ double tx, ty, px, py, d2;
1037+
1038+ if (!t1->active || !t2->active) {
1039+ stop_slot(impl, slot);
1040+ return;
1041+ }
1042+
1043+ slot->touches[0] = t1;
1044+ slot->touches[1] = t2;
1045+ slot->num_touches = 2;
1046+
1047+ if (pslot->num_touches != slot->num_touches ||
1048+ t1->id != p1->id || t2->id != p2->id) {
1049+ start_slot(impl, slot, touch);
1050+ return;
1051+ }
1052+
1053+ tx = t2->x - t1->x;
1054+ ty = t2->y - t1->y;
1055+ px = p2->x - p1->x;
1056+ py = p2->y - p1->y;
1057+
1058+ d2 = px * px + py * py;
1059+ if (d2 > 0) {
1060+ px /= d2;
1061+ py /= d2;
1062+ }
1063+
1064+ update_slot(impl, slot, tx * py - ty * px, tx * px + ty * py);
1065+}
1066+
1067+static void set_slot_multi(struct grail_impl *impl,
1068+ struct grail_element *slot,
1069+ struct grail_frame *frame,
1070+ const struct utouch_frame *touch)
1071+{
1072+ const struct grail_element *pslot = slot->prev;
1073+ struct grail_element **slots = frame->slots;
1074+ int i, j, n = impl->num_touches;
1075+ struct grail_element *best = 0;
1076+
1077+ if (touch->num_active < 3) {
1078+ stop_slot(impl, slot);
1079+ return;
1080+ }
1081+
1082+ memcpy(slot->touches, touch->active,
1083+ touch->num_active * sizeof(slot->touches[0]));
1084+ slot->num_touches = touch->num_active;
1085+
1086+ if (pslot->num_touches != slot->num_touches) {
1087+ start_slot(impl, slot, touch);
1088+ return;
1089+ }
1090+
1091+ for (i = 0; i < slot->num_touches; i++) {
1092+ if (slot->touches[i]->id != pslot->touches[i]->id) {
1093+ start_slot(impl, slot, touch);
1094+ return;
1095+ }
1096+ }
1097+
1098+ for (i = 0; i < impl->num_touches; i++) {
1099+ for (j = i + 1; j < impl->num_touches; j++) {
1100+ struct grail_element *s = slots[n++];
1101+ if (!s->num_touches)
1102+ continue;
1103+ if (!best || s->radius2 > best->radius2)
1104+ best = s;
1105+ }
1106+ }
1107+
1108+ update_slot(impl, slot, best->transform[1], best->transform[0]);
1109+}
1110+
1111+static void set_slots(struct grail_impl *impl,
1112+ struct grail_frame *frame,
1113+ const struct utouch_frame *touch)
1114+{
1115+ struct grail_element **slots = frame->slots;
1116+ struct utouch_contact *const *tc = touch->slots;
1117+ int i, j, n = 0;
1118+
1119+ for (i = 0; i < impl->num_touches; i++)
1120+ set_slot_one(impl, slots[n++], touch, tc[i]);
1121+
1122+ for (i = 0; i < impl->num_touches; i++)
1123+ for (j = i + 1; j < impl->num_touches; j++)
1124+ set_slot_two(impl, slots[n++], touch, tc[i], tc[j]);
1125+
1126+ set_slot_multi(impl, slots[n++], frame, touch);
1127+}
1128+
1129+static void collect_transforms(struct grail_impl *impl,
1130+ struct grail_frame *frame,
1131+ const struct utouch_frame *touch)
1132+{
1133+ const struct utouch_surface *s = utouch_frame_get_surface(impl->fh);
1134+ const struct grail_control *ctl = impl->ctl;
1135+ float dx = ctl->bar_x * (s->mapped_max_x - s->mapped_min_x);
1136+ float dy = ctl->bar_y * (s->mapped_max_y - s->mapped_min_y);
1137+ float ds2 = ctl->bar_scale * ctl->bar_scale;
1138+ float dt;
1139+ int i;
1140+
1141+ for (i = 0; i < impl->num_slots; i++) {
1142+ struct grail_element *s = frame->slots[i];
1143+
1144+ if (!s->expect_mask)
1145+ continue;
1146+
1147+ dt = touch->time - s->start_time;
1148+ if (dt > ctl->glue_ms) {
1149+
1150+ if (s->moveness > ctl->thresh_drag) {
1151+ if (fabs(s->drag.x) > dx)
1152+ s->active_mask |= GRAIL_EXPECT_X;
1153+ if (fabs(s->drag.y) > dy)
1154+ s->active_mask |= GRAIL_EXPECT_Y;
1155+ }
1156+ if (s->moveness < ctl->thresh_scale) {
1157+ if (fabs(s->scale2 - 1) > ds2)
1158+ s->active_mask |= GRAIL_EXPECT_SCALE;
1159+ if (fabs(s->angle) > ctl->bar_angle)
1160+ s->active_mask |= GRAIL_EXPECT_ANGLE;
1161+ }
1162+
1163+ s->active_mask &= s->expect_mask;
1164+
1165+ if (dt > ctl->drop_x_ms)
1166+ s->expect_mask &= ~GRAIL_EXPECT_X;
1167+ if (dt > ctl->drop_y_ms)
1168+ s->expect_mask &= ~GRAIL_EXPECT_Y;
1169+ if (dt > ctl->drop_scale_ms)
1170+ s->expect_mask &= ~GRAIL_EXPECT_SCALE;
1171+ if (dt > ctl->drop_angle_ms)
1172+ s->expect_mask &= ~GRAIL_EXPECT_ANGLE;
1173+
1174+ s->expect_mask |= s->active_mask;
1175+ }
1176+
1177+ if (s->expect_mask)
1178+ frame->ongoing[frame->num_ongoing++] = s;
1179+ }
1180+}
1181+
1182+const struct grail_frame *grail_pump_frame(grail_handle ge,
1183+ const struct utouch_frame *touch)
1184+{
1185+ struct grail_impl *impl = ge->impl;
1186+ struct grail_frame *frame = impl->frames[impl->nextframe];
1187+ const struct grail_frame *prev = frame->prev;
1188+ int i;
1189+
1190+ if (touch->slot_revision == touch->prev->slot_revision &&
1191+ !prev->num_ongoing)
1192+ return 0;
1193+
1194+ frame->touch = touch;
1195+ frame->num_ongoing = 0;
1196+ for (i = 0; i < impl->num_slots; i++)
1197+ frame->slots[i]->prev = prev->slots[i];
1198+
1199+ set_slots(impl, frame, touch);
1200+ collect_transforms(impl, frame, touch);
1201+
1202+ impl->nextframe = (impl->nextframe + 1) % impl->num_frames;
1203+
1204+ return frame;
1205+}
1206
1207=== modified file 'src/grail-gestures.c'
1208--- src/grail-gestures.c 2011-03-28 20:04:16 +0000
1209+++ src/grail-gestures.c 2011-03-29 08:01:03 +0000
1210@@ -2,8 +2,7 @@
1211 *
1212 * grail - Gesture Recognition And Instantiation Library
1213 *
1214- * Copyright (C) 2010 Canonical Ltd.
1215- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
1216+ * Copyright (C) 2010-2011 Canonical Ltd.
1217 *
1218 * This program is free software: you can redistribute it and/or modify it
1219 * under the terms of the GNU General Public License as published by the
1220
1221=== modified file 'src/grail-gestures.h'
1222--- src/grail-gestures.h 2011-03-28 20:04:07 +0000
1223+++ src/grail-gestures.h 2011-03-29 08:01:03 +0000
1224@@ -2,8 +2,7 @@
1225 *
1226 * grail - Gesture Recognition And Instantiation Library
1227 *
1228- * Copyright (C) 2010 Canonical Ltd.
1229- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
1230+ * Copyright (C) 2010-2011 Canonical Ltd.
1231 *
1232 * This program is free software: you can redistribute it and/or modify it
1233 * under the terms of the GNU General Public License as published by the
1234
1235=== modified file 'src/grail-impl.h'
1236--- src/grail-impl.h 2011-03-17 09:46:39 +0000
1237+++ src/grail-impl.h 2011-03-29 08:01:03 +0000
1238@@ -2,8 +2,7 @@
1239 *
1240 * grail - Gesture Recognition And Instantiation Library
1241 *
1242- * Copyright (C) 2010 Canonical Ltd.
1243- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
1244+ * Copyright (C) 2010-2011 Canonical Ltd.
1245 *
1246 * This program is free software: you can redistribute it and/or modify it
1247 * under the terms of the GNU General Public License as published by the
1248@@ -33,18 +32,56 @@
1249
1250 #define DIM_TOUCH 32
1251 #define DIM_TOUCH_BYTES ((DIM_TOUCH + 7) >> 3)
1252+#define GRAIL_ID_MAX 0xffff
1253+
1254+#define MIN(a, b) ((a) < (b) ? (a) : (b))
1255+#define MAX(a, b) ((a) > (b) ? (a) : (b))
1256+
1257+typedef void *grail_select_callback;
1258+
1259+/*
1260+ * In this implementation, there can be N one-gestures, N (N - 1) / 2
1261+ * two-gestures, and one global gesture.
1262+ */
1263+static inline int get_slot_count(int n)
1264+{
1265+ return n + n * (n - 1) / 2 + 1;
1266+}
1267+
1268+int create_grail2(struct grail_impl *x,
1269+ utouch_frame_handle fh,
1270+ unsigned int num_frames,
1271+ void *select,
1272+ unsigned int version,
1273+ unsigned int control_size,
1274+ unsigned int frame_size,
1275+ unsigned int slot_size);
1276+
1277+void destroy_grail2(struct grail_impl *x);
1278
1279 struct grail_impl {
1280 struct evemu_device *evemu;
1281 struct mtdev *mtdev;
1282 utouch_frame_handle fh;
1283- const struct utouch_frame *frame;
1284+ const struct utouch_frame *touch;
1285 struct evbuf evbuf;
1286 struct grailbuf gbuf;
1287 int filter_abs;
1288 int ongoing;
1289 int gesture;
1290 FILE *fptest;
1291+ /* new stuff below */
1292+ struct grail_control *ctl;
1293+ grail_select_callback select;
1294+ int num_frames;
1295+ int num_slots;
1296+ int num_touches;
1297+ int nextframe;
1298+ int seqid;
1299+ unsigned int control_size;
1300+ unsigned int frame_size;
1301+ unsigned int slot_size;
1302+ struct grail_frame **frames;
1303 };
1304
1305 #endif
1306
1307=== added file 'src/grail-init.c'
1308--- src/grail-init.c 1970-01-01 00:00:00 +0000
1309+++ src/grail-init.c 2011-03-29 08:01:03 +0000
1310@@ -0,0 +1,240 @@
1311+/*****************************************************************************
1312+ *
1313+ * grail - Gesture Recognition And Instantiation Library
1314+ *
1315+ * Copyright (C) 2010-2011 Canonical Ltd.
1316+ *
1317+ * This program is free software: you can redistribute it and/or modify it
1318+ * under the terms of the GNU General Public License as published by the
1319+ * Free Software Foundation, either version 3 of the License, or (at your
1320+ * option) any later version.
1321+ *
1322+ * This program is distributed in the hope that it will be useful, but
1323+ * WITHOUT ANY WARRANTY; without even the implied warranty of
1324+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1325+ * General Public License for more details.
1326+ *
1327+ * You should have received a copy of the GNU General Public License along
1328+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1329+ *
1330+ ****************************************************************************/
1331+
1332+#include "grail-impl.h"
1333+#include <stdlib.h>
1334+#include <string.h>
1335+#include <math.h>
1336+
1337+static struct grail_control *create_control(int size)
1338+{
1339+ struct grail_control *c = calloc(1, size);
1340+
1341+ if (!c)
1342+ return 0;
1343+
1344+ c->glue_ms = 60;
1345+ c->thresh_drag = 0.8;
1346+ c->thresh_scale = 0.2;
1347+ c->bar_x = 0.02;
1348+ c->bar_y = 0.02;
1349+ c->bar_scale = 0.3;
1350+ c->bar_angle = 0.1;
1351+ c->drop_x_ms = 300;
1352+ c->drop_y_ms = 300;
1353+ c->drop_scale_ms = 300;
1354+ c->drop_angle_ms = 300;
1355+
1356+ return c;
1357+}
1358+
1359+static void destroy_slots(struct grail_element **slots, int nslot)
1360+{
1361+ int i;
1362+
1363+ if (slots) {
1364+ for (i = nslot - 1; i >= 0; i--)
1365+ free(slots[i]);
1366+ free(slots);
1367+ }
1368+}
1369+
1370+static void destroy_frame(struct grail_frame *frame, int nslot)
1371+{
1372+ if (frame) {
1373+ destroy_slots(frame->slots, nslot);
1374+ free(frame->ongoing);
1375+ free(frame);
1376+ }
1377+}
1378+
1379+static void destroy_frames(struct grail_frame **frames, int nframe, int nslot)
1380+{
1381+ int i;
1382+
1383+ if (frames) {
1384+ for (i = nframe - 1; i >= 0; i--)
1385+ destroy_frame(frames[i], nslot);
1386+ free(frames);
1387+ }
1388+}
1389+
1390+static struct grail_element **create_slots(int nslot, int ntouch, int size)
1391+{
1392+ struct grail_element **slots;
1393+ struct grail_element *s;
1394+ int i;
1395+
1396+ slots = calloc(nslot, sizeof(slots[0]));
1397+ if (!slots)
1398+ return 0;
1399+
1400+ for (i = 0; i < nslot; i++) {
1401+ s = calloc(1, size + ntouch * sizeof(void *));
1402+ if (!s)
1403+ goto out;
1404+ s->slot = i;
1405+ s->id = -1;
1406+ s->touches = (void *)((char *)s + size);
1407+ slots[i] = s;
1408+ }
1409+
1410+ return slots;
1411+ out:
1412+ destroy_slots(slots, nslot);
1413+ return 0;
1414+}
1415+
1416+static struct grail_frame *create_frame(int nslot, int ntouch,
1417+ int frame_size, int slot_size)
1418+{
1419+ struct grail_frame *frame;
1420+ int i;
1421+
1422+ frame = calloc(1, frame_size);
1423+ if (!frame)
1424+ return 0;
1425+
1426+ frame->ongoing = calloc(nslot, sizeof(frame->ongoing[0]));
1427+ frame->slots = create_slots(nslot, ntouch, slot_size);
1428+ if (!frame->ongoing || !frame->slots)
1429+ goto out;
1430+
1431+ return frame;
1432+ out:
1433+ destroy_frame(frame, nslot);
1434+ return 0;
1435+}
1436+
1437+static struct grail_frame **create_frames(int nframe, int nslot, int ntouch,
1438+ int frame_size, int slot_size)
1439+{
1440+ struct grail_frame **frames;
1441+ struct grail_frame *f;
1442+ int i;
1443+
1444+ frames = calloc(nframe, sizeof(frames[0]));
1445+ if (!frames)
1446+ return 0;
1447+
1448+ for (i = 0; i < nframe; i++) {
1449+ f = create_frame(nslot, ntouch, frame_size, slot_size);
1450+ if (!f)
1451+ goto out;
1452+ frames[i] = f;
1453+ }
1454+
1455+ return frames;
1456+ out:
1457+ destroy_frames(frames, nframe, nslot);
1458+ return 0;
1459+}
1460+
1461+int create_grail2(struct grail_impl *x,
1462+ utouch_frame_handle fh,
1463+ unsigned int num_frames,
1464+ grail_select_callback select,
1465+ unsigned int version,
1466+ unsigned int control_size,
1467+ unsigned int frame_size,
1468+ unsigned int slot_size)
1469+{
1470+ struct utouch_surface *s = utouch_frame_get_surface(fh);
1471+ unsigned int ntouch = utouch_frame_get_num_slots(fh);
1472+ unsigned int nslot = get_slot_count(ntouch);
1473+ int i, j;
1474+
1475+ x->select = select;
1476+ x->control_size = MAX(control_size, sizeof(struct grail_control));
1477+ x->frame_size = MAX(frame_size, sizeof(struct grail_frame));
1478+ x->slot_size = MAX(slot_size, sizeof(struct grail_element));
1479+
1480+ x->num_frames = num_frames;
1481+ x->num_slots = nslot;
1482+ x->num_touches = ntouch;
1483+
1484+ x->ctl = create_control(x->control_size);
1485+ if (!x->ctl)
1486+ goto freemem;
1487+
1488+ x->frames = create_frames(num_frames, nslot, ntouch,
1489+ x->frame_size, x->slot_size);
1490+ if (!x->frames)
1491+ goto freemem;
1492+
1493+ for (i = 0; i < num_frames; i++)
1494+ x->frames[(i + 1) % num_frames]->prev = x->frames[i];
1495+
1496+ return 0;
1497+
1498+ freemem:
1499+ destroy_grail2(x);
1500+ return -ENOMEM;
1501+}
1502+
1503+void destroy_grail2(struct grail_impl *x)
1504+{
1505+ destroy_frames(x->frames, x->num_frames, x->num_slots);
1506+ free(x->ctl);
1507+}
1508+
1509+grail_handle grail_new_raw(utouch_frame_handle fh,
1510+ unsigned int num_frames,
1511+ grail_select_callback select,
1512+ unsigned int version,
1513+ unsigned int control_size,
1514+ unsigned int frame_size,
1515+ unsigned int slot_size)
1516+{
1517+ struct grail *ge;
1518+ struct grail_impl *x;
1519+
1520+ ge = calloc(1, sizeof(*ge));
1521+ if (!ge)
1522+ return 0;
1523+ x = calloc(1, sizeof(*x));
1524+ if (!x)
1525+ goto out;
1526+ x->fh = fh;
1527+ if (create_grail2(x, fh, num_frames, select,
1528+ version, control_size, frame_size, slot_size))
1529+ goto out;
1530+
1531+ ge->impl = x;
1532+ return ge;
1533+
1534+ out:
1535+ free(x);
1536+ free(ge);
1537+ return 0;
1538+}
1539+
1540+void grail_delete(grail_handle ge)
1541+{
1542+ destroy_grail2(ge->impl);
1543+ free(ge->impl);
1544+ free(ge);
1545+}
1546+
1547+struct grail_control *grail_get_control(grail_handle ge)
1548+{
1549+ return ge->impl->ctl;
1550+}
1551
1552=== modified file 'src/grail-inserter.c'
1553--- src/grail-inserter.c 2011-03-28 20:04:20 +0000
1554+++ src/grail-inserter.c 2011-03-29 08:01:03 +0000
1555@@ -2,8 +2,7 @@
1556 *
1557 * grail - Gesture Recognition And Instantiation Library
1558 *
1559- * Copyright (C) 2010 Canonical Ltd.
1560- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
1561+ * Copyright (C) 2010-2011 Canonical Ltd.
1562 *
1563 * This program is free software: you can redistribute it and/or modify it
1564 * under the terms of the GNU General Public License as published by the
1565
1566=== modified file 'src/grail-inserter.h'
1567--- src/grail-inserter.h 2011-03-28 20:04:20 +0000
1568+++ src/grail-inserter.h 2011-03-29 08:01:03 +0000
1569@@ -2,8 +2,7 @@
1570 *
1571 * grail - Gesture Recognition And Instantiation Library
1572 *
1573- * Copyright (C) 2010 Canonical Ltd.
1574- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
1575+ * Copyright (C) 2010-2011 Canonical Ltd.
1576 *
1577 * This program is free software: you can redistribute it and/or modify it
1578 * under the terms of the GNU General Public License as published by the
1579
1580=== added file 'src/grail-legacy.c'
1581--- src/grail-legacy.c 1970-01-01 00:00:00 +0000
1582+++ src/grail-legacy.c 2011-03-29 08:01:03 +0000
1583@@ -0,0 +1,65 @@
1584+/*****************************************************************************
1585+ *
1586+ * grail - Gesture Recognition And Instantiation Library
1587+ *
1588+ * Copyright (C) 2010-2011 Canonical Ltd.
1589+ *
1590+ * This program is free software: you can redistribute it and/or modify it
1591+ * under the terms of the GNU General Public License as published by the
1592+ * Free Software Foundation, either version 3 of the License, or (at your
1593+ * option) any later version.
1594+ *
1595+ * This program is distributed in the hope that it will be useful, but
1596+ * WITHOUT ANY WARRANTY; without even the implied warranty of
1597+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1598+ * General Public License for more details.
1599+ *
1600+ * You should have received a copy of the GNU General Public License along
1601+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1602+ *
1603+ ****************************************************************************/
1604+
1605+#include <grail.h>
1606+#include "grail-inserter.h"
1607+#include <string.h>
1608+#include <stdio.h>
1609+#include <unistd.h>
1610+#include <fcntl.h>
1611+#include <malloc.h>
1612+#include <errno.h>
1613+#include <stdlib.h>
1614+
1615+#ifndef GRAIL_NO_LEGACY_ABI
1616+
1617+void grail_filter_abs_events(struct grail *ge, int usage)
1618+{
1619+ struct grail_impl *x = ge->impl;
1620+ x->filter_abs = usage;
1621+}
1622+
1623+int grail_get_contacts(const struct grail *ge,
1624+ struct grail_contact *touch, int max_touch)
1625+{
1626+ const struct gesture_inserter *gin = ge->gin;
1627+ const struct utouch_frame *frame = ge->impl->touch;
1628+ int i;
1629+ if (frame->num_active < max_touch)
1630+ max_touch = frame->num_active;
1631+ for (i = 0; i < max_touch; i++) {
1632+ struct grail_contact *t = &touch[i];
1633+ const struct utouch_contact *ct = frame->active[i];
1634+ t->id = ct->id;
1635+ t->tool_type = ct->tool_type;
1636+ t->pos.x = ct->x;
1637+ t->pos.y = ct->y;
1638+ t->touch_major = ct->touch_major;
1639+ t->touch_minor = ct->touch_minor;
1640+ t->width_major = ct->width_major;
1641+ t->width_minor = ct->width_minor;
1642+ t->angle = ct->orientation;
1643+ t->pressure = ct->pressure;
1644+ }
1645+ return max_touch;
1646+}
1647+
1648+#endif
1649
1650=== modified file 'src/grail-recognizer.c'
1651--- src/grail-recognizer.c 2011-03-28 20:04:07 +0000
1652+++ src/grail-recognizer.c 2011-03-29 08:01:03 +0000
1653@@ -2,8 +2,7 @@
1654 *
1655 * grail - Gesture Recognition And Instantiation Library
1656 *
1657- * Copyright (C) 2010 Canonical Ltd.
1658- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
1659+ * Copyright (C) 2010-2011 Canonical Ltd.
1660 *
1661 * This program is free software: you can redistribute it and/or modify it
1662 * under the terms of the GNU General Public License as published by the
1663
1664=== modified file 'src/grail-recognizer.h'
1665--- src/grail-recognizer.h 2011-03-28 20:04:07 +0000
1666+++ src/grail-recognizer.h 2011-03-29 08:01:03 +0000
1667@@ -2,8 +2,7 @@
1668 *
1669 * grail - Gesture Recognition And Instantiation Library
1670 *
1671- * Copyright (C) 2010 Canonical Ltd.
1672- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
1673+ * Copyright (C) 2010-2011 Canonical Ltd.
1674 *
1675 * This program is free software: you can redistribute it and/or modify it
1676 * under the terms of the GNU General Public License as published by the
1677
1678=== modified file 'src/grailbuf.h'
1679--- src/grailbuf.h 2011-01-02 12:06:56 +0000
1680+++ src/grailbuf.h 2011-03-29 08:01:03 +0000
1681@@ -2,8 +2,7 @@
1682 *
1683 * grail - Gesture Recognition And Instantiation Library
1684 *
1685- * Copyright (C) 2010 Canonical Ltd.
1686- * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
1687+ * Copyright (C) 2010-2011 Canonical Ltd.
1688 *
1689 * This program is free software: you can redistribute it and/or modify it
1690 * under the terms of the GNU General Public License as published by the
1691
1692=== modified file 'test/Makefile.am'
1693--- test/Makefile.am 2011-03-17 09:47:52 +0000
1694+++ test/Makefile.am 2011-03-29 08:01:03 +0000
1695@@ -9,6 +9,7 @@
1696
1697 check_grail_SOURCES = \
1698 check-mapping.c \
1699+ check-transform.c \
1700 check-grail.c
1701
1702 check_grail_CFLAGS = \
1703
1704=== modified file 'test/check-grail.c'
1705--- test/check-grail.c 2011-03-17 09:47:52 +0000
1706+++ test/check-grail.c 2011-03-29 08:01:03 +0000
1707@@ -3,6 +3,7 @@
1708 #define LOGFILE_PREFIX ""
1709
1710 extern Suite *make_mapping_suite();
1711+extern Suite *make_transform_suite();
1712
1713 int main(int argc CK_ATTRIBUTE_UNUSED, char* argv[] CK_ATTRIBUTE_UNUSED)
1714 {
1715@@ -11,6 +12,7 @@
1716 int num_failed;
1717
1718 srunner_add_suite(sr, make_mapping_suite());
1719+ srunner_add_suite(sr, make_transform_suite());
1720
1721 srunner_set_log(sr, "check_grail.log");
1722 srunner_set_xml(sr, "check_grail.xml");
1723
1724=== added file 'test/check-transform.c'
1725--- test/check-transform.c 1970-01-01 00:00:00 +0000
1726+++ test/check-transform.c 2011-03-29 08:01:03 +0000
1727@@ -0,0 +1,137 @@
1728+#include <check.h>
1729+#include <utouch/frame-mtdev.h>
1730+#include <grail.h>
1731+#include <string.h>
1732+#include <stdio.h>
1733+#include <unistd.h>
1734+#include <fcntl.h>
1735+#include <stdlib.h>
1736+#include <time.h>
1737+#include <math.h>
1738+
1739+struct test_data {
1740+ struct evemu_device *evemu;
1741+ utouch_frame_handle fh;
1742+ grail_handle ge;
1743+ FILE *fp;
1744+ struct timeval evtime;
1745+};
1746+
1747+static int near(const struct grail_coord *p, float x, float y)
1748+{
1749+ double dx = p->x - x;
1750+ double dy = p->y - y;
1751+ return dx * dx + dy * dy < 1e-8 * (x * x + y * y);
1752+}
1753+
1754+static int init_test_data(struct test_data *data, const char *path)
1755+{
1756+ memset(data, 0, sizeof(*data));
1757+
1758+ data->fp = fopen(path, "r");
1759+ if (!data->fp)
1760+ return -1;
1761+
1762+ data->evemu = evemu_new(NULL);
1763+ if (!data->evemu || evemu_read(data->evemu, data->fp) <= 0)
1764+ return -1;
1765+
1766+ data->fh = utouch_frame_new_engine(100, 32, 100);
1767+ if (!data->fh || utouch_frame_init_mtdev(data->fh, data->evemu))
1768+ return -1;
1769+
1770+ data->ge = grail_new(data->fh, 10, 0);
1771+ if (!data->ge)
1772+ return -1;
1773+
1774+ return 0;
1775+}
1776+
1777+static void term_test_data(struct test_data *data)
1778+{
1779+ grail_delete(data->ge);
1780+ utouch_frame_delete_engine(data->fh);
1781+ evemu_delete(data->evemu);
1782+ fclose(data->fp);
1783+}
1784+
1785+static int get_event(struct test_data *data, struct input_event *ev)
1786+{
1787+ return evemu_read_event_realtime(data->fp, ev, &data->evtime) > 0;
1788+}
1789+
1790+static const struct grail_element *get_element(struct test_data *data,
1791+ const struct input_event *ev)
1792+{
1793+ const struct utouch_frame *touch;
1794+ const struct grail_frame *frame;
1795+
1796+ touch = utouch_frame_pump_mtdev(data->fh, ev);
1797+ if (!touch)
1798+ return 0;
1799+ frame = grail_pump_frame(data->ge, touch);
1800+ if (!frame || !frame->num_ongoing)
1801+ return 0;
1802+
1803+ return frame->ongoing[frame->num_ongoing - 1];
1804+}
1805+
1806+START_TEST(device_coordinates)
1807+{
1808+ struct test_data data;
1809+ struct input_event ev;
1810+ const struct grail_element *slot;
1811+ struct grail_coord pos = { 0, 0 };
1812+
1813+ fail_if(init_test_data(&data, "io/evemu/one-tap.evemu"));
1814+
1815+ while (get_event(&data, &ev)) {
1816+ slot = get_element(&data, &ev);
1817+ if (slot)
1818+ pos = slot->center;
1819+ }
1820+
1821+ fail_unless(near(&pos, 17087, 14790));
1822+
1823+ term_test_data(&data);
1824+}
1825+END_TEST
1826+
1827+START_TEST(mapped_coordinates)
1828+{
1829+ static const struct grail_coord min = { 0, 0 }, max = { 1.6, 1 };
1830+ struct test_data data;
1831+ struct input_event ev;
1832+ const struct grail_element *slot;
1833+ struct grail_coord pos = { 0, 0 };
1834+
1835+ fail_if(init_test_data(&data, "io/evemu/one-tap.evemu"));
1836+ grail_set_bbox(data.ge, &min, &max);
1837+
1838+ while (get_event(&data, &ev)) {
1839+ slot = get_element(&data, &ev);
1840+ if (slot)
1841+ pos = slot->center;
1842+ }
1843+
1844+ fail_unless(near(&pos, 0.834303, 0.451338));
1845+
1846+ term_test_data(&data);
1847+}
1848+END_TEST
1849+
1850+Suite *make_transform_suite()
1851+{
1852+ Suite *s = suite_create("grail-solver");
1853+ TCase *test;
1854+
1855+ test = tcase_create("device_coordinates");
1856+ tcase_add_test(test, device_coordinates);
1857+ suite_add_tcase(s, test);
1858+
1859+ test = tcase_create("mapped_coordinates");
1860+ tcase_add_test(test, mapped_coordinates);
1861+ suite_add_tcase(s, test);
1862+
1863+ return s;
1864+}
1865
1866=== modified file 'tools/Makefile.am'
1867--- tools/Makefile.am 2011-01-02 12:08:08 +0000
1868+++ tools/Makefile.am 2011-03-29 08:01:03 +0000
1869@@ -1,7 +1,15 @@
1870-bin_PROGRAMS = grail-gesture
1871+bin_PROGRAMS = grail-gesture grail-test-mtdev
1872+
1873+if HAVE_XI
1874+
1875+bin_PROGRAMS += grail-transform
1876+
1877+endif
1878
1879 INCLUDES=-I$(top_srcdir)/include/
1880
1881-grail_gesture_SOURCES = grail-gesture.c
1882-grail_gesture_LDFLAGS = -L$(top_builddir)/src/.libs/ \
1883- -lutouch-grail -lutouch-frame -lutouch-evemu -lmtdev -lm
1884+AM_CFLAGS = $(X11_CFLAGS) $(XINPUT_CFLAGS)
1885+
1886+AM_LDFLAGS = -L$(top_builddir)/src/.libs/ \
1887+ -lutouch-grail -lutouch-frame -lutouch-evemu -lmtdev \
1888+ $(X11_LIBS) $(XINPUT_LIBS) -lm
1889
1890=== modified file 'tools/grail-gesture.c'
1891--- tools/grail-gesture.c 2011-03-17 09:46:39 +0000
1892+++ tools/grail-gesture.c 2011-03-29 08:01:03 +0000
1893@@ -2,7 +2,7 @@
1894 *
1895 * grail - Gesture Recognition And Instantiation Library
1896 *
1897- * Copyright (C) 2010 Canonical Ltd.
1898+ * Copyright (C) 2010-2011 Canonical Ltd.
1899 *
1900 * This program is free software: you can redistribute it and/or modify it
1901 * under the terms of the GNU General Public License as published by the
1902@@ -17,9 +17,6 @@
1903 * You should have received a copy of the GNU General Public License along
1904 * with this program. If not, see <http://www.gnu.org/licenses/>.
1905 *
1906- * Authors:
1907- * Henrik Rydberg <rydberg@bitmath.org>
1908- *
1909 ****************************************************************************/
1910
1911 #include <grail.h>
1912
1913=== added file 'tools/grail-test-mtdev.c'
1914--- tools/grail-test-mtdev.c 1970-01-01 00:00:00 +0000
1915+++ tools/grail-test-mtdev.c 2011-03-29 08:01:03 +0000
1916@@ -0,0 +1,256 @@
1917+/*****************************************************************************
1918+ *
1919+ * grail - Gesture Recognition And Instantiation Library
1920+ *
1921+ * Copyright (C) 2010-2011 Canonical Ltd.
1922+ *
1923+ * This program is free software: you can redistribute it and/or modify it
1924+ * under the terms of the GNU General Public License as published by the
1925+ * Free Software Foundation, either version 3 of the License, or (at your
1926+ * option) any later version.
1927+ *
1928+ * This program is distributed in the hope that it will be useful, but
1929+ * WITHOUT ANY WARRANTY; without even the implied warranty of
1930+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1931+ * General Public License for more details.
1932+ *
1933+ * You should have received a copy of the GNU General Public License along
1934+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1935+ *
1936+ ****************************************************************************/
1937+
1938+#define MTDEV_NO_LEGACY_API
1939+
1940+#include <utouch/frame-mtdev.h>
1941+#include <grail.h>
1942+#include <string.h>
1943+#include <stdio.h>
1944+#include <unistd.h>
1945+#include <fcntl.h>
1946+#include <math.h>
1947+
1948+struct frame_test {
1949+ struct evemu_device *evemu;
1950+ struct mtdev *mtdev;
1951+ utouch_frame_handle fh;
1952+ grail_handle ge;
1953+};
1954+
1955+static int init_evemu(struct frame_test *test, FILE *fp, int fd)
1956+{
1957+ test->evemu = evemu_new(NULL);
1958+ if (!test->evemu)
1959+ return -1;
1960+ if (fp)
1961+ return evemu_read(test->evemu, fp) <= 0;
1962+ else
1963+ return evemu_extract(test->evemu, fd);
1964+}
1965+
1966+static int init_mtdev(struct frame_test *test, int fd)
1967+{
1968+ test->mtdev = mtdev_new_open(fd);
1969+ if (!test->mtdev)
1970+ return -1;
1971+ return 0;
1972+}
1973+
1974+static int init_frame(struct frame_test *test, int fd)
1975+{
1976+ test->fh = utouch_frame_new_engine(100, 32, 100);
1977+ if (!test->fh)
1978+ return -1;
1979+ return utouch_frame_init_mtdev(test->fh, test->evemu);
1980+}
1981+
1982+static int init_grail(struct frame_test *test)
1983+{
1984+ struct grail_coord min = { 0, 0 };
1985+ struct grail_coord max = { 1, 1 };
1986+ test->ge = grail_new(test->fh, 10, 0);
1987+ if (!test->ge)
1988+ return -1;
1989+ grail_set_bbox(test->ge, &min, &max);
1990+ return 0;
1991+}
1992+
1993+static void destroy_all(struct frame_test *test)
1994+{
1995+ grail_delete(test->ge);
1996+ utouch_frame_delete_engine(test->fh);
1997+ if (test->mtdev)
1998+ mtdev_close_delete(test->mtdev);
1999+ evemu_delete(test->evemu);
2000+ memset(test, 0, sizeof(*test));
2001+}
2002+
2003+static void report_frame(grail_handle ge,
2004+ const struct utouch_frame *touch)
2005+{
2006+ const struct grail_frame *frame = grail_pump_frame(ge, touch);
2007+ int i;
2008+
2009+ if (!frame)
2010+ return;
2011+
2012+ fprintf(stderr, "ongoing elements: %d\n", frame->num_ongoing);
2013+
2014+ for (i = 0; i < frame->num_ongoing; i++) {
2015+ const struct grail_element *slot = frame->ongoing[i];
2016+ if (!slot->active_mask)
2017+ continue;
2018+
2019+ fprintf(stderr, " element %d\n", i);
2020+ fprintf(stderr, " slot: %d\n", slot->slot);
2021+ fprintf(stderr, " id: %d\n", slot->id);
2022+ fprintf(stderr, " num_touches: %d\n", slot->num_touches);
2023+ fprintf(stderr, " expect: %d\n", slot->expect_mask);
2024+ fprintf(stderr, " active: %d\n", slot->active_mask);
2025+ fprintf(stderr, " start time: %ld\n", slot->start_time);
2026+ fprintf(stderr, " center.x: %f\n", slot->center.x);
2027+ fprintf(stderr, " center.y: %f\n", slot->center.y);
2028+ fprintf(stderr, " velocity.x: %f\n", slot->velocity.x);
2029+ fprintf(stderr, " velocity.y: %f\n", slot->velocity.y);
2030+ fprintf(stderr, " radius2: %f\n", slot->radius2);
2031+ fprintf(stderr, " %+08f %+08f %+08f\n"
2032+ " %+08f %+08f %+08f\n"
2033+ " %+08f %+08f %+08f\n",
2034+ slot->transform[0], slot->transform[1],
2035+ slot->transform[2], slot->transform[3],
2036+ slot->transform[4], slot->transform[5],
2037+ slot->transform[6], slot->transform[7],
2038+ slot->transform[8]);
2039+ fprintf(stderr, " moveness: %f\n", slot->moveness);
2040+ fprintf(stderr, " pivot.x: %f\n", slot->pivot.x);
2041+ fprintf(stderr, " pivot.y: %f\n", slot->pivot.y);
2042+ fprintf(stderr, " drag.x: %f\n", slot->drag.x);
2043+ fprintf(stderr, " drag.y: %f\n", slot->drag.y);
2044+ fprintf(stderr, " scale2: %f\n", slot->scale2);
2045+ fprintf(stderr, " angle: %f\n", slot->angle);
2046+ }
2047+}
2048+
2049+static void loop_device(struct frame_test *test, FILE *fp, int fd)
2050+{
2051+ const struct utouch_frame *frame;
2052+ struct input_event ev;
2053+
2054+ if (fp) {
2055+ struct timeval evtime;
2056+ memset(&evtime, 0, sizeof(evtime));
2057+ while (evemu_read_event_realtime(fp, &ev, &evtime) > 0) {
2058+ frame = utouch_frame_pump_mtdev(test->fh, &ev);
2059+ if (frame)
2060+ report_frame(test->ge, frame);
2061+ }
2062+ } else {
2063+ while (!mtdev_idle(test->mtdev, fd, 5000)) {
2064+ while (mtdev_get(test->mtdev, fd, &ev, 1) > 0) {
2065+ frame = utouch_frame_pump_mtdev(test->fh, &ev);
2066+ if (frame)
2067+ report_frame(test->ge, frame);
2068+ }
2069+ }
2070+ }
2071+}
2072+
2073+static void report_device_caps(struct frame_test *test)
2074+{
2075+ const struct utouch_surface *s = utouch_frame_get_surface(test->fh);
2076+
2077+ fprintf(stderr, "device props:\n");
2078+ if (s->needs_pointer)
2079+ fprintf(stderr, "\tpointer\n");
2080+ if (s->is_direct)
2081+ fprintf(stderr, "\tdirect\n");
2082+ if (s->is_buttonpad)
2083+ fprintf(stderr, "\tbuttonpad\n");
2084+ if (s->is_semi_mt)
2085+ fprintf(stderr, "\tsemi_mt\n");
2086+ fprintf(stderr, "device mt events:\n");
2087+ if (s->use_touch_major)
2088+ fprintf(stderr, "\ttouch_major\n");
2089+ if (s->use_touch_minor)
2090+ fprintf(stderr, "\ttouch_minor\n");
2091+ if (s->use_width_major)
2092+ fprintf(stderr, "\twidth_major\n");
2093+ if (s->use_width_minor)
2094+ fprintf(stderr, "\twidth_minor\n");
2095+ if (s->use_orientation)
2096+ fprintf(stderr, "\torientation\n");
2097+ if (s->use_pressure)
2098+ fprintf(stderr, "\tpressure\n");
2099+ if (s->use_distance)
2100+ fprintf(stderr, "\tdistance\n");
2101+
2102+ fprintf(stderr, "touch frames: %d\n",
2103+ utouch_frame_get_num_frames(test->fh));
2104+ fprintf(stderr, "touch slots: %d\n",
2105+ utouch_frame_get_num_slots(test->fh));
2106+}
2107+
2108+int main(int argc, char *argv[])
2109+{
2110+ struct frame_test test;
2111+ struct stat fs;
2112+ FILE *fp = 0;
2113+ int fd;
2114+
2115+ if (argc < 2) {
2116+ fprintf(stderr, "Usage: %s <device>\n", argv[0]);
2117+ return -1;
2118+ }
2119+
2120+ memset(&test, 0, sizeof(test));
2121+
2122+ fd = open(argv[1], O_RDONLY | O_NONBLOCK);
2123+ if (fd < 0) {
2124+ fprintf(stderr, "error: could not open device\n");
2125+ return -1;
2126+ }
2127+ if (fstat(fd, &fs)) {
2128+ fprintf(stderr, "error: could not stat the device\n");
2129+ return -1;
2130+ }
2131+ if (!fs.st_rdev)
2132+ fp = fdopen(fd, "r");
2133+
2134+ if (!fp && ioctl(fd, EVIOCGRAB, 1)) {
2135+ fprintf(stderr, "error: could not grab the device\n");
2136+ return -1;
2137+ }
2138+
2139+ if (init_evemu(&test, fp, fd)) {
2140+ fprintf(stderr, "error: could not describe device\n");
2141+ return -1;
2142+ }
2143+ if (!utouch_frame_is_supported_mtdev(test.evemu)) {
2144+ fprintf(stderr, "error: unsupported device\n");
2145+ return -1;
2146+ }
2147+
2148+ fprintf(stderr, "device: %s\n", evemu_get_name(test.evemu));
2149+
2150+ if (!fp && init_mtdev(&test, fd)) {
2151+ fprintf(stderr, "error: could not init mtdev\n");
2152+ return -1;
2153+ }
2154+ if (init_frame(&test, fd)) {
2155+ fprintf(stderr, "error: could not init frame\n");
2156+ return -1;
2157+ }
2158+ if (init_grail(&test)) {
2159+ fprintf(stderr, "error: could not init grail\n");
2160+ return -1;
2161+ }
2162+
2163+ report_device_caps(&test);
2164+
2165+ loop_device(&test, fp, fd);
2166+
2167+ destroy_all(&test);
2168+
2169+ if (fs.st_rdev)
2170+ ioctl(fd, EVIOCGRAB, 0);
2171+ return 0;
2172+}
2173
2174=== added file 'tools/grail-transform.c'
2175--- tools/grail-transform.c 1970-01-01 00:00:00 +0000
2176+++ tools/grail-transform.c 2011-03-29 08:01:03 +0000
2177@@ -0,0 +1,374 @@
2178+/*****************************************************************************
2179+ *
2180+ * grail - Gesture Recognition And Instantiation Library
2181+ *
2182+ * Copyright (C) 2010-2011 Canonical Ltd.
2183+ *
2184+ * This program is free software: you can redistribute it and/or modify it
2185+ * under the terms of the GNU General Public License as published by the
2186+ * Free Software Foundation, either version 3 of the License, or (at your
2187+ * option) any later version.
2188+ *
2189+ * This program is distributed in the hope that it will be useful, but
2190+ * WITHOUT ANY WARRANTY; without even the implied warranty of
2191+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2192+ * General Public License for more details.
2193+ *
2194+ * You should have received a copy of the GNU General Public License along
2195+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2196+ *
2197+ ****************************************************************************/
2198+
2199+#include "config.h"
2200+#include <evemu.h>
2201+#include <utouch/frame-mtdev.h>
2202+#include <utouch/frame-xi2.h>
2203+#include <grail.h>
2204+#include <stdio.h>
2205+#include <stdlib.h>
2206+#include <unistd.h>
2207+#include <fcntl.h>
2208+#include <string.h>
2209+#include <math.h>
2210+
2211+struct appdata {
2212+ int opcode;
2213+ struct grail_coord min, max;
2214+ int fd;
2215+ struct evemu_device *evemu;
2216+ struct mtdev *mtdev;
2217+ utouch_frame_handle fh;
2218+ struct grail *ge;
2219+
2220+ struct grail_coord pos[4];
2221+ struct grail_coord touch[32];
2222+ struct grail_coord pivot;
2223+ XPoint pts[5];
2224+ int scaling;
2225+ int ntouch;
2226+
2227+ Display *dsp;
2228+ Window win;
2229+ GC gc;
2230+ int screen;
2231+ float off_x, off_y;
2232+ unsigned long white, black;
2233+};
2234+
2235+static void clear_screen(struct appdata *w)
2236+{
2237+ const struct utouch_surface *s = utouch_frame_get_surface(w->fh);
2238+ int width = s->mapped_max_x - s->mapped_min_x;
2239+ int height = s->mapped_max_y - s->mapped_min_y;
2240+ int i;
2241+
2242+ XSetForeground(w->dsp, w->gc, w->white);
2243+ XFillRectangle(w->dsp, w->win, w->gc, 0, 0, width, height);
2244+
2245+ for (i = 0; i < 5; i++) {
2246+ w->pts[i].x = w->pos[i % 4].x - w->off_x;
2247+ w->pts[i].y = w->pos[i % 4].y - w->off_y;
2248+ }
2249+
2250+ XSetForeground(w->dsp, w->gc, w->black);
2251+ XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin);
2252+
2253+}
2254+
2255+static void draw_object(struct appdata *w)
2256+{
2257+ static const double frac = 0.01;
2258+ const struct utouch_surface *s = utouch_frame_get_surface(w->fh);
2259+ double d = frac * (s->mapped_max_x - s->mapped_min_x);
2260+ int i;
2261+
2262+ XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin);
2263+
2264+ if (w->scaling)
2265+ XFillArc(w->dsp, w->win, w->gc,
2266+ w->pivot.x - d / 2, w->pivot.y - d / 2,
2267+ d, d, 0, 360 * 64);
2268+
2269+ d *= 4;
2270+ for (i = 0; i < w->ntouch; i++)
2271+ XFillArc(w->dsp, w->win, w->gc,
2272+ w->touch[i].x - d / 2, w->touch[i].y - d / 2,
2273+ d, d, 0, 360 * 64);
2274+}
2275+
2276+static void report_frame(struct appdata *w,
2277+ const struct utouch_frame *touch)
2278+{
2279+ const struct grail_control *ctl = grail_get_control(w->ge);
2280+ const struct grail_frame *frame;
2281+ const struct grail_element *slot;
2282+ struct grail_coord tmp;
2283+ int i;
2284+
2285+ if (!touch)
2286+ return;
2287+
2288+ frame = grail_pump_frame(w->ge, touch);
2289+ if (!frame || !frame->num_ongoing || !frame->prev->num_ongoing)
2290+ return;
2291+
2292+ slot = frame->ongoing[frame->num_ongoing - 1];
2293+ if (slot->transform[0] == 0 && slot->transform[1] == 0)
2294+ return;
2295+
2296+ for (i = 0; i < 4; i++) {
2297+ grail_element_transform(slot, &tmp, &w->pos[i]);
2298+ w->pos[i] = tmp;
2299+ }
2300+
2301+ XSetForeground(w->dsp, w->gc, w->white);
2302+ draw_object(w);
2303+
2304+ w->ntouch = touch->num_active;
2305+ for (i = 0; i < w->ntouch; i++) {
2306+ w->touch[i].x = touch->active[i]->x - w->off_x;
2307+ w->touch[i].y = touch->active[i]->y - w->off_y;
2308+ }
2309+
2310+ w->scaling = slot->moveness < ctl->thresh_scale;
2311+ w->pivot.x = slot->pivot.x - w->off_x;
2312+ w->pivot.y = slot->pivot.y - w->off_y;
2313+
2314+ for (i = 0; i < 5; i++) {
2315+ w->pts[i].x = w->pos[i % 4].x - w->off_x;
2316+ w->pts[i].y = w->pos[i % 4].y - w->off_y;
2317+ }
2318+
2319+ XSetForeground(w->dsp, w->gc, w->black);
2320+ draw_object(w);
2321+
2322+ XFlush(w->dsp);
2323+}
2324+
2325+static int init_window(struct appdata *w)
2326+{
2327+ int event, err;
2328+
2329+ w->pos[0].x = 100;
2330+ w->pos[0].y = 100;
2331+ w->pos[1].x = 200;
2332+ w->pos[1].y = 100;
2333+ w->pos[2].x = 200;
2334+ w->pos[2].y = 200;
2335+ w->pos[3].x = 100;
2336+ w->pos[3].y = 200;
2337+
2338+ w->dsp = XOpenDisplay(NULL);
2339+ if (!w->dsp)
2340+ return -1;
2341+ if (!XQueryExtension(w->dsp, "XInputExtension",
2342+ &w->opcode, &event, &err))
2343+ return -1;
2344+
2345+ w->screen = DefaultScreen(w->dsp);
2346+ w->white = WhitePixel(w->dsp, w->screen);
2347+ w->black = BlackPixel(w->dsp, w->screen);
2348+
2349+ w->win = XCreateSimpleWindow(w->dsp, XDefaultRootWindow(w->dsp),
2350+ 0, 0, 600, 600, 0, w->black, w->white);
2351+ w->gc = DefaultGC(w->dsp, w->screen);
2352+
2353+ XMapWindow(w->dsp, w->win);
2354+ XFlush(w->dsp);
2355+
2356+ return 0;
2357+}
2358+
2359+static void term_window(struct appdata *w)
2360+{
2361+ XDestroyWindow(w->dsp, w->win);
2362+ XCloseDisplay(w->dsp);
2363+}
2364+
2365+static void set_screen_size_mtdev(struct appdata *w, XEvent *xev)
2366+{
2367+ struct utouch_surface *s = utouch_frame_get_surface(w->fh);
2368+ XConfigureEvent *cev = (XConfigureEvent *)xev;
2369+
2370+ s->mapped_min_x = 0;
2371+ s->mapped_min_y = 0;
2372+ s->mapped_max_x = DisplayWidth(w->dsp, w->screen);
2373+ s->mapped_max_y = DisplayHeight(w->dsp, w->screen);
2374+ s->mapped_max_pressure = 1;
2375+
2376+ if (cev) {
2377+ w->off_x = cev->x;
2378+ w->off_y = cev->y;
2379+ }
2380+}
2381+
2382+static void loop_device_mtdev(struct appdata *w)
2383+{
2384+ const struct utouch_frame *tf;
2385+ struct input_event iev;
2386+ XEvent xev;
2387+
2388+ clear_screen(w);
2389+
2390+ set_screen_size_mtdev(w, 0);
2391+ XSelectInput(w->dsp, w->win, StructureNotifyMask);
2392+
2393+ while (1) {
2394+ while (!mtdev_idle(w->mtdev, w->fd, 100)) {
2395+ while (mtdev_get(w->mtdev, w->fd, &iev, 1) > 0) {
2396+ tf = utouch_frame_pump_mtdev(w->fh, &iev);
2397+ report_frame(w, tf);
2398+ }
2399+ }
2400+ while (XPending(w->dsp)) {
2401+ XNextEvent(w->dsp, &xev);
2402+ set_screen_size_mtdev(w, &xev);
2403+ }
2404+ }
2405+}
2406+
2407+static int run_mtdev(struct appdata *w, const char *path)
2408+{
2409+ w->fd = open(path, O_RDONLY | O_NONBLOCK);
2410+ if (w->fd < 0) {
2411+ fprintf(stderr, "error: could not open device\n");
2412+ return -1;
2413+ }
2414+ if (ioctl(w->fd, EVIOCGRAB, 1)) {
2415+ fprintf(stderr, "error: could not grab the device\n");
2416+ return -1;
2417+ }
2418+
2419+ w->evemu = evemu_new(NULL);
2420+ if (!w->evemu)
2421+ return -1;
2422+ if (evemu_extract(w->evemu, w->fd))
2423+ return -1;
2424+ w->mtdev = mtdev_new_open(w->fd);
2425+ if (!w->mtdev)
2426+ return -1;
2427+ w->fh = utouch_frame_new_engine(500, 32, 100);
2428+ if (!w->fh)
2429+ return -1;
2430+ if (utouch_frame_init_mtdev(w->fh, w->evemu))
2431+ return -1;
2432+ w->ge = grail_new(w->fh, 100, 0);
2433+ if (!w->ge)
2434+ return -1;
2435+
2436+ grail_get_control(w->ge)->drop_x_ms = 1e8;
2437+ grail_get_control(w->ge)->drop_y_ms = 1e8;
2438+ grail_get_control(w->ge)->drop_scale_ms = 1e8;
2439+ grail_get_control(w->ge)->drop_angle_ms = 1e8;
2440+
2441+ loop_device_mtdev(w);
2442+
2443+ grail_delete(w->ge);
2444+ utouch_frame_delete_engine(w->fh);
2445+ mtdev_close_delete(w->mtdev);
2446+ evemu_delete(w->evemu);
2447+
2448+ ioctl(w->fd, EVIOCGRAB, 0);
2449+ close(w->fd);
2450+}
2451+
2452+#if HAVE_XI
2453+static void loop_device_xi2(struct appdata *w, int id)
2454+{
2455+ const struct utouch_frame *tf;
2456+ XIEventMask mask;
2457+
2458+ mask.deviceid = id;
2459+ mask.mask_len = XIMaskLen(XI_LASTEVENT);
2460+ mask.mask = calloc(mask.mask_len, sizeof(char));
2461+
2462+ XISetMask(mask.mask, XI_TouchBegin);
2463+ XISetMask(mask.mask, XI_TouchUpdate);
2464+ XISetMask(mask.mask, XI_TouchEnd);
2465+ XISetMask(mask.mask, XI_PropertyEvent);
2466+ XISelectEvents(w->dsp, w->win, &mask, 1);
2467+
2468+ XSelectInput(w->dsp, DefaultRootWindow(w->dsp), StructureNotifyMask);
2469+
2470+ while (1) {
2471+ XEvent ev;
2472+ XIDeviceEvent *event = (void *)&ev;
2473+ XGenericEventCookie *cookie = &ev.xcookie;
2474+ XNextEvent(w->dsp, &ev);
2475+
2476+ if (XGetEventData(w->dsp, cookie) &&
2477+ cookie->type == GenericEvent &&
2478+ cookie->extension == w->opcode) {
2479+ tf = utouch_frame_pump_xi2(w->fh, cookie->data);
2480+ report_frame(w, tf);
2481+ }
2482+ XFreeEventData(w->dsp, cookie);
2483+ }
2484+
2485+}
2486+
2487+static int run_xi2(struct appdata *w, int id)
2488+{
2489+ XIDeviceInfo *info, *dev;
2490+ int ndevices, i;
2491+
2492+ info = XIQueryDevice(w->dsp, XIAllDevices, &ndevices);
2493+ dev = 0;
2494+ for (i = 0; i < ndevices; i++)
2495+ if (info[i].deviceid == id)
2496+ dev = &info[i];
2497+ if (!dev)
2498+ return -1;
2499+
2500+ w->fh = utouch_frame_new_engine(500, 32, 100);
2501+ if (!w->fh)
2502+ return -1;
2503+ if (utouch_frame_init_xi2(w->fh, w->dsp, dev))
2504+ return -1;
2505+ w->ge = grail_new(w->fh, 100, 0);
2506+ if (!w->ge)
2507+ return -1;
2508+
2509+ loop_device_xi2(w, id);
2510+
2511+ grail_delete(w->ge);
2512+ utouch_frame_delete_engine(w->fh);
2513+
2514+ XIFreeDeviceInfo(info);
2515+
2516+ return 0;
2517+}
2518+#else
2519+static int run_xi2(struct appdata *w, int id)
2520+{
2521+ fprintf(stderr, "X not supported in this build (use --with-xi)\n");
2522+ return 0;
2523+}
2524+#endif
2525+
2526+int main(int argc, char **argv)
2527+{
2528+ struct appdata w;
2529+ int id, ret;
2530+
2531+ if (argc < 2) {
2532+ fprintf(stderr, "Usage: %s <device>\n", argv[0]);
2533+ return -1;
2534+ }
2535+
2536+ memset(&w, 0, sizeof(w));
2537+
2538+ if (init_window(&w))
2539+ return -1;
2540+
2541+ id = atoi(argv[1]);
2542+
2543+ if (id)
2544+ ret = run_xi2(&w, id);
2545+ else
2546+ ret = run_mtdev(&w, argv[1]);
2547+
2548+ term_window(&w);
2549+
2550+ return ret;
2551+}
2552
2553=== modified file 'utouch-grail.sym.in'
2554--- utouch-grail.sym.in 2011-01-02 12:08:42 +0000
2555+++ utouch-grail.sym.in 2011-03-29 08:01:03 +0000
2556@@ -1,13 +1,19 @@
2557 grail_close
2558+grail_delete
2559 grail_filter_abs_events
2560+grail_get_contact_frame
2561 grail_get_contacts
2562+grail_get_control
2563 grail_get_units
2564+grail_get_version
2565 grail_idle
2566 grail_mask_clear_mask
2567 grail_mask_count
2568 grail_mask_get_first
2569 grail_mask_get_next
2570 grail_mask_set_mask
2571+grail_new_raw
2572 grail_open
2573 grail_pull
2574+grail_pump_frame
2575 grail_set_bbox

Subscribers

People subscribed via source and target branches

to all changes: