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

Proposed by Henrik Rydberg
Status: Merged
Merged at revision: 155
Proposed branch: lp:~oif-team/grail/grail2
Merge into: lp:grail
Diff against target: 2949 lines (+2320/-155)
36 files modified
AUTHORS (+1/-0)
configure.ac (+8/-1)
docs/gestures.txt (+58/-0)
docs/pivot.txt (+146/-0)
include/grail-bits.h (+1/-2)
include/grail-types.h (+1/-2)
include/grail.h (+254/-49)
include/grail.h.orig (+277/-0)
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 (+17/-13)
src/grail-bits.c (+1/-2)
src/grail-event.c (+1/-27)
src/grail-frame.c (+398/-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 (+371/-0)
To merge this branch: bzr merge lp:~oif-team/grail/grail2
Reviewer Review Type Date Requested Status
Chase Douglas (community) Approve
Review via email: mp+59405@code.launchpad.net

This proposal supersedes a proposal from 2011-04-12.

Description of the change

New grail2 branch, rebased to current trunk. This version addresses these points:

* Added reference to Lagrange relaxation and some more comments to the documentation

* Treats center and drag separately in the expectation mask

* Adds the option of using an unbounded pivot

Since this branch only contains additions and the new tools for testing, I suggest we merge this into trunk now, so that we can concentrate on the modifications needed for the grail2-to-grail1 glue.

To post a comment you must log in.
Revision history for this message
Henrik Rydberg (rydberg) wrote : Posted in a previous version of this proposal

Another rebase, triggered by stuff that went into trunk already. Gesture documentation augmentation folded into this series as well.

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

Henrik,

I'm feeling really good about the architecture of the code. I still have questions about some of the math, but I'll leave that aside for now ;-)

I like the new transform tool quite a bit though; it really helps visualize what is going on.

Initially, I had lots more questions, but my investigations have answered most of those. Here are the remaining comments/questions I have:

* What would you think about passing around complete 3x3 matrices instead of the 3x2 simplified matrices that grail 2 emits right now? If we did something like this, a 3x3 matrix could be thrown into many transformation libraries, like pixman, without any conversion.

* In set_slot_multi(), the touches are deep copied into the grail_element slot. In the other set_slot_*() functions, the touches are shallow copied from the passed in utouch frame. It seems that it would be best for the usage model to be consistent between all the functions... is this left-over from a change, or is there a definite rationale for the difference?

* grail_pump_frame() returns a reference to a new grail frame. The utouch frame may be retrieved by calling grail_get_contact_frame(). How do we know that the utouch contact prev pointer in the returned utouch frame is still valid? It may become invalid as soon as utouch_frame is
pumped. I don't think this could cause a bug if the code calls the frame and grail methods appropriately. However, we could run into issues with folks doing things in odd ways, since the code is non-re-entrant. For instance, if anyone needs to do parallel programming with this interface
it could get very dicey. At the very least, we should add a note in grail.h that the utouch frame data is only valid until the utouch frame is pumped again.

One thing that may help is to add a utouch_frame function that can retrieve the previous frame, if available, instead of giving the client a pointer to memory that may end up modified over time. An even better alternative would be to have reference counting of frames, but that would be a larger architecture change to utouch frame. Do you have any thoughts here?

* Touch gestures seem to be missing from grail 2.

Overall, I'm feeling pretty good about the changes. As I now understand it, the extra freedom of choosing an appropriate pivot point may allow for better touch mapping as well. I really like the work overall!

As a side note, when we go to merge this Duncan has asked that we merge it into a separate series until at least all the dependent pieces are in place to not lose functionality. I set up the lp:utouch-grail/2.x series for this purpose. Once we have this and the next merge proposals approved we can look into merging it into trunk.

Thanks!

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

Hi Chase,

thanks for your comments!

* Sending 3x3 matrices

The elements store 2x3 for memory reasons. The recipe to create the full 3x3 matrix is simple, so I would prefer to leave it as is.

* Deep copy

All functions copy the pointers, there is no deep copy anywhere. Perhaps the memcpy() in set_slot_multi caused the confusion.

* Pumping

The utouch frames are constructed as a fixed ring, so all pointers are always valid, although they will pointer to the "wrong" data after a while when the data wraps around.

The semantics around prev points could be improved upon, as you suggest. There was originally an idea that a gesture frame could span several touch frames, hence the extra logic around prev pointers for those. The reason for the idea was to be able to skip frames with "unstable" touch configurations, using the glue time. However, since then, this stabilization logic has been moved to
the actual gesture fragment activation, and it seems to me one could again simplify the semantics and say that every touch frame corresponds to a gesture frame. Any thoughts on that?

Regardless of the above, the get_frame methods could be further specified to only be well defined from a callback, for instance. In all other instances, the pointers are known anyways, from the flow of the code.

* Touch gestures

It works in this end, when running grail-gesture

* Merging

The grail2 branch i feel is pretty well tested, so that could in principle go to trunk. It only contains additions, no replacements. No biggie if we do the series for this as well, that is fine. Perhaps the series should be called 1.1, though, since be are not breaking ABI?

The grail2.next branch is not fully complete, agreed. There are test cases missing to guard the replacement patches. Minor behavior changes might also need to be checked and defined. Also, I am working on yet another simplification of the code, that should get rid of two of the three event buffers in use.

So yes, merging everything into a new series sounds good.

Tbanks!

Revision history for this message
Jussi Pakkanen (jpakkane) wrote :

Gnome's versions of MIN and MAX macros have one more set of parentheses around the condition:

http://developer.gnome.org/glib/stable/glib-Standard-Macros.html

That is, they use

#define MIN(a, b) (((a) < (b)) ? (a) : (b))

rather than

#define MIN(a, b) ((a) < (b) ? (a) : (b))

I can't see how this could lead to errors, but that's the way they do it.

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

Hm... it _looks_ like code that does not trust the operator precedence rules. Thanks for the information, anyways. I think we can safely go with our version. A further interesting example can be found in include/linux/kernel.h, where temporary variables are used.

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

I think the best course of action right now is to merge the changes so we can move on. We can resolve any issues with fixes moving forward.

I still have issues with the code that is in the unstable ppa. Until we get those fixed I would rather not merge the code directly into trunk. For now, lets merge this into lp:utouch-grail/2.x, and once we're sure all regressions are fixed we can redirect the lp:utouch-grail series to lp:utouch-grail/2.x.

(I've updated lp:utouch-grail/2.x to be in sync with lp:utouch-grail).

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

It was a bit of work for all of us to get this one in, now that it is done, thank you.

I will update 2.x to this point also, and remake the remaining branches.

Cheers!

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

Subscribers

People subscribed via source and target branches

to all changes: