summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/grail.h204
-rw-r--r--src/Makefile.am4
-rw-r--r--src/grail-frame.c399
-rw-r--r--src/grail-impl.h38
-rw-r--r--src/grail-init.c241
5 files changed, 885 insertions, 1 deletions
diff --git a/include/grail.h b/include/grail.h
index b208556..d9f3937 100644
--- a/include/grail.h
+++ b/include/grail.h
@@ -44,8 +44,17 @@ extern "C" {
44#define GRAIL_STATUS_UPDATE 1 44#define GRAIL_STATUS_UPDATE 1
45#define GRAIL_STATUS_END 2 45#define GRAIL_STATUS_END 2
46 46
47#define GRAIL_EXPECT_CENTER_X 0x0001
48#define GRAIL_EXPECT_CENTER_Y 0x0002
49#define GRAIL_EXPECT_DRAG_X 0x0004
50#define GRAIL_EXPECT_DRAG_Y 0x0008
51#define GRAIL_EXPECT_SCALE 0x0010
52#define GRAIL_EXPECT_ANGLE 0x0020
53#define GRAIL_EXPECT_MASK 0x003f
54
47typedef float grail_prop_t; /* gesture properties */ 55typedef float grail_prop_t; /* gesture properties */
48typedef utouch_frame_time_t grail_time_t; /* time in milliseconds */ 56typedef utouch_frame_time_t grail_time_t; /* time in milliseconds */
57typedef struct grail *grail_handle; /* the grail instance handle */
49 58
50/** 59/**
51 * struct grail_get_version - get grail library version 60 * struct grail_get_version - get grail library version
@@ -69,6 +78,64 @@ struct grail_coord {
69 float x, y; 78 float x, y;
70}; 79};
71 80
81grail_handle GRAIL_PUBLIC grail_new_raw(utouch_frame_handle fh,
82 unsigned int num_frames,
83 void *select,
84 unsigned int version,
85 unsigned int control_size,
86 unsigned int frame_size,
87 unsigned int slot_size);
88
89/**
90 * grail_new - allocate and initialize a new grail instance
91 * @fh: utouch frame handle to use
92 * @num_frames: number of frames in cyclic buffer
93 * @select: client selection callback
94 *
95 * Initialize the internal grail structures.
96 *
97 * Returns zero in case of failure.
98 */
99#define grail_new(fh, num_frames, select) \
100 grail_new_raw(fh, num_frames, select, \
101 GRAIL_VERSION, \
102 sizeof(struct grail_control), \
103 sizeof(struct grail_frame), \
104 sizeof(struct grail_element))
105
106/**
107 * grail_delete - destroy and delete grail instance
108 * @ge: grail instance in use
109 *
110 * Deallocates all internal memory structures.
111 */
112void GRAIL_PUBLIC grail_delete(grail_handle ge);
113
114/**
115 * grail_get_control - get mutable control structure
116 * @ge: the grail device in use
117 *
118 * Return the control struct of the grail instance.
119 *
120 * The control pointer is ABI agnostic, owned by the grail instance, and
121 * has grail scope.
122 */
123struct grail_control GRAIL_PUBLIC *grail_get_control(grail_handle ge);
124
125/**
126 * grail_pump_frame - insert touch frames into grail
127 * @ge: the grail device in use
128 * @frame: the touch frame to insert
129 *
130 * Insert a new touch frame into the grail engine. If the frame induces a
131 * new gesture frame, a pointer to the frame is returned.
132 *
133 * The grail frame pointer is ABI agnostic, owned by the grail instance, and
134 * has grail scope.
135 */
136const struct grail_frame GRAIL_PUBLIC *
137grail_pump_frame(grail_handle ge, const struct utouch_frame *frame);
138
72/** 139/**
73 * struct grail_client_id - Gesture client information 140 * struct grail_client_id - Gesture client information
74 * @client: Client id 141 * @client: Client id
@@ -95,6 +162,143 @@ struct grail_client_info {
95}; 162};
96 163
97/** 164/**
165 * struct grail_control - control parameters of grail
166 * @glue_ms: minimum time to hold activation (ms)
167 * @bar_center_x: horizontal distance to activate (surface width fraction)
168 * @bar_center_y: vertical distance to activate (surface height fraction)
169 * @bar_drag_x: horizontal distance to activate (surface width fraction)
170 * @bar_drag_y: vertical distance to activate (surface height fraction)
171 * @bar_scale: minimum scaling to activate (fraction)
172 * @bar_angle: minimum angle to activate (radians)
173 * @drop_x_ms: horizontal expect timeout (ms)
174 * @drop_y_ms: vertical expect timeout (ms)
175 * @drop_scale_ms: scaling expect timeout (ms)
176 * @drop_angle_ms: rotation expect timeout (ms)
177 * @pivot_unbound: when true, the pivot is not bound to the contact area
178 *
179 * The parameters are used to tune the behavior of the gesture recognition.
180 *
181 * The moveness is a number between zero and one denoting the
182 * character of the current transform. Zero means pure rotate and
183 * scale, one means pure drag.
184 *
185 * Later versions of this struct may grow in size, but will remain
186 * binary compatible with older versions.
187 */
188struct grail_control {
189 float glue_ms;
190 float bar_center_x;
191 float bar_center_y;
192 float bar_drag_x;
193 float bar_drag_y;
194 float bar_scale;
195 float bar_angle;
196 float drop_x_ms;
197 float drop_y_ms;
198 float drop_scale_ms;
199 float drop_angle_ms;
200 int pivot_unbound;
201};
202
203/**
204 * struct grail_frame - frame of ongoing elementary transformations
205 * @prev: pointer to the previous gesture frame
206 * @touch: pointer to the touch frame triggering this gesture frame
207 * @num_ongoing: number of elements in the ongoing array
208 * @ongoing: array of ongoing transformation elements
209 * @slots: array of all transformation slots
210 *
211 * A gesture frame consists of one or several touch frames glued
212 * together into a stable transition, combined with information on
213 * ongoing elementary gestural transformations. The array of ongoing
214 * elements contains all elements with a nonzero expect mask.
215 *
216 * Later versions of this struct may grow in size, but will remain
217 * binary compatible with older versions.
218 */
219struct grail_frame {
220 const struct grail_frame *prev;
221 const struct utouch_frame *touch;
222 unsigned int num_ongoing;
223 struct grail_element **ongoing;
224 struct grail_element **slots;
225};
226
227/**
228 * struct grail_element - elementary gesture transformation
229 * @prev: respective element of previous frame
230 * @slot: the transformation slot occupied by this element
231 * @id: unique identifier of the ongoing transformation
232 * @num_touches: number of contacts of this element
233 * @touches: array of contacts of this element
234 * @start_time: start time of this element
235 * @start_center: center position at start of transform (surface units)
236 * @expect_mask: bitmask of expected gestures (grail main types)
237 * @active_mask: bitmask of activated gestures (grail main types)
238 * @center: gesture center position (surface units)
239 * @velocity: current center velocity (surface units per second)
240 * @radius: gesture radius from center (surface units)
241 * @transform: the transformation matrix of the gesture
242 * @pivot: current center of rotate and scale (surface units)
243 * @drag: accumulated transformation displacement (surface units)
244 * @scale: accumulated scale (dimensionless)
245 * @angle: accumulated rotation angle (radians)
246 *
247 * The grail element describes the ongoing gestural transformation of
248 * a particular set of contacts. The expect mask describes which
249 * gestural transformations may become active during the course of
250 * events, and the active mask describes which have passed their
251 * respective activation threshold. The set of expected gestures can
252 * change over time, for instance by exclusion or timeout.
253 *
254 * Applications handling rotation, either by transformation matrix or
255 * angle, should use the drag displacement. For other applications,
256 * the center displacement may be used instead, as to not lose
257 * movement accuracy.
258 *
259 * Later versions of this struct may grow in size, but will remain
260 * binary compatible with older versions.
261 */
262struct grail_element {
263 const struct grail_element *prev;
264 int slot;
265 int id;
266 int num_touches;
267 const struct utouch_contact **touches;
268 grail_time_t start_time;
269 struct grail_coord start_center;
270 unsigned int expect_mask;
271 unsigned int active_mask;
272 struct grail_coord center;
273 struct grail_coord velocity;
274 float radius2;
275 float transform[6];
276 float moveness;
277 struct grail_coord pivot;
278 struct grail_coord drag;
279 float scale2;
280 float angle;
281};
282
283/**
284 * grail_element_transform - transform coordinates using element
285 * @slot: the transformation element to use
286 * @q: the grail coordinate to fill
287 * @x: the grail coordinate to transform
288 *
289 * Performs the 3x3 transform *q = T *p, where T is the element
290 * transform.
291 */
292static inline void grail_element_transform(const struct grail_element *slot,
293 struct grail_coord *q,
294 const struct grail_coord *p)
295{
296 const float *T = slot->transform;
297 q->x = T[0] * p->x + T[1] * p->y + T[2];
298 q->y = T[3] * p->x + T[4] * p->y + T[5];
299}
300
301/**
98 * struct grail_event - Gesture event 302 * struct grail_event - Gesture event
99 * @type: The gesture type 303 * @type: The gesture type
100 * @id: Unique identifier foof the gesture instance 304 * @id: Unique identifier foof the gesture instance
diff --git a/src/Makefile.am b/src/Makefile.am
index b26574c..5011c1f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,7 +26,9 @@ libutouch_grail_la_SOURCES = \
26 grail-event.c \ 26 grail-event.c \
27 grail-impl.h \ 27 grail-impl.h \
28 grail-api.c \ 28 grail-api.c \
29 grail-legacy.c 29 grail-legacy.c \
30 grail-init.c \
31 grail-frame.c
30 32
31# These are flags required to properly set up 33# These are flags required to properly set up
32# the build. -fvisibility requires GCC > 4 (or clang) 34# the build. -fvisibility requires GCC > 4 (or clang)
diff --git a/src/grail-frame.c b/src/grail-frame.c
new file mode 100644
index 0000000..cf38452
--- /dev/null
+++ b/src/grail-frame.c
@@ -0,0 +1,399 @@
1/*****************************************************************************
2 *
3 * grail - Gesture Recognition And Instantiation Library
4 *
5 * Copyright (C) 2010 Canonical Ltd.
6 * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 ****************************************************************************/
22
23#include "grail-impl.h"
24#include <stdlib.h>
25#include <string.h>
26#include <math.h>
27
28static void set_center_velocity_and_radius(struct grail_impl *impl,
29 struct grail_element *slot)
30{
31 const struct utouch_contact **tc = slot->touches;
32 double x, y, vx, vy, r2, dx, dy;
33 int i;
34
35 switch (slot->num_touches) {
36 case 1:
37 x = tc[0]->x;
38 y = tc[0]->y;
39 vx = tc[0]->vx;
40 vy = tc[0]->vy;
41 r2 = 0;
42 break;
43 case 2:
44 dx = 0.5 * (tc[1]->x - tc[0]->x);
45 dy = 0.5 * (tc[1]->y - tc[0]->y);
46 x = tc[0]->x + dx;
47 y = tc[0]->y + dy;
48 vx = 0.5 * (tc[0]->vx + tc[1]->vx);
49 vy = 0.5 * (tc[0]->vy + tc[1]->vy);
50 r2 = dx * dx + dy * dy;
51 break;
52 default:
53 x = y = vx = vy = r2 = 0;
54 for (i = 0; i < slot->num_touches; i++) {
55 x += tc[i]->x;
56 y += tc[i]->y;
57 vx += tc[i]->vx;
58 vy += tc[i]->vy;
59 }
60 x /= slot->num_touches;
61 y /= slot->num_touches;
62 vx /= slot->num_touches;
63 vy /= slot->num_touches;
64 for (i = 0; i < slot->num_touches; i++) {
65 dx = tc[i]->x - x;
66 dy = tc[i]->y - y;
67 r2 += dx * dx + dy * dy;
68 }
69 r2 /= slot->num_touches;
70 break;
71 }
72
73 slot->center.x = x;
74 slot->center.y = y;
75 slot->velocity.x = 1000 * vx;
76 slot->velocity.y = 1000 * vy;
77 slot->radius2 = r2;
78}
79
80static void set_moveness_pivot_and_drag(struct grail_impl *impl,
81 struct grail_element *slot,
82 double ds, double dc)
83{
84 const struct grail_control *ctl = impl->ctl;
85 const struct grail_element *pslot = slot->prev;
86 double mx = slot->center.x - pslot->center.x;
87 double my = slot->center.y - pslot->center.y;
88 float *T = slot->transform;
89
90 slot->moveness = 1;
91 slot->pivot = pslot->center;
92
93 if (slot->num_touches > 1) {
94 double wx = (1 - dc) * mx + ds * my;
95 double wy = (1 - dc) * my - ds * mx;
96 double w2 = wx * wx + wy * wy;
97 if (w2 > 0) {
98 double q = (mx * mx + my * my) / w2;
99 double s = ctl->pivot_unbound ?
100 q : sqrt(pslot->radius2 / w2);
101 if (s < q) {
102 slot->moveness = 1 - s / q;
103 slot->pivot.x += s * wx;
104 slot->pivot.y += s * wy;
105 } else {
106 slot->moveness = 0;
107 slot->pivot.x += q * wx;
108 slot->pivot.y += q * wy;
109 }
110 }
111 }
112
113 mx *= slot->moveness;
114 my *= slot->moveness;
115
116 T[0] = dc;
117 T[1] = ds;
118 T[2] = (1 - dc) * slot->pivot.x - ds * slot->pivot.y + mx;
119 T[3] = -ds;
120 T[4] = dc;
121 T[5] = (1 - dc) * slot->pivot.y + ds * slot->pivot.x + my;
122
123 slot->drag.x = pslot->drag.x + mx;
124 slot->drag.y = pslot->drag.y + my;
125}
126
127static void start_slot(struct grail_impl *impl,
128 struct grail_element *slot,
129 const struct utouch_frame *touch)
130{
131 float *T = slot->transform;
132
133 slot->id = impl->seqid++ & GRAIL_ID_MAX;
134 slot->expect_mask = GRAIL_EXPECT_MASK;
135 slot->active_mask = 0;
136 slot->start_time = touch->time;
137 set_center_velocity_and_radius(impl, slot);
138 slot->start_center = slot->center;
139 T[0] = T[4] = 1;
140 T[1] = T[2] = T[3] = T[5] = 0;
141 slot->pivot = slot->center;
142 slot->drag.x = 0;
143 slot->drag.y = 0;
144 slot->scale2 = 1;
145 slot->angle = 0;
146}
147
148static void update_slot(struct grail_impl *impl,
149 struct grail_element *slot,
150 double ds, double dc)
151{
152 const struct grail_element *pslot = slot->prev;
153
154 slot->id = pslot->id;
155 slot->start_time = pslot->start_time;
156 slot->start_center = pslot->start_center;
157 slot->expect_mask = pslot->expect_mask;
158 slot->active_mask = pslot->active_mask;
159
160 set_center_velocity_and_radius(impl, slot);
161 set_moveness_pivot_and_drag(impl, slot, ds, dc);
162
163 slot->scale2 = pslot->scale2 * (ds * ds + dc * dc);
164 slot->angle = pslot->angle + ds / dc; /* atan2(ds, dc) */
165}
166
167static void stop_slot(struct grail_impl *impl,
168 struct grail_element *slot)
169{
170 const struct grail_element *pslot = slot->prev;
171 float *T = slot->transform;
172
173 slot->id = -1;
174 slot->num_touches = 0;
175 slot->start_time = pslot->start_time;
176 slot->start_center = pslot->start_center;
177 slot->expect_mask = 0;
178 slot->active_mask = pslot->active_mask;
179 slot->center = pslot->center;
180 slot->velocity = pslot->velocity;
181 slot->radius2 = pslot->radius2;
182 T[0] = T[4] = 1;
183 T[1] = T[2] = T[3] = T[5] = 0;
184 slot->moveness = 1;
185 slot->pivot = pslot->pivot;
186 slot->drag = pslot->drag;
187 slot->scale2 = pslot->scale2;
188 slot->angle = pslot->angle;
189}
190
191static void set_slot_one(struct grail_impl *impl,
192 struct grail_element *slot,
193 const struct utouch_frame *touch,
194 const struct utouch_contact *t1)
195{
196 const struct grail_element *pslot = slot->prev;
197 const struct utouch_contact *p1 = pslot->touches[0];
198
199 if (!t1->active) {
200 stop_slot(impl, slot);
201 return;
202 }
203
204 slot->touches[0] = t1;
205 slot->num_touches = 1;
206
207 if (pslot->num_touches != slot->num_touches || t1->id != p1->id) {
208 start_slot(impl, slot, touch);
209 return;
210 }
211
212 update_slot(impl, slot, 0, 1);
213}
214
215static void set_slot_two(struct grail_impl *impl,
216 struct grail_element *slot,
217 const struct utouch_frame *touch,
218 const struct utouch_contact *t1,
219 const struct utouch_contact *t2)
220{
221 const struct grail_element *pslot = slot->prev;
222 const struct utouch_contact *p1 = pslot->touches[0];
223 const struct utouch_contact *p2 = pslot->touches[1];
224 double tx, ty, px, py, d2;
225
226 if (!t1->active || !t2->active) {
227 stop_slot(impl, slot);
228 return;
229 }
230
231 slot->touches[0] = t1;
232 slot->touches[1] = t2;
233 slot->num_touches = 2;
234
235 if (pslot->num_touches != slot->num_touches ||
236 t1->id != p1->id || t2->id != p2->id) {
237 start_slot(impl, slot, touch);
238 return;
239 }
240
241 tx = t2->x - t1->x;
242 ty = t2->y - t1->y;
243 px = p2->x - p1->x;
244 py = p2->y - p1->y;
245
246 d2 = px * px + py * py;
247 if (d2 > 0) {
248 px /= d2;
249 py /= d2;
250 }
251
252 update_slot(impl, slot, tx * py - ty * px, tx * px + ty * py);
253}
254
255static void set_slot_multi(struct grail_impl *impl,
256 struct grail_element *slot,
257 struct grail_frame *frame,
258 const struct utouch_frame *touch)
259{
260 const struct grail_element *pslot = slot->prev;
261 struct grail_element **slots = frame->slots;
262 int i, j, n = impl->num_touches;
263 struct grail_element *best = 0;
264
265 if (touch->num_active < 3) {
266 stop_slot(impl, slot);
267 return;
268 }
269
270 memcpy(slot->touches, touch->active,
271 touch->num_active * sizeof(slot->touches[0]));
272 slot->num_touches = touch->num_active;
273
274 if (pslot->num_touches != slot->num_touches) {
275 start_slot(impl, slot, touch);
276 return;
277 }
278
279 for (i = 0; i < slot->num_touches; i++) {
280 if (slot->touches[i]->id != pslot->touches[i]->id) {
281 start_slot(impl, slot, touch);
282 return;
283 }
284 }
285
286 for (i = 0; i < impl->num_touches; i++) {
287 for (j = i + 1; j < impl->num_touches; j++) {
288 struct grail_element *s = slots[n++];
289 if (!s->num_touches)
290 continue;
291 if (!best || s->radius2 > best->radius2)
292 best = s;
293 }
294 }
295
296 update_slot(impl, slot, best->transform[1], best->transform[0]);
297}
298
299static void set_slots(struct grail_impl *impl,
300 struct grail_frame *frame,
301 const struct utouch_frame *touch)
302{
303 struct grail_element **slots = frame->slots;
304 struct utouch_contact *const *tc = touch->slots;
305 int i, j, n = 0;
306
307 for (i = 0; i < impl->num_touches; i++)
308 set_slot_one(impl, slots[n++], touch, tc[i]);
309
310 for (i = 0; i < impl->num_touches; i++)
311 for (j = i + 1; j < impl->num_touches; j++)
312 set_slot_two(impl, slots[n++], touch, tc[i], tc[j]);
313
314 set_slot_multi(impl, slots[n++], frame, touch);
315}
316
317static void collect_transforms(struct grail_impl *impl,
318 struct grail_frame *frame,
319 const struct utouch_frame *touch)
320{
321 const struct utouch_surface *s = utouch_frame_get_surface(impl->fh);
322 const struct grail_control *ctl = impl->ctl;
323 float c_x = ctl->bar_center_x * (s->mapped_max_x - s->mapped_min_x);
324 float c_y = ctl->bar_center_y * (s->mapped_max_y - s->mapped_min_y);
325 float d_x = ctl->bar_drag_x * (s->mapped_max_x - s->mapped_min_x);
326 float d_y = ctl->bar_drag_y * (s->mapped_max_y - s->mapped_min_y);
327 float ds2 = ctl->bar_scale * ctl->bar_scale;
328 float dt;
329 int i;
330
331 for (i = 0; i < impl->num_slots; i++) {
332 struct grail_element *s = frame->slots[i];
333
334 if (!s->num_touches)
335 continue;
336
337 dt = touch->time - s->start_time;
338 if (dt > ctl->glue_ms) {
339 unsigned int mask = s->active_mask;
340
341 if (fabs(s->center.x - s->start_center.x) > c_x)
342 mask |= GRAIL_EXPECT_CENTER_X;
343 if (fabs(s->center.y - s->start_center.y) > c_y)
344 mask |= GRAIL_EXPECT_CENTER_Y;
345 if (fabs(s->drag.x) > d_x)
346 mask |= GRAIL_EXPECT_DRAG_X;
347 if (fabs(s->drag.y) > d_y)
348 mask |= GRAIL_EXPECT_DRAG_Y;
349 if (fabs(s->scale2 - 1) > ds2)
350 mask |= GRAIL_EXPECT_SCALE;
351 if (fabs(s->angle) > ctl->bar_angle)
352 mask |= GRAIL_EXPECT_ANGLE;
353
354 s->active_mask = mask;
355
356 if (dt < ctl->drop_x_ms)
357 mask |= GRAIL_EXPECT_CENTER_X;
358 if (dt < ctl->drop_y_ms)
359 mask |= GRAIL_EXPECT_CENTER_Y;
360 if (dt < ctl->drop_x_ms)
361 mask |= GRAIL_EXPECT_DRAG_X;
362 if (dt < ctl->drop_y_ms)
363 mask |= GRAIL_EXPECT_DRAG_Y;
364 if (dt < ctl->drop_scale_ms)
365 mask |= GRAIL_EXPECT_SCALE;
366 if (dt < ctl->drop_angle_ms)
367 mask |= GRAIL_EXPECT_ANGLE;
368
369 s->expect_mask &= mask;
370 }
371
372 frame->ongoing[frame->num_ongoing++] = s;
373 }
374}
375
376const struct grail_frame GRAIL_PUBLIC *
377grail_pump_frame(grail_handle ge, const struct utouch_frame *touch)
378{
379 struct grail_impl *impl = ge->impl;
380 struct grail_frame *frame = impl->frames[impl->nextframe];
381 const struct grail_frame *prev = frame->prev;
382 int i;
383
384 if (touch->slot_revision == touch->prev->slot_revision &&
385 !prev->num_ongoing)
386 return 0;
387
388 frame->touch = touch;
389 frame->num_ongoing = 0;
390 for (i = 0; i < impl->num_slots; i++)
391 frame->slots[i]->prev = prev->slots[i];
392
393 set_slots(impl, frame, touch);
394 collect_transforms(impl, frame, touch);
395
396 impl->nextframe = (impl->nextframe + 1) % impl->num_frames;
397
398 return frame;
399}
diff --git a/src/grail-impl.h b/src/grail-impl.h
index 8f73a2d..e9b1038 100644
--- a/src/grail-impl.h
+++ b/src/grail-impl.h
@@ -33,6 +33,32 @@
33 33
34#define DIM_TOUCH 32 34#define DIM_TOUCH 32
35#define DIM_TOUCH_BYTES ((DIM_TOUCH + 7) >> 3) 35#define DIM_TOUCH_BYTES ((DIM_TOUCH + 7) >> 3)
36#define GRAIL_ID_MAX 0xffff
37
38#define MIN(a, b) ((a) < (b) ? (a) : (b))
39#define MAX(a, b) ((a) > (b) ? (a) : (b))
40
41typedef void *grail_select_callback;
42
43/*
44 * In this implementation, there can be N one-gestures, N (N - 1) / 2
45 * two-gestures, and one global gesture.
46 */
47static inline int get_slot_count(int n)
48{
49 return n + n * (n - 1) / 2 + 1;
50}
51
52int create_grail2(struct grail_impl *x,
53 utouch_frame_handle fh,
54 unsigned int num_frames,
55 void *select,
56 unsigned int version,
57 unsigned int control_size,
58 unsigned int frame_size,
59 unsigned int slot_size);
60
61void destroy_grail2(struct grail_impl *x);
36 62
37struct grail_impl { 63struct grail_impl {
38 struct evemu_device *evemu; 64 struct evemu_device *evemu;
@@ -45,6 +71,18 @@ struct grail_impl {
45 int ongoing; 71 int ongoing;
46 int gesture; 72 int gesture;
47 FILE *fptest; 73 FILE *fptest;
74 /* new stuff below */
75 struct grail_control *ctl;
76 grail_select_callback select;
77 int num_frames;
78 int num_slots;
79 int num_touches;
80 int nextframe;
81 int seqid;
82 unsigned int control_size;
83 unsigned int frame_size;
84 unsigned int slot_size;
85 struct grail_frame **frames;
48}; 86};
49 87
50#endif 88#endif
diff --git a/src/grail-init.c b/src/grail-init.c
new file mode 100644
index 0000000..18e6996
--- /dev/null
+++ b/src/grail-init.c
@@ -0,0 +1,241 @@
1/*****************************************************************************
2 *
3 * grail - Gesture Recognition And Instantiation Library
4 *
5 * Copyright (C) 2010 Canonical Ltd.
6 * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 ****************************************************************************/
22
23#include "grail-impl.h"
24#include <stdlib.h>
25#include <string.h>
26#include <math.h>
27
28static struct grail_control *create_control(int size)
29{
30 struct grail_control *c = calloc(1, size);
31
32 if (!c)
33 return 0;
34
35 c->glue_ms = 60;
36 c->bar_center_x = 0.03;
37 c->bar_center_y = 0.03;
38 c->bar_drag_x = 0.03;
39 c->bar_drag_y = 0.03;
40 c->bar_scale = 0.3;
41 c->bar_angle = 0.1;
42 c->drop_x_ms = 300;
43 c->drop_y_ms = 300;
44 c->drop_scale_ms = 300;
45 c->drop_angle_ms = 300;
46
47 return c;
48}
49
50static void destroy_slots(struct grail_element **slots, int nslot)
51{
52 int i;
53
54 if (slots) {
55 for (i = nslot - 1; i >= 0; i--)
56 free(slots[i]);
57 free(slots);
58 }
59}
60
61static void destroy_frame(struct grail_frame *frame, int nslot)
62{
63 if (frame) {
64 destroy_slots(frame->slots, nslot);
65 free(frame->ongoing);
66 free(frame);
67 }
68}
69
70static void destroy_frames(struct grail_frame **frames, int nframe, int nslot)
71{
72 int i;
73
74 if (frames) {
75 for (i = nframe - 1; i >= 0; i--)
76 destroy_frame(frames[i], nslot);
77 free(frames);
78 }
79}
80
81static struct grail_element **create_slots(int nslot, int ntouch, int size)
82{
83 struct grail_element **slots;
84 struct grail_element *s;
85 int i;
86
87 slots = calloc(nslot, sizeof(slots[0]));
88 if (!slots)
89 return 0;
90
91 for (i = 0; i < nslot; i++) {
92 s = calloc(1, size + ntouch * sizeof(void *));
93 if (!s)
94 goto out;
95 s->slot = i;
96 s->id = -1;
97 s->touches = (void *)((char *)s + size);
98 slots[i] = s;
99 }
100
101 return slots;
102 out:
103 destroy_slots(slots, nslot);
104 return 0;
105}
106
107static struct grail_frame *create_frame(int nslot, int ntouch,
108 int frame_size, int slot_size)
109{
110 struct grail_frame *frame;
111 int i;
112
113 frame = calloc(1, frame_size);
114 if (!frame)
115 return 0;
116
117 frame->ongoing = calloc(nslot, sizeof(frame->ongoing[0]));
118 frame->slots = create_slots(nslot, ntouch, slot_size);
119 if (!frame->ongoing || !frame->slots)
120 goto out;
121
122 return frame;
123 out:
124 destroy_frame(frame, nslot);
125 return 0;
126}
127
128static struct grail_frame **create_frames(int nframe, int nslot, int ntouch,
129 int frame_size, int slot_size)
130{
131 struct grail_frame **frames;
132 struct grail_frame *f;
133 int i;
134
135 frames = calloc(nframe, sizeof(frames[0]));
136 if (!frames)
137 return 0;
138
139 for (i = 0; i < nframe; i++) {
140 f = create_frame(nslot, ntouch, frame_size, slot_size);
141 if (!f)
142 goto out;
143 frames[i] = f;
144 }
145
146 return frames;
147 out:
148 destroy_frames(frames, nframe, nslot);
149 return 0;
150}
151
152int create_grail2(struct grail_impl *x,
153 utouch_frame_handle fh,
154 unsigned int num_frames,
155 grail_select_callback select,
156 unsigned int version,
157 unsigned int control_size,
158 unsigned int frame_size,
159 unsigned int slot_size)
160{
161 struct utouch_surface *s = utouch_frame_get_surface(fh);
162 unsigned int ntouch = utouch_frame_get_num_slots(fh);
163 unsigned int nslot = get_slot_count(ntouch);
164 int i, j;
165
166 x->select = select;
167 x->control_size = MAX(control_size, sizeof(struct grail_control));
168 x->frame_size = MAX(frame_size, sizeof(struct grail_frame));
169 x->slot_size = MAX(slot_size, sizeof(struct grail_element));
170
171 x->num_frames = num_frames;
172 x->num_slots = nslot;
173 x->num_touches = ntouch;
174
175 x->ctl = create_control(x->control_size);
176 if (!x->ctl)
177 goto freemem;
178
179 x->frames = create_frames(num_frames, nslot, ntouch,
180 x->frame_size, x->slot_size);
181 if (!x->frames)
182 goto freemem;
183
184 for (i = 0; i < num_frames; i++)
185 x->frames[(i + 1) % num_frames]->prev = x->frames[i];
186
187 return 0;
188
189 freemem:
190 destroy_grail2(x);
191 return -ENOMEM;
192}
193
194void destroy_grail2(struct grail_impl *x)
195{
196 destroy_frames(x->frames, x->num_frames, x->num_slots);
197 free(x->ctl);
198}
199
200grail_handle GRAIL_PUBLIC grail_new_raw(utouch_frame_handle fh,
201 unsigned int num_frames,
202 grail_select_callback select,
203 unsigned int version,
204 unsigned int control_size,
205 unsigned int frame_size,
206 unsigned int slot_size)
207{
208 struct grail *ge;
209 struct grail_impl *x;
210
211 ge = calloc(1, sizeof(*ge));
212 if (!ge)
213 return 0;
214 x = calloc(1, sizeof(*x));
215 if (!x)
216 goto out;
217 x->fh = fh;
218 if (create_grail2(x, fh, num_frames, select,
219 version, control_size, frame_size, slot_size))
220 goto out;
221
222 ge->impl = x;
223 return ge;
224
225 out:
226 free(x);
227 free(ge);
228 return 0;
229}
230
231void GRAIL_PUBLIC grail_delete(grail_handle ge)
232{
233 destroy_grail2(ge->impl);
234 free(ge->impl);
235 free(ge);
236}
237
238struct grail_control GRAIL_PUBLIC *grail_get_control(grail_handle ge)
239{
240 return ge->impl->ctl;
241}