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

Proposed by Chase Douglas
Status: Rejected
Rejected by: Chase Douglas
Proposed branch: lp:~chasedouglas/grail/pivot_type
Merge into: lp:~oif-team/grail/grail2
Diff against target: 2417 lines (+743/-1170)
23 files modified
include/grail-bits.h (+1/-0)
include/grail.h (+46/-36)
src/Makefile.am (+0/-7)
src/gestures-drag.c (+0/-135)
src/gestures-pinch.c (+0/-129)
src/gestures-rotate.c (+0/-128)
src/gestures-tapping.c (+0/-100)
src/gestures-touch.c (+0/-98)
src/grail-api.c (+12/-96)
src/grail-bits.c (+9/-0)
src/grail-frame.c (+159/-48)
src/grail-gestures.c (+0/-210)
src/grail-gestures.h (+0/-115)
src/grail-impl.h (+1/-0)
src/grail-init.c (+0/-2)
src/grail-inserter.c (+0/-32)
src/grail-inserter.h (+0/-2)
src/grail-legacy.c (+104/-0)
src/grail-recognizer.c (+353/-16)
src/grail-recognizer.h (+39/-4)
tools/grail-test-mtdev.c (+0/-1)
tools/grail-transform.c (+17/-11)
utouch-grail.sym.in (+2/-0)
To merge this branch: bzr merge lp:~chasedouglas/grail/pivot_type
Reviewer Review Type Date Requested Status
Henrik Rydberg (community) Disapprove
Review via email: mp+59272@code.launchpad.net

Description of the change

RFC for this changeset that adds configuration of where the pivot should be determined.

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

Removing the moveness threshold values, i can live with that, no biggie

The transform matrix should include the pivot, or it would no be useful for other programs which expect a linear transform, which is also the most efficient.

What you call the center of rotation is precisely the same as the moveness = 0 special case,
so configuration could instead be done by allowing the cutoff radius to vary, instead of having separate "algorithms".

The rest seems to be a reproduction of what is in grail2, only less efficiently coded.

All in all, I can imagine reducing this to a ten-line patch, on top of the other grail2 branches, handling mode switches. We should also think about how/if we should model the degrees of freedom depending on what gesture types are being asked for, or if this should really be controllable by the app, or if simply all data should be sent.

Because the patch should really go on top of the original gesture frames branch, I am rejecting this particular merge request.

review: Disapprove
lp:~chasedouglas/grail/pivot_type updated
151. By Chase Douglas

Make the pivot point determination configurable

* Remove moveness from grail_element
* Remove thresh_scale and thresh_drag from control
* Introduce a control for the pivot type
* Fix translation computation
* Fix grail_element_transform so it uses the pivot point
* Add new functionality for computing different pivot points
* Determine the drag value based on strictly on the centroid motion
  - This should fix grail 1 translation errors

152. By Chase Douglas

Use a red dot to denote the pivot point

The pivot point is also now drawn after the touches so it is visible when
on top of a touch point. Some drawing code was simplified by using
clear_screen.

153. By Chase Douglas

As an example, tell grail to use the convex hull pivot confinement in
grail-transform.

154. By Chase Douglas

Merge in grail 2 to grail 1 translation layer

Unmerged revisions

154. By Chase Douglas

Merge in grail 2 to grail 1 translation layer

153. By Chase Douglas

As an example, tell grail to use the convex hull pivot confinement in
grail-transform.

152. By Chase Douglas

Use a red dot to denote the pivot point

The pivot point is also now drawn after the touches so it is visible when
on top of a touch point. Some drawing code was simplified by using
clear_screen.

151. By Chase Douglas

Make the pivot point determination configurable

* Remove moveness from grail_element
* Remove thresh_scale and thresh_drag from control
* Introduce a control for the pivot type
* Fix translation computation
* Fix grail_element_transform so it uses the pivot point
* Add new functionality for computing different pivot points
* Determine the drag value based on strictly on the centroid motion
  - This should fix grail 1 translation errors

150. By Henrik Rydberg

Update copyright information

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

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

149. By Henrik Rydberg

Introduce the grail transform tool

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

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

148. By Henrik Rydberg

Introduce test-mtdev

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

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

147. By Henrik Rydberg

Add gesture transform unit tests

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

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

146. By Henrik Rydberg

Document the gesture frame logic

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

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

145. By Henrik Rydberg

Introduce gesture frames

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

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'include/grail-bits.h'
--- include/grail-bits.h 2011-04-12 16:35:37 +0000
+++ include/grail-bits.h 2011-04-27 19:43:23 +0000
@@ -49,6 +49,7 @@
4949
50void grail_mask_set_mask(grail_mask_t *a, const grail_mask_t *b, int bytes);50void grail_mask_set_mask(grail_mask_t *a, const grail_mask_t *b, int bytes);
51void grail_mask_clear_mask(grail_mask_t *a, const grail_mask_t *b, int bytes);51void grail_mask_clear_mask(grail_mask_t *a, const grail_mask_t *b, int bytes);
52int grail_mask_inner(const grail_mask_t *a, const grail_mask_t *b, int bytes);
5253
53int grail_mask_count(const grail_mask_t *mask, int bytes);54int grail_mask_count(const grail_mask_t *mask, int bytes);
54int grail_mask_get_first(const grail_mask_t *mask, int bytes);55int grail_mask_get_first(const grail_mask_t *mask, int bytes);
5556
=== modified file 'include/grail.h'
--- include/grail.h 2011-04-12 16:35:37 +0000
+++ include/grail.h 2011-04-27 19:43:23 +0000
@@ -128,6 +128,27 @@
128 */128 */
129const struct grail_frame *grail_pump_frame(grail_handle ge,129const struct grail_frame *grail_pump_frame(grail_handle ge,
130 const struct utouch_frame *frame);130 const struct utouch_frame *frame);
131/**
132 * grail_pivot_type - Option for determining location of pivot point
133 * @GRAIL_CENTROID: use the centroid of the touch points as the pivot point
134 * @GRAIL_CENTER_OF_ROTATION: set the pivot point such that there is no
135 translation in the transformation matrix ("instant center of rotation")
136 * @GRAIL_CONVEX_HULL_RADIUS: Minimize translation while confining the pivot
137 point to a circle around the centroid approximating the radius of the
138 convex hull of the touch points
139 *
140 * The gesture transformation matrix and pivot point are dependent. This means
141 * a transformation can be found for any given pivot point. Depending on the use
142 * case, one pivot point location may be better than another. If the use case
143 * involves only dragging gestures, GRAIL_CENTROID is best. If the use case
144 * involves only rotation gestures, GRAIL_CENTER_OF_ROTATION or
145 * may be better GRAIL_CONVEX_HULL_RADIUS.
146 */
147enum grail_pivot_type {
148 GRAIL_CENTROID = 0,
149 GRAIL_CENTER_OF_ROTATION,
150 GRAIL_CONVEX_HULL_RADIUS
151};
131152
132/**153/**
133 * struct grail_client_id - Gesture client information154 * struct grail_client_id - Gesture client information
@@ -157,8 +178,6 @@
157/**178/**
158 * struct grail_control - control parameters of grail179 * struct grail_control - control parameters of grail
159 * @glue_ms: minimum time to hold activation (ms)180 * @glue_ms: minimum time to hold activation (ms)
160 * @thresh_drag: minimum moveness for drag
161 * @thresh_scale: maximum moveness for rotate and scale
162 * @bar_x: minimum horizontal distance to activate (surface width fraction)181 * @bar_x: minimum horizontal distance to activate (surface width fraction)
163 * @bar_y: minimum vertical distance to activate (surface height fraction)182 * @bar_y: minimum vertical distance to activate (surface height fraction)
164 * @bar_scale: minimum scaling to activate (fraction)183 * @bar_scale: minimum scaling to activate (fraction)
@@ -170,17 +189,11 @@
170 *189 *
171 * The parameters are used to tune the behavior of the gesture recognition.190 * The parameters are used to tune the behavior of the gesture recognition.
172 *191 *
173 * The moveness is a number between zero and one denoting the
174 * character of the current transform. Zero means pure rotate and
175 * scale, one means pure drag.
176 *
177 * Later versions of this struct may grow in size, but will remain192 * Later versions of this struct may grow in size, but will remain
178 * binary compatible with older versions.193 * binary compatible with older versions.
179 */194 */
180struct grail_control {195struct grail_control {
181 float glue_ms;196 float glue_ms;
182 float thresh_drag;
183 float thresh_scale;
184 float bar_x;197 float bar_x;
185 float bar_y;198 float bar_y;
186 float bar_scale;199 float bar_scale;
@@ -189,6 +202,7 @@
189 float drop_y_ms;202 float drop_y_ms;
190 float drop_scale_ms;203 float drop_scale_ms;
191 float drop_angle_ms;204 float drop_angle_ms;
205 enum grail_pivot_type pivot_type;
192};206};
193207
194/**208/**
@@ -262,7 +276,6 @@
262 struct grail_coord velocity;276 struct grail_coord velocity;
263 float radius2;277 float radius2;
264 float transform[6];278 float transform[6];
265 float moveness;
266 struct grail_coord pivot;279 struct grail_coord pivot;
267 struct grail_coord drag;280 struct grail_coord drag;
268 float scale2;281 float scale2;
@@ -283,8 +296,12 @@
283 const struct grail_coord *p)296 const struct grail_coord *p)
284{297{
285 const float *T = slot->transform;298 const float *T = slot->transform;
286 q->x = T[0] * p->x + T[1] * p->y + T[2];299 q->x = T[0] * (p->x - slot->pivot.x) +
287 q->y = T[3] * p->x + T[4] * p->y + T[5];300 T[1] * (p->y - slot->pivot.y) +
301 T[2] + slot->pivot.x;
302 q->y = T[3] * (p->x - slot->pivot.x) +
303 T[4] * (p->y - slot->pivot.y) +
304 T[5] + slot->pivot.y;
288}305}
289306
290/**307/**
@@ -349,21 +366,6 @@
349};366};
350367
351/**368/**
352 * grail_open - open a grail device
353 * @ge: the grail device to open
354 * @fd: file descriptor of the kernel device
355 *
356 * Initialize the internal grail structures and configure it by reading the
357 * protocol capabilities through the file descriptor.
358 *
359 * The callbacks, parameters and priv pointer should be set prior to this
360 * call.
361 *
362 * Returns zero on success, negative error number otherwise.
363 */
364int grail_open(struct grail *ge, int fd);
365
366/**
367 * grail_idle - check state of kernel device369 * grail_idle - check state of kernel device
368 * @ge: the grail device in use370 * @ge: the grail device in use
369 * @fd: file descriptor of the kernel device371 * @fd: file descriptor of the kernel device
@@ -391,16 +393,6 @@
391int grail_pull(struct grail *ge, int fd);393int grail_pull(struct grail *ge, int fd);
392394
393/**395/**
394 * grail_close - close the grail device
395 * @ge: the grail device to close
396 * @fd: file descriptor of the kernel device
397 *
398 * Deallocates all memory associated with grail, and clears the grail
399 * structure.
400 */
401void grail_close(struct grail *ge, int fd);
402
403/**
404 * grail_set_bbox - set the grail unit bounding box396 * grail_set_bbox - set the grail unit bounding box
405 * @ge: the grail device in use397 * @ge: the grail device in use
406 * @min: the minimum (lower-left) corner of the bounding box398 * @min: the minimum (lower-left) corner of the bounding box
@@ -443,6 +435,22 @@
443 */435 */
444const struct utouch_frame *grail_get_contact_frame(const struct grail *ge);436const struct utouch_frame *grail_get_contact_frame(const struct grail *ge);
445437
438/**
439 * grail_get_gesture_frame - get current gesture frame
440 * @ge: the grail device in use
441 *
442 * Return the gesture frame currently being processed. If called from
443 * within a gesture callback, it is guaranteed to return the frame
444 * corresponding to the gesture.
445 *
446 * The returned pointer can be NULL if no input has yet been extracted
447 * through the grail instance.
448 *
449 * The frame pointer is ABI agnostic, owned by the grail instance, and
450 * has grail scope.
451 */
452const struct grail_frame *grail_get_gesture_frame(const struct grail *ge);
453
446#ifndef GRAIL_NO_LEGACY_API454#ifndef GRAIL_NO_LEGACY_API
447455
448struct grail_contact {456struct grail_contact {
@@ -457,6 +465,8 @@
457 float pressure;465 float pressure;
458};466};
459467
468int grail_open(struct grail *ge, int fd);
469void grail_close(struct grail *ge, int fd);
460void grail_filter_abs_events(struct grail *ge, int usage);470void grail_filter_abs_events(struct grail *ge, int usage);
461471
462int grail_get_contacts(const struct grail *ge,472int grail_get_contacts(const struct grail *ge,
463473
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2011-04-12 16:35:23 +0000
+++ src/Makefile.am 2011-04-27 19:43:23 +0000
@@ -15,13 +15,6 @@
15 grail-bits.c \15 grail-bits.c \
16 grail-inserter.c \16 grail-inserter.c \
17 grail-inserter.h \17 grail-inserter.h \
18 grail-gestures.c \
19 grail-gestures.h \
20 gestures-touch.c \
21 gestures-drag.c \
22 gestures-pinch.c \
23 gestures-rotate.c \
24 gestures-tapping.c \
25 grail-recognizer.c \18 grail-recognizer.c \
26 grail-recognizer.h \19 grail-recognizer.h \
27 grail-event.c \20 grail-event.c \
2821
=== removed file 'src/gestures-drag.c'
--- src/gestures-drag.c 2011-04-12 16:35:37 +0000
+++ src/gestures-drag.c 1970-01-01 00:00:00 +0000
@@ -1,135 +0,0 @@
1/*****************************************************************************
2 *
3 * grail - Gesture Recognition And Instantiation Library
4 *
5 * Copyright (C) 2010-2011 Canonical Ltd.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ****************************************************************************/
21
22#include "grail-recognizer.h"
23#include <math.h>
24#include <stdio.h>
25
26static const int getype[DIM_TOUCH + 1] = {
27 -1,
28 GRAIL_TYPE_DRAG1,
29 GRAIL_TYPE_DRAG2,
30 GRAIL_TYPE_DRAG3,
31 GRAIL_TYPE_DRAG4,
32 GRAIL_TYPE_DRAG5,
33};
34
35static void set_props(const struct gesture_inserter *gin,
36 struct combo_model *s, const struct move_model *m,
37 const struct utouch_frame *frame)
38{
39 if (m->single) {
40 s->prop[GRAIL_PROP_DRAG_DX] = m->fm[FM_X].raw_delta;
41 s->prop[GRAIL_PROP_DRAG_DY] = m->fm[FM_Y].raw_delta;
42 } else {
43 s->prop[GRAIL_PROP_DRAG_DX] = m->fm[FM_X].action_delta;
44 s->prop[GRAIL_PROP_DRAG_DY] = m->fm[FM_Y].action_delta;
45 }
46 s->prop[GRAIL_PROP_DRAG_VX] = m->fm[FM_X].velocity;
47 s->prop[GRAIL_PROP_DRAG_VY] = m->fm[FM_Y].velocity;
48 s->prop[GRAIL_PROP_DRAG_X] = m->fm[FM_X].value;
49 s->prop[GRAIL_PROP_DRAG_Y] = m->fm[FM_Y].value;
50 s->nprop = 6;
51 s->nprop += gin_add_contact_props(gin, s->prop + s->nprop, frame);
52}
53
54static const int fm_mask = 0x03;
55
56int gru_drag(struct grail *ge,
57 const struct utouch_frame *frame)
58{
59 struct gesture_recognizer *gru = ge->gru;
60 struct combo_model *state = &gru->drag;
61 struct move_model *move = &gru->move;
62 int mask = state->active ? (move->active & fm_mask) : fm_mask;
63 if (!move->multi && !move->single) {
64 if (state->active) {
65 gru_end(ge, state->gid, move,
66 state->prop, state->nprop);
67 state->active = 0;
68 }
69 }
70 if ((move->timeout & fm_mask) == fm_mask) {
71 if (state->active) {
72 gin_gid_timeout(ge, state->gid);
73 }
74 }
75 if (!state->active) {
76 int type = getype[move->ntouch];
77 if (type < 0)
78 return 0;
79 state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
80 state->active = 1;
81 }
82 if (!(move->tickle & mask))
83 return 0;
84 if (!(move->active & fm_mask))
85 return 0;
86 set_props(ge->gin, state, move, frame);
87 gru_event(ge, state->gid, move, state->prop, state->nprop);
88 return 1;
89}
90
91int gru_windrag(struct grail *ge,
92 const struct utouch_frame *frame)
93{
94 struct gesture_recognizer *gru = ge->gru;
95 struct combo_model *state = &gru->windrag;
96 struct move_model *move = &gru->move;
97 int mask = state->active ? (move->active & fm_mask) : fm_mask;
98 if (!move->multi && !move->single) {
99 if (state->active && out_of_bounds(state, move)) {
100 gru_end(ge, state->gid, move,
101 state->prop, state->nprop);
102 state->active = 0;
103 }
104 }
105 if ((move->timeout & fm_mask) == fm_mask) {
106 if (state->active) {
107 gin_gid_timeout(ge, state->gid);
108 }
109 }
110 if (!state->active) {
111 if (move->ntouch == 4) {
112 state->gid = gin_gid_begin(ge, GRAIL_TYPE_MDRAG,
113 PRIO_META, frame);
114 state->mintouch = 1;
115 state->maxtouch = 4;
116 state->active = 1;
117 } else if (move->ntouch == 3) {
118 state->gid = gin_gid_begin(ge, GRAIL_TYPE_EDRAG,
119 PRIO_ENV, frame);
120 state->mintouch = 1;
121 state->maxtouch = 3;
122 state->active = 1;
123 } else {
124 return 0;
125 }
126 }
127 if (!(move->tickle & mask))
128 return 0;
129 if (!(move->active & fm_mask))
130 return 0;
131 set_props(ge->gin, state, move, frame);
132 gru_event(ge, state->gid, move, state->prop, state->nprop);
133 return 1;
134}
135
1360
=== removed file 'src/gestures-pinch.c'
--- src/gestures-pinch.c 2011-04-12 16:35:37 +0000
+++ src/gestures-pinch.c 1970-01-01 00:00:00 +0000
@@ -1,129 +0,0 @@
1/*****************************************************************************
2 *
3 * grail - Gesture Recognition And Instantiation Library
4 *
5 * Copyright (C) 2010-2011 Canonical Ltd.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ****************************************************************************/
21
22#include "grail-recognizer.h"
23#include <math.h>
24#include <stdio.h>
25
26static const int getype[DIM_TOUCH + 1] = {
27 0,
28 0,
29 GRAIL_TYPE_PINCH2,
30 GRAIL_TYPE_PINCH3,
31 GRAIL_TYPE_PINCH4,
32 GRAIL_TYPE_PINCH5,
33};
34
35static const int fm_mask = 0x04;
36
37static void set_props(const struct gesture_inserter *gin,
38 struct combo_model *s,
39 const struct move_model *m,
40 const struct utouch_frame *frame)
41{
42 s->prop[GRAIL_PROP_PINCH_DR] = m->fm[FM_R].action_delta;
43 s->prop[GRAIL_PROP_PINCH_VR] = m->fm[FM_R].velocity;
44 s->prop[GRAIL_PROP_PINCH_R] = m->fm[FM_R].value;
45 s->nprop = 3;
46 s->nprop += gin_add_contact_props(gin, s->prop + s->nprop, frame);
47}
48
49int gru_pinch(struct grail *ge,
50 const struct utouch_frame *frame)
51{
52 struct gesture_recognizer *gru = ge->gru;
53 struct combo_model *state = &gru->pinch;
54 struct move_model *move = &gru->move;
55 int mask = state->active ? (move->active & fm_mask) : fm_mask;
56 if (!move->multi && !move->single) {
57 if (state->active) {
58 gru_end(ge, state->gid, move,
59 state->prop, state->nprop);
60 state->active = 0;
61 }
62 return 0;
63 }
64 if ((move->timeout & fm_mask) == fm_mask) {
65 if (state->active) {
66 gin_gid_timeout(ge, state->gid);
67 }
68 }
69 if (!(move->tickle & mask))
70 return 0;
71 if (!state->active) {
72 int type = getype[move->ntouch];
73 if (!type)
74 return 0;
75 state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
76 state->active = 1;
77 }
78 if (!(move->active & fm_mask))
79 return 0;
80 set_props(ge->gin, state, move, frame);
81 gru_event(ge, state->gid, move, state->prop, state->nprop);
82 return 1;
83}
84
85int gru_winpinch(struct grail *ge,
86 const struct utouch_frame *frame)
87{
88 struct gesture_recognizer *gru = ge->gru;
89 struct combo_model *state = &gru->winpinch;
90 struct move_model *move = &gru->move;
91 int mask = state->active ? (move->active & fm_mask) : fm_mask;
92 if (!move->multi) {
93 if (state->active && out_of_bounds(state, move)) {
94 gru_end(ge, state->gid, move,
95 state->prop, state->nprop);
96 state->active = 0;
97 }
98 return 0;
99 }
100 if ((move->timeout & fm_mask) == fm_mask) {
101 if (state->active) {
102 gin_gid_timeout(ge, state->gid);
103 }
104 }
105 if (!(move->tickle & mask))
106 return 0;
107 if (!state->active) {
108 if (move->ntouch == 4) {
109 state->gid = gin_gid_begin(ge, GRAIL_TYPE_MPINCH,
110 PRIO_META, frame);
111 state->mintouch = 2;
112 state->maxtouch = 4;
113 state->active = 1;
114 } else if (move->ntouch == 3) {
115 state->gid = gin_gid_begin(ge, GRAIL_TYPE_EPINCH,
116 PRIO_ENV, frame);
117 state->mintouch = 2;
118 state->maxtouch = 3;
119 state->active = 1;
120 } else {
121 return 0;
122 }
123 }
124 if (!(move->active & fm_mask))
125 return 0;
126 set_props(ge->gin, state, move, frame);
127 gru_event(ge, state->gid, move, state->prop, state->nprop);
128 return 1;
129}
1300
=== removed file 'src/gestures-rotate.c'
--- src/gestures-rotate.c 2011-04-12 16:35:37 +0000
+++ src/gestures-rotate.c 1970-01-01 00:00:00 +0000
@@ -1,128 +0,0 @@
1/*****************************************************************************
2 *
3 * grail - Gesture Recognition And Instantiation Library
4 *
5 * Copyright (C) 2010-2011 Canonical Ltd.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ****************************************************************************/
21
22#include "grail-recognizer.h"
23#include <math.h>
24#include <stdio.h>
25
26static const int getype[DIM_TOUCH + 1] = {
27 0,
28 0,
29 GRAIL_TYPE_ROTATE2,
30 GRAIL_TYPE_ROTATE3,
31 GRAIL_TYPE_ROTATE4,
32 GRAIL_TYPE_ROTATE5,
33};
34
35static const int fm_mask = 0x08;
36
37static void set_props(const struct gesture_inserter *gin,
38 struct combo_model *s, const struct move_model *m,
39 const struct utouch_frame *frame)
40{
41 s->prop[GRAIL_PROP_ROTATE_DA] = m->fm[FM_A].action_delta;
42 s->prop[GRAIL_PROP_ROTATE_VA] = m->fm[FM_A].velocity;
43 s->prop[GRAIL_PROP_ROTATE_A] = m->fm[FM_A].value;
44 s->nprop = 3;
45 s->nprop += gin_add_contact_props(gin, s->prop + s->nprop, frame);
46}
47
48int gru_rotate(struct grail *ge,
49 const struct utouch_frame *frame)
50{
51 struct gesture_recognizer *gru = ge->gru;
52 struct combo_model *state = &gru->rotate;
53 struct move_model *move = &gru->move;
54 int mask = state->active ? (move->active & fm_mask) : fm_mask;
55 if (!move->multi && !move->single) {
56 if (state->active) {
57 gru_end(ge, state->gid, move,
58 state->prop, state->nprop);
59 state->active = 0;
60 }
61 return 0;
62 }
63 if ((move->timeout & fm_mask) == fm_mask) {
64 if (state->active) {
65 gin_gid_timeout(ge, state->gid);
66 }
67 }
68 if (!(move->tickle & mask))
69 return 0;
70 if (!state->active) {
71 int type = getype[move->ntouch];
72 if (!type)
73 return 0;
74 state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
75 state->active = 1;
76 }
77 if (!(move->active & fm_mask))
78 return 0;
79 set_props(ge->gin, state, move, frame);
80 gru_event(ge, state->gid, move, state->prop, state->nprop);
81 return 1;
82}
83
84int gru_winrotate(struct grail *ge,
85 const struct utouch_frame *frame)
86{
87 struct gesture_recognizer *gru = ge->gru;
88 struct combo_model *state = &gru->winrotate;
89 struct move_model *move = &gru->move;
90 int mask = state->active ? (move->active & fm_mask) : fm_mask;
91 if (!move->multi) {
92 if (state->active && out_of_bounds(state, move)) {
93 gru_end(ge, state->gid, move,
94 state->prop, state->nprop);
95 state->active = 0;
96 }
97 return 0;
98 }
99 if ((move->timeout & fm_mask) == fm_mask) {
100 if (state->active) {
101 gin_gid_timeout(ge, state->gid);
102 }
103 }
104 if (!(move->tickle & mask))
105 return 0;
106 if (!state->active) {
107 if (move->ntouch == 4) {
108 state->gid = gin_gid_begin(ge, GRAIL_TYPE_MROTATE,
109 PRIO_META, frame);
110 state->mintouch = 2;
111 state->maxtouch = 4;
112 state->active = 1;
113 } else if (move->ntouch == 3) {
114 state->gid = gin_gid_begin(ge, GRAIL_TYPE_EROTATE,
115 PRIO_ENV, frame);
116 state->mintouch = 2;
117 state->maxtouch = 3;
118 state->active = 1;
119 } else {
120 return 0;
121 }
122 }
123 if (!(move->active & fm_mask))
124 return 0;
125 set_props(ge->gin, state, move, frame);
126 gru_event(ge, state->gid, move, state->prop, state->nprop);
127 return 1;
128}
1290
=== removed file 'src/gestures-tapping.c'
--- src/gestures-tapping.c 2011-04-12 16:35:37 +0000
+++ src/gestures-tapping.c 1970-01-01 00:00:00 +0000
@@ -1,100 +0,0 @@
1/*****************************************************************************
2 *
3 * grail - Gesture Recognition And Instantiation Library
4 *
5 * Copyright (C) 2010-2011 Canonical Ltd.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ****************************************************************************/
21
22#include "grail-recognizer.h"
23#include <math.h>
24
25static const int fm_mask = 0x07;
26
27static void set_props(const struct gesture_inserter *gin,
28 struct tapping_model *s, const struct move_model *m,
29 const struct utouch_frame *frame)
30{
31 s->prop[GRAIL_PROP_TAP_DT] = m->time - s->start;
32 s->prop[GRAIL_PROP_TAP_X] = m->fm[FM_X].value;
33 s->prop[GRAIL_PROP_TAP_Y] = m->fm[FM_Y].value;
34 s->nprop = 3;
35 s->nprop += gin_add_contact_props(gin, s->prop + s->nprop, frame);
36}
37
38int gru_tapping(struct grail *ge,
39 const struct utouch_frame *frame)
40{
41 struct gesture_recognizer *gru = ge->gru;
42 struct tapping_model *state = &gru->tapping;
43 struct move_model *move = &gru->move;
44 state->tap = 0;
45 if (frame->num_active && !frame->prev->num_active) {
46 state->mintouch = 0;
47 state->maxtouch = 0;
48 }
49 if (move->ntouch > state->maxtouch) {
50 if (state->active) {
51 gin_gid_discard(ge, state->gid);
52 state->active = 0;
53 }
54 state->start = move->time;
55 state->maxtouch = move->ntouch;
56 set_props(ge->gin, state, move, frame);
57 if (state->maxtouch <= 5) {
58 int type = GRAIL_TYPE_TAP1 + state->maxtouch - 1;
59 state->gid = gin_gid_begin(ge, type, PRIO_TAP, frame);
60 state->active = 1;
61 }
62 return 0;
63 }
64 if (!state->active) {
65 state->mintouch = move->ntouch;
66 state->maxtouch = move->ntouch;
67 return 0;
68 }
69 if (move->ntouch <= state->mintouch) {
70 int x = state->prop[GRAIL_PROP_TAP_X];
71 int y = state->prop[GRAIL_PROP_TAP_Y];
72 int t = move->time - state->start;
73 if (t > move->fm[FM_X].bar_ms) {
74 gin_gid_discard(ge, state->gid);
75 state->mintouch = move->ntouch;
76 state->maxtouch = move->ntouch;
77 state->active = 0;
78 return 0;
79 }
80 state->tap = state->maxtouch;
81 state->prop[GRAIL_PROP_TAP_DT] = t;
82 gin_gid_event(ge, state->gid, x, y, state->maxtouch,
83 state->prop, state->nprop, 1);
84 state->mintouch = move->ntouch;
85 state->maxtouch = move->ntouch;
86 state->active = 0;
87 return 1;
88 }
89 if (!move->ntouch)
90 return 0;
91 state->prop[GRAIL_PROP_TAP_DT] = move->time - state->start;
92 if ((move->active & fm_mask) ||
93 move->time - state->start > move->fm[FM_X].bar_ms) {
94 gin_gid_discard(ge, state->gid);
95 state->mintouch = move->ntouch;
96 state->maxtouch = move->ntouch;
97 state->active = 0;
98 }
99 return 0;
100}
1010
=== removed file 'src/gestures-touch.c'
--- src/gestures-touch.c 2011-04-04 17:27:38 +0000
+++ src/gestures-touch.c 1970-01-01 00:00:00 +0000
@@ -1,98 +0,0 @@
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-recognizer.h"
24#include <math.h>
25#include <stdio.h>
26
27static const int getype[DIM_TOUCH + 1] = {
28 -1,
29 GRAIL_TYPE_TOUCH1,
30 GRAIL_TYPE_TOUCH2,
31 GRAIL_TYPE_TOUCH3,
32 GRAIL_TYPE_TOUCH4,
33 GRAIL_TYPE_TOUCH5,
34};
35
36int gru_touch(struct grail *ge,
37 const struct utouch_frame *frame)
38{
39 struct gesture_recognizer *gru = ge->gru;
40 struct combo_model *state = &gru->touch;
41 struct move_model *move = &gru->move;
42 if (frame->slot_revision != frame->prev->slot_revision) {
43 if (state->active) {
44 gru_end(ge, state->gid, move,
45 state->prop, state->nprop);
46 state->active = 0;
47 }
48 }
49 if (!state->active) {
50 int type = getype[move->ntouch];
51 if (type <= 0)
52 return 0;
53 state->gid = gin_gid_begin(ge, type, -PRIO_GESTURE, frame);
54 state->active = 1;
55 }
56 if (move->time - move->fm[FM_X].original_ms <= move->fm[FM_X].hold_ms)
57 return 0;
58 state->nprop = gin_add_contact_props(ge->gin, state->prop, frame);
59 gru_event(ge, state->gid, move, state->prop, state->nprop);
60 return 1;
61}
62
63int gru_wintouch(struct grail *ge,
64 const struct utouch_frame *frame)
65{
66 struct gesture_recognizer *gru = ge->gru;
67 struct combo_model *state = &gru->wintouch;
68 struct move_model *move = &gru->move;
69 if (frame->slot_revision != frame->prev->slot_revision) {
70 if (state->active && out_of_bounds(state, move)) {
71 gru_end(ge, state->gid, move,
72 state->prop, state->nprop);
73 state->active = 0;
74 }
75 }
76 if (!state->active) {
77 if (move->ntouch == 4) {
78 state->gid = gin_gid_begin(ge, GRAIL_TYPE_MTOUCH,
79 -PRIO_META, frame);
80 state->mintouch = 1;
81 state->maxtouch = 4;
82 state->active = 1;
83 } else if (move->ntouch == 3) {
84 state->gid = gin_gid_begin(ge, GRAIL_TYPE_ETOUCH,
85 -PRIO_ENV, frame);
86 state->mintouch = 1;
87 state->maxtouch = 3;
88 state->active = 1;
89 } else {
90 return 0;
91 }
92 }
93 if (move->time - move->fm[FM_X].original_ms <= move->fm[FM_X].hold_ms)
94 return 0;
95 state->nprop = gin_add_contact_props(ge->gin, state->prop, frame);
96 gru_event(ge, state->gid, move, state->prop, state->nprop);
97 return 1;
98}
990
=== modified file 'src/grail-api.c'
--- src/grail-api.c 2011-04-12 16:35:37 +0000
+++ src/grail-api.c 2011-04-27 19:43:23 +0000
@@ -30,104 +30,11 @@
30#include <errno.h>30#include <errno.h>
31#include <stdlib.h>31#include <stdlib.h>
3232
33#define DIM_FRAMES 100
34#define FRAME_RATE 100
35
36unsigned int grail_get_version(void)33unsigned int grail_get_version(void)
37{34{
38 return GRAIL_VERSION;35 return GRAIL_VERSION;
39}36}
4037static const float TIMEOUT_MS = 300;
41int grail_open(struct grail *ge, int fd)
42{
43 struct grail_impl *x;
44 struct stat fs;
45 int ret;
46
47 ret = fstat(fd, &fs);
48 if (ret)
49 return ret;
50
51 x = calloc(1, sizeof(*x));
52 if (!x)
53 return -ENOMEM;
54
55 if (!fs.st_rdev)
56 x->fptest = fdopen(fd, "r");
57
58 x->evemu = evemu_new(x->fptest ? "fptest" : 0);
59 if (!x->evemu) {
60 ret = -ENOMEM;
61 goto freemem;
62 }
63 if (x->fptest)
64 ret = evemu_read(x->evemu, x->fptest) <= 0;
65 else
66 ret = evemu_extract(x->evemu, fd);
67 if (ret)
68 goto freemem;
69 if (!utouch_frame_is_supported_mtdev(x->evemu)) {
70 ret = -ENODEV;
71 goto freemem;
72 }
73
74 if (!x->fptest) {
75 x->mtdev = mtdev_new_open(fd);
76 if (!x->mtdev) {
77 ret = -ENOMEM;
78 goto freemem;
79 }
80 }
81 x->fh = utouch_frame_new_engine(DIM_FRAMES, DIM_TOUCH, FRAME_RATE);
82 if (!x->fh) {
83 ret = -ENOMEM;
84 goto freedev;
85 }
86 ret = utouch_frame_init_mtdev(x->fh, x->evemu);
87 if (ret)
88 goto freeframe;
89
90 ge->impl = x;
91
92 ret = gin_init(ge);
93 if (ret)
94 goto freeframe;
95
96 ret = gru_init(ge);
97 if (ret)
98 goto freegin;
99
100 return 0;
101 freegin:
102 gin_destroy(ge);
103 freeframe:
104 utouch_frame_delete_engine(x->fh);
105 freedev:
106 if (x->mtdev)
107 mtdev_close_delete(x->mtdev);
108 freemem:
109 evemu_delete(x->evemu);
110 if (x->fptest)
111 fclose(x->fptest);
112 free(x);
113 ge->impl = 0;
114 return ret;
115}
116
117void grail_close(struct grail *ge, int fd)
118{
119 struct grail_impl *x = ge->impl;
120 gru_destroy(ge);
121 gin_destroy(ge);
122 utouch_frame_delete_engine(x->fh);
123 if (x->mtdev)
124 mtdev_close_delete(x->mtdev);
125 evemu_delete(x->evemu);
126 if (x->fptest)
127 fclose(x->fptest);
128 free(x);
129 ge->impl = 0;
130}
13138
132int grail_idle(struct grail *ge, int fd, int ms)39int grail_idle(struct grail *ge, int fd, int ms)
133{40{
@@ -154,6 +61,11 @@
154 return ge->impl->touch;61 return ge->impl->touch;
155}62}
15663
64const struct grail_frame *grail_get_gesture_frame(const struct grail *ge)
65{
66 return ge->impl->frame;
67}
68
157static void flush_events(struct grail *ge)69static void flush_events(struct grail *ge)
158{70{
159 struct grail_impl *impl = ge->impl;71 struct grail_impl *impl = ge->impl;
@@ -219,7 +131,7 @@
219 struct gesture_inserter *gin = ge->gin;131 struct gesture_inserter *gin = ge->gin;
220132
221 return grail_mask_count(gin->used, sizeof(gin->used)) == 0 &&133 return grail_mask_count(gin->used, sizeof(gin->used)) == 0 &&
222 frame->time - frame->mod_time > gru->move.fm[FM_X].hold_ms;134 frame->time - frame->mod_time > TIMEOUT_MS;
223}135}
224136
225static void report_frame(struct grail *ge,137static void report_frame(struct grail *ge,
@@ -227,9 +139,13 @@
227 const struct input_event *syn)139 const struct input_event *syn)
228{140{
229 struct grail_impl *impl = ge->impl;141 struct grail_impl *impl = ge->impl;
142 const struct grail_frame *frame;
230 struct grail_event gev;143 struct grail_event gev;
231144
145 frame = grail_pump_frame(ge, touch);
146
232 impl->touch = touch;147 impl->touch = touch;
148 impl->frame = frame;
233149
234 if (touch->num_active && !touch->prev->num_active) {150 if (touch->num_active && !touch->prev->num_active) {
235 impl->ongoing = 1;151 impl->ongoing = 1;
@@ -240,7 +156,7 @@
240 return;156 return;
241157
242 gin_frame_begin(ge, touch);158 gin_frame_begin(ge, touch);
243 gru_recognize(ge, touch);159 gru_recognize(ge, frame, touch);
244 gin_frame_end(ge, touch);160 gin_frame_end(ge, touch);
245161
246 if (!grailbuf_empty(&impl->gbuf))162 if (!grailbuf_empty(&impl->gbuf))
247163
=== modified file 'src/grail-bits.c'
--- src/grail-bits.c 2011-04-12 16:35:37 +0000
+++ src/grail-bits.c 2011-04-27 19:43:23 +0000
@@ -57,6 +57,15 @@
57 *a++ &= ~*b++;57 *a++ &= ~*b++;
58}58}
5959
60int grail_mask_inner(const grail_mask_t *a, const grail_mask_t *b, int bytes)
61{
62 int k;
63 for (k = 0; k < bytes; k++)
64 if (a[k] & b[k])
65 return 1;
66 return 0;
67}
68
60int grail_mask_count(const grail_mask_t *mask, int bytes)69int grail_mask_count(const grail_mask_t *mask, int bytes)
61{70{
62 int count = 0;71 int count = 0;
6372
=== modified file 'src/grail-frame.c'
--- src/grail-frame.c 2011-04-12 16:35:37 +0000
+++ src/grail-frame.c 2011-04-27 19:43:23 +0000
@@ -71,51 +71,26 @@
7171
72 slot->center.x = x;72 slot->center.x = x;
73 slot->center.y = y;73 slot->center.y = y;
74 slot->pivot = slot->center;
74 slot->velocity.x = 1000 * vx;75 slot->velocity.x = 1000 * vx;
75 slot->velocity.y = 1000 * vy;76 slot->velocity.y = 1000 * vy;
76 slot->radius2 = r2;77 slot->radius2 = r2;
77}78}
7879
79static void set_moveness_pivot_and_drag(struct grail_impl *impl,80static void set_transform(struct grail_impl *impl, struct grail_element *slot,
80 struct grail_element *slot,81 double ds, double dc)
81 double ds, double dc)
82{82{
83 const struct grail_element *pslot = slot->prev;83 const struct grail_element *pslot = slot->prev;
84 double mx = slot->center.x - pslot->center.x;84 double mx = slot->center.x - pslot->center.x;
85 double my = slot->center.y - pslot->center.y;85 double my = slot->center.y - pslot->center.y;
86 float *T = slot->transform;86 float *T = slot->transform;
8787
88 slot->moveness = 1;
89 slot->pivot = pslot->center;
90
91 if (slot->num_touches > 1) {
92 double wx = (1 - dc) * mx + ds * my;
93 double wy = (1 - dc) * my - ds * mx;
94 double w2 = wx * wx + wy * wy;
95 if (w2 > 0) {
96 double s = sqrt(pslot->radius2 / w2);
97 double q = (mx * mx + my * my) / w2;
98 if (s < q) {
99 slot->moveness = 1 - s / q;
100 slot->pivot.x += s * wx;
101 slot->pivot.y += s * wy;
102 } else {
103 slot->moveness = 0;
104 slot->pivot.x += q * wx;
105 slot->pivot.y += q * wy;
106 }
107 }
108 }
109
110 mx *= slot->moveness;
111 my *= slot->moveness;
112
113 T[0] = dc;88 T[0] = dc;
114 T[1] = ds;89 T[1] = ds;
115 T[2] = (1 - dc) * slot->pivot.x - ds * slot->pivot.y + mx;90 T[2] = mx;
116 T[3] = -ds;91 T[3] = -ds;
117 T[4] = dc;92 T[4] = dc;
118 T[5] = (1 - dc) * slot->pivot.y + ds * slot->pivot.x + my;93 T[5] = my;
11994
120 slot->drag.x = pslot->drag.x + mx;95 slot->drag.x = pslot->drag.x + mx;
121 slot->drag.y = pslot->drag.y + my;96 slot->drag.y = pslot->drag.y + my;
@@ -134,7 +109,6 @@
134 set_center_velocity_and_radius(impl, slot);109 set_center_velocity_and_radius(impl, slot);
135 T[0] = T[4] = 1;110 T[0] = T[4] = 1;
136 T[1] = T[2] = T[3] = T[5] = 0;111 T[1] = T[2] = T[3] = T[5] = 0;
137 slot->pivot = slot->center;
138 slot->drag.x = 0;112 slot->drag.x = 0;
139 slot->drag.y = 0;113 slot->drag.y = 0;
140 slot->scale2 = 1;114 slot->scale2 = 1;
@@ -153,7 +127,7 @@
153 slot->active_mask = pslot->active_mask;127 slot->active_mask = pslot->active_mask;
154128
155 set_center_velocity_and_radius(impl, slot);129 set_center_velocity_and_radius(impl, slot);
156 set_moveness_pivot_and_drag(impl, slot, ds, dc);130 set_transform(impl, slot, ds, dc);
157131
158 slot->scale2 = pslot->scale2 * (ds * ds + dc * dc);132 slot->scale2 = pslot->scale2 * (ds * ds + dc * dc);
159 slot->angle = pslot->angle + ds / dc; /* atan2(ds, dc) */133 slot->angle = pslot->angle + ds / dc; /* atan2(ds, dc) */
@@ -175,8 +149,6 @@
175 slot->radius2 = pslot->radius2;149 slot->radius2 = pslot->radius2;
176 T[0] = T[4] = 1;150 T[0] = T[4] = 1;
177 T[1] = T[2] = T[3] = T[5] = 0;151 T[1] = T[2] = T[3] = T[5] = 0;
178 slot->moveness = 1;
179 slot->pivot = pslot->pivot;
180 slot->drag = pslot->drag;152 slot->drag = pslot->drag;
181 slot->scale2 = pslot->scale2;153 slot->scale2 = pslot->scale2;
182 slot->angle = pslot->angle;154 slot->angle = pslot->angle;
@@ -308,6 +280,141 @@
308 set_slot_multi(impl, slots[n++], frame, touch);280 set_slot_multi(impl, slots[n++], frame, touch);
309}281}
310282
283/**
284 * Determine the pivot point where the transformation matrix has zero
285 * translation. Thus, T1 is equal to:
286 *
287 * T1: [ a -b 0 ]
288 * [ b a 0 ]
289 * [ 0 0 1 ]
290 *
291 * Using the equation noted in the comment for set_pivot we can solve for P1.
292 */
293static inline int center_of_rotation(float a, float b, float c, float d,
294 float x0, float y0, float *x1, float *y1)
295{
296 float div = a*a - 2*a + b*b + 1;
297
298 if (div == 0)
299 return 0;
300
301 *x1 = (a*a*x0 - a*(2*x0+c) + b*b*x0 - b*d + c + x0) / div;
302 *y1 = (a*a*y0 - a*(2*y0+d) + b*b*y0 + b*c + d + y0) / div;
303
304 return 1;
305}
306
307/**
308 * Determine a new pivot point and modify the transformation matrix to
309 * match.
310 *
311 * For any given point q that is transformed by a 2D affine transformation
312 * matrix T about pivot point P the new point q' may be determined by the
313 * following equation:
314 *
315 * q' = T * (q - P) + P
316 *
317 * T and P are dependent, so we can modify one and find a new value for the
318 * other. We will label the original T and P as T0 and P0, and the new values
319 * will be labeled T1 and P1. We can find new values by solving the following
320 * equation:
321 *
322 * q' = T0 * (q - P0) + P0 = T1 * (q - P1) + P1
323 *
324 * In the calculations below, we use standard variables for the scalar values
325 * that make up T0 and P0:
326 *
327 * T0: [ a -b c0 ] P0: [ x0 ]
328 * [ b a d0 ] [ y0 ]
329 * [ 0 0 1 ] [ 0 ]
330 *
331 * Note that rotation and scaling are independent of the pivot point, so
332 * a0 == a1 and b0 == b1. Thus, the variable names are left as just a and b.
333 */
334static void set_pivot(struct grail_element *e, enum grail_pivot_type type)
335{
336 float *T = e->transform;
337 float a = T[0];
338 float b = T[3];
339 float c0 = T[2];
340 float d0 = T[5];
341 float x0 = e->pivot.x;
342 float y0 = e->pivot.y;
343 float x1;
344 float y1;
345
346 switch (type) {
347 case GRAIL_CENTROID:
348 /* Grail computation is performed on the centroid already. */
349 break;
350
351 case GRAIL_CENTER_OF_ROTATION:
352 /* If this fails, transformation is pure translation. We can't
353 * do anything in this case. */
354 if (center_of_rotation(a, b, c0, d0, x0, y0, &x1, &y1)) {
355 T[2] = T[5] = 0;
356 e->pivot.x = x1;
357 e->pivot.y = y1;
358 }
359 break;
360
361 /**
362 * We define an approximation of the convex hull of the touches as a
363 * circle centered at the centroid of the touch points and with a radius
364 * equal to the average distance of each touch point to the centroid. We
365 * then determine the pivot point within the circle that minimizes
366 * translation. To accomplish this, first determine the center of
367 * rotation point as above. Then check if it is within the confining
368 * circle. If it is, then stop. Otherwise, determine the intersection of
369 * the circle and the line defined by the centroid of the touch points
370 * and the center of rotation point. The intersection is the new pivot.
371 *
372 * Lastly, determine the new translation values c1 and d1 in the T1
373 * transformation matrix. To do this, we set P1 as:
374 *
375 * P1: [ x1 ]
376 * [ y1 ]
377 * [ 0 ]
378 *
379 * and then we solve the equation noted above for T1.
380 */
381 case GRAIL_CONVEX_HULL_RADIUS: {
382 float d2;
383 float scale;
384
385 /* If this fails, transformation is pure translation. We can't
386 * do anything in this case, and the pivot point will remain at
387 * the centroid which matches the criteria. */
388 if (!center_of_rotation(a, b, c0, d0, x0, y0, &x1, &y1))
389 break;
390
391 /* If the center of rotation falls within the circle, we've
392 * reached an optimal state. */
393 d2 = (x1 - x0)*(x1-x0) + (y1 - y0)*(y1-y0);
394 if (d2 <= e->radius2) {
395 T[2] = T[5] = 0;
396 e->pivot.x = x1;
397 e->pivot.y = y1;
398 break;
399 }
400
401 /* Intersect line from centroid to center of rotation to find
402 * the best pivot point. */
403 scale = sqrtf(e->radius2 / d2);
404 x1 = x0 + (x1 - x0) * scale;
405 y1 = y0 + (y1 - y0) * scale;
406
407 /* Compute the new translation values by solving the equation
408 * above. */
409 T[2] = a*(x1 - x0) + b*(y0 - y1) + c0 + x0 - x1;
410 T[5] = a*(y1 - y0) + b*(y1 - y0) + d0 + y0 - y1;
411 e->pivot.x = x1;
412 e->pivot.y = y1;
413 break;
414 }
415 }
416}
417
311static void collect_transforms(struct grail_impl *impl,418static void collect_transforms(struct grail_impl *impl,
312 struct grail_frame *frame,419 struct grail_frame *frame,
313 const struct utouch_frame *touch)420 const struct utouch_frame *touch)
@@ -326,22 +433,20 @@
326 if (!s->num_touches)433 if (!s->num_touches)
327 continue;434 continue;
328435
436 set_pivot(s, ctl->pivot_type);
437
329 dt = touch->time - s->start_time;438 dt = touch->time - s->start_time;
330 if (dt > ctl->glue_ms) {439 if (dt > ctl->glue_ms) {
331 unsigned int mask = s->active_mask;440 unsigned int mask = s->active_mask;
332441
333 if (s->moveness > ctl->thresh_drag) {442 if (fabs(s->drag.x) > dx)
334 if (fabs(s->drag.x) > dx)443 mask |= GRAIL_EXPECT_X;
335 mask |= GRAIL_EXPECT_X;444 if (fabs(s->drag.y) > dy)
336 if (fabs(s->drag.y) > dy)445 mask |= GRAIL_EXPECT_Y;
337 mask |= GRAIL_EXPECT_Y;446 if (fabs(s->scale2 - 1) > ds2)
338 }447 mask |= GRAIL_EXPECT_SCALE;
339 if (s->moveness < ctl->thresh_scale) {448 if (fabs(s->angle) > ctl->bar_angle)
340 if (fabs(s->scale2 - 1) > ds2)449 mask |= GRAIL_EXPECT_ANGLE;
341 mask |= GRAIL_EXPECT_SCALE;
342 if (fabs(s->angle) > ctl->bar_angle)
343 mask |= GRAIL_EXPECT_ANGLE;
344 }
345450
346 s->active_mask = mask;451 s->active_mask = mask;
347452
@@ -365,10 +470,16 @@
365 const struct utouch_frame *touch)470 const struct utouch_frame *touch)
366{471{
367 struct grail_impl *impl = ge->impl;472 struct grail_impl *impl = ge->impl;
368 struct grail_frame *frame = impl->frames[impl->nextframe];473 struct grail_frame *frame;
369 const struct grail_frame *prev = frame->prev;474 const struct grail_frame *prev;
370 int i;475 int i;
371476
477 if (!impl->frames)
478 return 0;
479
480 frame = impl->frames[impl->nextframe];
481 prev = frame->prev;
482
372 if (touch->slot_revision == touch->prev->slot_revision &&483 if (touch->slot_revision == touch->prev->slot_revision &&
373 !prev->num_ongoing)484 !prev->num_ongoing)
374 return 0;485 return 0;
375486
=== removed file 'src/grail-gestures.c'
--- src/grail-gestures.c 2011-04-12 16:35:37 +0000
+++ src/grail-gestures.c 1970-01-01 00:00:00 +0000
@@ -1,210 +0,0 @@
1/*****************************************************************************
2 *
3 * grail - Gesture Recognition And Instantiation Library
4 *
5 * Copyright (C) 2010-2011 Canonical Ltd.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ****************************************************************************/
21
22#include "grail-recognizer.h"
23#include "grail-impl.h"
24#include <math.h>
25
26static const float FM_SN[DIM_FM] = { 1000, 1000, 1000, 1000 };
27static const float FM_BAR[DIM_FM] = { 50, 50, 50, 50 };
28static const grail_time_t FM_HOLD_MS[DIM_FM] = { 60, 60, 60, 60 };
29static const grail_time_t FM_BAR_MS[DIM_FM] = { 300, 300, 500, 500 };
30static const grail_time_t SAMPLE_MS = 10;
31static const float EPS = 1e-3;
32
33static void compute_position(float *x, float *y,
34 const struct utouch_frame *frame)
35{
36 int i, n = frame->num_active;
37 *x = 0;
38 *y = 0;
39 if (n < 1)
40 return;
41 for (i = 0; i < n; i++) {
42 const struct utouch_contact *t = frame->active[i];
43 *x += t->x;
44 *y += t->y;
45 }
46 *x /= n;
47 *y /= n;
48}
49
50static float compute_radius(float x, float y,
51 const struct utouch_frame *frame)
52{
53 int i, n = frame->num_active;
54 float r = 0, r2 = 0;
55 if (n < 2)
56 return r;
57 for (i = 0; i < n; i++) {
58 const struct utouch_contact *t = frame->active[i];
59 float dx = t->x - x;
60 float dy = t->y - y;
61 r2 += dx * dx + dy * dy;
62 }
63 r2 /= n;
64 r = sqrt(r2);
65 return r;
66}
67
68static float compute_rotation(float x, float y, float r,
69 const struct utouch_frame *frame)
70{
71 int i, n = frame->num_active;
72 float da = 0, darc2 = 0;
73 if (n < 2)
74 return da;
75 for (i = 0; i < n; i++) {
76 const struct utouch_contact *t = frame->active[i];
77 const struct utouch_contact *ot = t->prev;
78 float dx = t->x - x;
79 float dy = t->y - y;
80 float mx = t->x - ot->x;
81 float my = t->y - ot->y;
82 darc2 += dx * my - dy * mx;
83 }
84 darc2 /= n;
85 da = darc2 / (r * r);
86 return da;
87}
88
89static void move_reset(struct move_model *m, int i, float x, grail_time_t t)
90{
91 struct filter_model *fm = &m->fm[i];
92 fm->raw_delta = 0;
93 fm->action_delta = 0;
94 fm->velocity = 0;
95 fm->value = x;
96 fm->original = x;
97 fm->original_ms = t;
98 fm->sample = x;
99 fm->sample_ms = t;
100 m->tickle &= ~(1 << i);
101 m->active &= ~(1 << i);
102 m->timeout &= ~(1 << i);
103}
104
105static void move_update(struct move_model *m, int i, float x, grail_time_t t)
106{
107 struct filter_model *fm = &m->fm[i];
108 float dt = t - fm->sample_ms;
109 fm->raw_delta = x - fm->value;
110 fm->action_delta = fm->raw_delta;
111 fm->value = x;
112 if (dt > SAMPLE_MS) {
113 fm->velocity = (x - fm->sample) / dt;
114 fm->sample = x;
115 fm->sample_ms = t;
116 }
117 if (fabs(fm->raw_delta) > EPS)
118 m->tickle |= (1 << i);
119 else
120 m->tickle &= ~(1 << i);
121 if (m->active & (1 << i))
122 return;
123 fm->action_delta = 0;
124 if (fabs(x - fm->original) > fm->bar) {
125 if (t - fm->original_ms > fm->hold_ms) {
126 m->active |= (1 << i);
127 fm->action_delta = x - fm->original;
128 }
129 } else if (t - fm->original_ms > fm->bar_ms) {
130 m->timeout |= (1 << i);
131 }
132}
133
134void gru_init_motion(struct grail *ge)
135{
136 struct utouch_surface *s = utouch_frame_get_surface(ge->impl->fh);
137 struct gesture_recognizer *gru = ge->gru;
138 struct move_model *m = &gru->move;
139 float D[DIM_FM];
140 int i;
141 D[FM_X] = s->mapped_max_x - s->mapped_min_x;
142 D[FM_Y] = s->mapped_max_y - s->mapped_min_y;
143 D[FM_R] = sqrt(D[FM_X] * D[FM_X] + D[FM_Y] * D[FM_Y]);
144 D[FM_A] = 2 * M_PI;
145 for (i = 0; i < DIM_FM; i++) {
146 m->fm[i].fuzz = D[i] / FM_SN[i];
147 m->fm[i].bar = D[i] / FM_BAR[i];
148 m->fm[i].hold_ms = FM_HOLD_MS[i];
149 m->fm[i].bar_ms = FM_BAR_MS[i];
150 }
151}
152
153void gru_motion(struct grail *ge,
154 const struct utouch_frame *frame)
155{
156 const struct utouch_surface *s = utouch_frame_get_surface(ge->impl->fh);
157 struct gesture_recognizer *gru = ge->gru;
158 struct move_model *m = &gru->move;
159 grail_time_t t = frame->time;
160 float x, y, r, a;
161
162 compute_position(&x, &y, frame);
163 if (frame->prev->revision != frame->revision) {
164 r = compute_radius(x, y, frame);
165 a = 0;
166 move_reset(m, FM_X, x, t);
167 move_reset(m, FM_Y, y, t);
168 move_reset(m, FM_R, r, t);
169 move_reset(m, FM_A, a, t);
170 m->single = 0;
171 m->multi = 0;
172 } else if (frame->num_active < 2) {
173 r = 0;
174 a = 0;
175 move_update(m, FM_X, x, t);
176 move_update(m, FM_Y, y, t);
177 move_reset(m, FM_R, r, t);
178 move_reset(m, FM_A, a, t);
179 m->single = 1;
180 m->multi = 0;
181 } else {
182 r = compute_radius(x, y, frame);
183 a = m->fm[FM_A].value;
184 if (!s->is_semi_mt)
185 a += compute_rotation(x, y, r, frame);
186 move_update(m, FM_X, x, t);
187 move_update(m, FM_Y, y, t);
188 move_update(m, FM_R, r, t);
189 move_update(m, FM_A, a, t);
190 m->single = 0;
191 m->multi = 1;
192 }
193 m->ntouch = frame->num_active;
194 m->time = t;
195}
196
197void gru_event(struct grail *ge, int gid,
198 const struct move_model *m,
199 const grail_prop_t *prop, int nprop)
200{
201 gin_gid_event(ge, gid, m->fm[FM_X].value, m->fm[FM_Y].value, m->ntouch,
202 prop, nprop, 0);
203}
204
205void gru_end(struct grail *ge, int gid, const struct move_model *m,
206 const grail_prop_t *prop, int nprop)
207{
208 gin_gid_end(ge, gid, m->fm[FM_X].value, m->fm[FM_Y].value, m->ntouch,
209 prop, nprop);
210}
2110
=== removed file 'src/grail-gestures.h'
--- src/grail-gestures.h 2011-04-12 16:35:37 +0000
+++ src/grail-gestures.h 1970-01-01 00:00:00 +0000
@@ -1,115 +0,0 @@
1/*****************************************************************************
2 *
3 * grail - Gesture Recognition And Instantiation Library
4 *
5 * Copyright (C) 2010-2011 Canonical Ltd.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ****************************************************************************/
21
22#ifndef _GRAIL_GESTURES_H
23#define _GRAIL_GESTURES_H
24
25#include "grail-inserter.h"
26
27#define PRIO_POINTER 1
28#define PRIO_GESTURE 2
29#define PRIO_ENV 3
30#define PRIO_META 4
31#define PRIO_TAP 5
32
33#define DIM_FM 4
34
35#define FM_X 0
36#define FM_Y 1
37#define FM_R 2
38#define FM_A 3
39
40struct filter_model {
41 float raw_delta;
42 float action_delta;
43 float velocity;
44 float value;
45 float original;
46 float sample;
47 float fuzz;
48 float bar;
49 grail_time_t original_ms;
50 grail_time_t sample_ms;
51 grail_time_t hold_ms;
52 grail_time_t bar_ms;
53};
54
55struct move_model {
56 struct filter_model fm[DIM_FM];
57 int tickle, active, timeout;
58 int single, multi, ntouch;
59 grail_time_t time;
60};
61
62void gru_init_motion(struct grail *ge);
63void gru_motion(struct grail *ge,
64 const struct utouch_frame *frame);
65void gru_event(struct grail *ge, int gid,
66 const struct move_model *move,
67 const grail_prop_t *prop, int nprop);
68void gru_end(struct grail *ge, int gid,
69 const struct move_model *move,
70 const grail_prop_t *prop, int nprop);
71
72struct combo_model {
73 int active, gid;
74 int mintouch, maxtouch;
75 int nprop;
76 grail_prop_t prop[DIM_GRAIL_PROP];
77};
78
79int gru_touch(struct grail *ge,
80 const struct utouch_frame *frame);
81int gru_drag(struct grail *ge,
82 const struct utouch_frame *frame);
83int gru_pinch(struct grail *ge,
84 const struct utouch_frame *frame);
85int gru_rotate(struct grail *ge,
86 const struct utouch_frame *frame);
87
88static inline int out_of_bounds(const struct combo_model *s,
89 const struct move_model *m)
90{
91 return m->ntouch < s->mintouch || m->ntouch > s->maxtouch;
92}
93
94int gru_wintouch(struct grail *ge,
95 const struct utouch_frame *frame);
96int gru_windrag(struct grail *ge,
97 const struct utouch_frame *frame);
98int gru_winpinch(struct grail *ge,
99 const struct utouch_frame *frame);
100int gru_winrotate(struct grail *ge,
101 const struct utouch_frame *frame);
102
103struct tapping_model {
104 grail_time_t start;
105 int mintouch, maxtouch;
106 int active, gid, tap;
107 int nprop;
108 grail_prop_t prop[DIM_GRAIL_PROP];
109};
110
111int gru_tapping(struct grail *ge,
112 const struct utouch_frame *frame);
113
114#endif
115
1160
=== modified file 'src/grail-impl.h'
--- src/grail-impl.h 2011-04-12 16:35:37 +0000
+++ src/grail-impl.h 2011-04-27 19:43:23 +0000
@@ -82,6 +82,7 @@
82 unsigned int frame_size;82 unsigned int frame_size;
83 unsigned int slot_size;83 unsigned int slot_size;
84 struct grail_frame **frames;84 struct grail_frame **frames;
85 const struct grail_frame *frame;
85};86};
8687
87#endif88#endif
8889
=== modified file 'src/grail-init.c'
--- src/grail-init.c 2011-04-12 16:35:37 +0000
+++ src/grail-init.c 2011-04-27 19:43:23 +0000
@@ -32,8 +32,6 @@
32 return 0;32 return 0;
3333
34 c->glue_ms = 60;34 c->glue_ms = 60;
35 c->thresh_drag = 0.8;
36 c->thresh_scale = 0.2;
37 c->bar_x = 0.03;35 c->bar_x = 0.03;
38 c->bar_y = 0.03;36 c->bar_y = 0.03;
39 c->bar_scale = 0.3;37 c->bar_scale = 0.3;
4038
=== modified file 'src/grail-inserter.c'
--- src/grail-inserter.c 2011-04-12 16:35:37 +0000
+++ src/grail-inserter.c 2011-04-27 19:43:23 +0000
@@ -37,18 +37,6 @@
37 return -1;37 return -1;
38}38}
3939
40static int mask_overlap(const grail_mask_t *a, const grail_mask_t *b,
41 int bytes)
42{
43 int i;
44
45 for (i = 0; i < bytes; i++)
46 if (a[i] & b[i])
47 return 1;
48
49 return 0;
50}
51
52// todo: spanning tree for multi-user case40// todo: spanning tree for multi-user case
53static void setup_new_gestures(struct grail *ge,41static void setup_new_gestures(struct grail *ge,
54 const struct utouch_frame *frame)42 const struct utouch_frame *frame)
@@ -157,15 +145,6 @@
157145
158 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {146 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
159 struct slot_state *s = &gin->state[i];147 struct slot_state *s = &gin->state[i];
160 if (!s->timeout)
161 continue;
162 if (mask_overlap(keep, s->span, sizeof(keep)))
163 continue;
164 gin_gid_discard(ge, s->id);
165 }
166
167 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
168 struct slot_state *s = &gin->state[i];
169 struct gesture_event ev;148 struct gesture_event ev;
170 grail_mask_set(gin->types, s->type);149 grail_mask_set(gin->types, s->type);
171 if (s->priority < hold[s->slice] && !s->sent)150 if (s->priority < hold[s->slice] && !s->sent)
@@ -202,7 +181,6 @@
202 s->priority = priority;181 s->priority = priority;
203 s->slice = 0;182 s->slice = 0;
204 }183 }
205 s->timeout = 0;
206 s->sent = 0;184 s->sent = 0;
207 s->id = gin->gestureid++ & MAX_GESTURE_ID;185 s->id = gin->gestureid++ & MAX_GESTURE_ID;
208 s->status = GRAIL_STATUS_BEGIN;186 s->status = GRAIL_STATUS_BEGIN;
@@ -230,13 +208,6 @@
230 grail_mask_set(gin->unused, i);208 grail_mask_set(gin->unused, i);
231}209}
232210
233void gin_gid_timeout(struct grail *ge, int gid)
234{
235 int i = find_gslot(ge->gin, gid);
236 if (i >= 0)
237 ge->gin->state[i].timeout = 1;
238}
239
240void gin_gid_event(struct grail *ge, int gid,211void gin_gid_event(struct grail *ge, int gid,
241 float x, float y, int ntouch,212 float x, float y, int ntouch,
242 const grail_prop_t *prop, int nprop,213 const grail_prop_t *prop, int nprop,
@@ -297,7 +268,4 @@
297 s->mapped_min_y = tmin->y;268 s->mapped_min_y = tmin->y;
298 s->mapped_max_x = tmax->x;269 s->mapped_max_x = tmax->x;
299 s->mapped_max_y = tmax->y;270 s->mapped_max_y = tmax->y;
300
301 if (ge->gru)
302 gru_init_motion(ge);
303}271}
304272
=== modified file 'src/grail-inserter.h'
--- src/grail-inserter.h 2011-04-12 16:35:37 +0000
+++ src/grail-inserter.h 2011-04-27 19:43:23 +0000
@@ -37,7 +37,6 @@
37 int type;37 int type;
38 int priority;38 int priority;
39 int slice;39 int slice;
40 int timeout;
41 int sent;40 int sent;
42 int id;41 int id;
43 int status;42 int status;
@@ -80,7 +79,6 @@
80int gin_gid_begin(struct grail *ge, int type, int priority,79int gin_gid_begin(struct grail *ge, int type, int priority,
81 const struct utouch_frame *frame);80 const struct utouch_frame *frame);
82void gin_gid_discard(struct grail *ge, int gid);81void gin_gid_discard(struct grail *ge, int gid);
83void gin_gid_timeout(struct grail *ge, int gid);
8482
85void gin_gid_event(struct grail *ge, int gid,83void gin_gid_event(struct grail *ge, int gid,
86 float x, float y, int ntouch,84 float x, float y, int ntouch,
8785
=== modified file 'src/grail-legacy.c'
--- src/grail-legacy.c 2011-04-12 16:35:37 +0000
+++ src/grail-legacy.c 2011-04-27 19:43:23 +0000
@@ -31,6 +31,110 @@
3131
32#ifndef GRAIL_NO_LEGACY_ABI32#ifndef GRAIL_NO_LEGACY_ABI
3333
34#define DIM_FRAMES 100
35#define FRAME_RATE 100
36
37int grail_open(struct grail *ge, int fd)
38{
39 struct grail_impl *x;
40 struct stat fs;
41 int ret;
42
43 ret = fstat(fd, &fs);
44 if (ret)
45 return ret;
46
47 x = calloc(1, sizeof(*x));
48 if (!x)
49 return -ENOMEM;
50
51 if (!fs.st_rdev)
52 x->fptest = fdopen(fd, "r");
53
54 x->evemu = evemu_new(x->fptest ? "fptest" : 0);
55 if (!x->evemu) {
56 ret = -ENOMEM;
57 goto freemem;
58 }
59 if (x->fptest)
60 ret = evemu_read(x->evemu, x->fptest) <= 0;
61 else
62 ret = evemu_extract(x->evemu, fd);
63 if (ret)
64 goto freemem;
65 if (!utouch_frame_is_supported_mtdev(x->evemu)) {
66 ret = -ENODEV;
67 goto freemem;
68 }
69
70 if (!x->fptest) {
71 x->mtdev = mtdev_new_open(fd);
72 if (!x->mtdev) {
73 ret = -ENOMEM;
74 goto freemem;
75 }
76 }
77 x->fh = utouch_frame_new_engine(DIM_FRAMES, DIM_TOUCH, FRAME_RATE);
78 if (!x->fh) {
79 ret = -ENOMEM;
80 goto freedev;
81 }
82 ret = utouch_frame_init_mtdev(x->fh, x->evemu);
83 if (ret)
84 goto freeframe;
85
86 ret = create_grail2(x, x->fh, DIM_FRAMES, NULL,
87 GRAIL_VERSION,
88 sizeof(struct grail_control),
89 sizeof(struct grail_frame),
90 sizeof(struct grail_element));
91 if (ret)
92 goto freeframe;
93
94 ge->impl = x;
95
96 ret = gin_init(ge);
97 if (ret)
98 goto freegrail2;
99
100 ret = gru_init(ge);
101 if (ret)
102 goto freegin;
103
104 return 0;
105 freegin:
106 gin_destroy(ge);
107 freegrail2:
108 destroy_grail2(x);
109 freeframe:
110 utouch_frame_delete_engine(x->fh);
111 freedev:
112 if (x->mtdev)
113 mtdev_close_delete(x->mtdev);
114 freemem:
115 evemu_delete(x->evemu);
116 if (x->fptest)
117 fclose(x->fptest);
118 free(x);
119 ge->impl = 0;
120 return ret;
121}
122
123void grail_close(struct grail *ge, int fd)
124{
125 struct grail_impl *x = ge->impl;
126 gru_destroy(ge);
127 gin_destroy(ge);
128 destroy_grail2(x);
129 utouch_frame_delete_engine(x->fh);
130 if (x->mtdev)
131 mtdev_close_delete(x->mtdev);
132 evemu_delete(x->evemu);
133 if (x->fptest)
134 fclose(x->fptest);
135 free(x);
136 ge->impl = 0;
137}
34void grail_filter_abs_events(struct grail *ge, int usage)138void grail_filter_abs_events(struct grail *ge, int usage)
35{139{
36 struct grail_impl *x = ge->impl;140 struct grail_impl *x = ge->impl;
37141
=== modified file 'src/grail-recognizer.c'
--- src/grail-recognizer.c 2011-04-12 16:35:37 +0000
+++ src/grail-recognizer.c 2011-04-27 19:43:23 +0000
@@ -23,6 +23,178 @@
23#include <string.h>23#include <string.h>
24#include <malloc.h>24#include <malloc.h>
25#include <errno.h>25#include <errno.h>
26#include <math.h>
27
28static const float TAP_TIME_MS = 300;
29static const int MAX_TOUCH_GESTURE = 5;
30
31static void touch_props(const struct gesture_inserter *gin,
32 struct combo_model *s, const struct grail_element *m,
33 const struct utouch_frame *frame)
34{
35 s->nprop = 0;
36}
37
38static void drag_props(const struct gesture_inserter *gin,
39 struct combo_model *s, const struct grail_element *m,
40 const struct utouch_frame *frame)
41{
42 s->prop[GRAIL_PROP_DRAG_DX] = m->drag.x - m->prev->drag.x;
43 s->prop[GRAIL_PROP_DRAG_DY] = m->drag.y - m->prev->drag.y;
44 s->prop[GRAIL_PROP_DRAG_VX] = m->velocity.x;
45 s->prop[GRAIL_PROP_DRAG_VY] = m->velocity.y;
46 s->prop[GRAIL_PROP_DRAG_X] = m->drag.x;
47 s->prop[GRAIL_PROP_DRAG_Y] = m->drag.y;
48 s->nprop = 6;
49}
50
51static void pinch_props(const struct gesture_inserter *gin,
52 struct combo_model *s, const struct grail_element *m,
53 const struct utouch_frame *frame)
54{
55 s->prop[GRAIL_PROP_PINCH_DR] =
56 sqrt(m->radius2) - sqrt(m->prev->radius2);
57 s->prop[GRAIL_PROP_PINCH_VR] = 0;
58 s->prop[GRAIL_PROP_PINCH_R] = sqrt(m->radius2);
59 s->nprop = 3;
60}
61
62static void rotate_props(const struct gesture_inserter *gin,
63 struct combo_model *s, const struct grail_element *m,
64 const struct utouch_frame *frame)
65{
66 s->prop[GRAIL_PROP_ROTATE_DA] = m->angle - m->prev->angle;
67 s->prop[GRAIL_PROP_ROTATE_VA] = 0;
68 s->prop[GRAIL_PROP_ROTATE_A] = m->angle;
69 s->nprop = 3;
70}
71
72static void tap_props(const struct gesture_inserter *gin,
73 struct combo_model *s, const struct grail_element *m,
74 const struct utouch_frame *frame)
75{
76 s->prop[GRAIL_PROP_TAP_DT] = frame->time - s->start;
77 s->prop[GRAIL_PROP_TAP_X] = m->center.x;
78 s->prop[GRAIL_PROP_TAP_Y] = m->center.y;
79 s->nprop = 3;
80}
81
82static const struct gesture_handler touch_handler = {
83 GRAIL_EXPECT_X | GRAIL_EXPECT_Y,
84 {
85 { -1, 0, 0, 0 },
86 { GRAIL_TYPE_TOUCH1, 1, 1, PRIO_GESTURE },
87 { GRAIL_TYPE_TOUCH2, 2, 2, PRIO_GESTURE },
88 { GRAIL_TYPE_TOUCH3, 3, 3, PRIO_GESTURE },
89 { GRAIL_TYPE_TOUCH4, 4, 4, PRIO_GESTURE },
90 { GRAIL_TYPE_TOUCH5, 5, 5, PRIO_GESTURE }
91 },
92 touch_props
93};
94
95static const struct gesture_handler drag_handler = {
96 GRAIL_EXPECT_X | GRAIL_EXPECT_Y,
97 {
98 { -1, 0, 0, 0 },
99 { GRAIL_TYPE_DRAG1, 1, 1, PRIO_GESTURE },
100 { GRAIL_TYPE_DRAG2, 2, 2, PRIO_GESTURE },
101 { GRAIL_TYPE_DRAG3, 3, 3, PRIO_GESTURE },
102 { GRAIL_TYPE_DRAG4, 4, 4, PRIO_GESTURE },
103 { GRAIL_TYPE_DRAG5, 5, 5, PRIO_GESTURE }
104 },
105 drag_props
106};
107
108static const struct gesture_handler pinch_handler = {
109 GRAIL_EXPECT_SCALE,
110 {
111 { -1, 0, 0, 0 },
112 { -1, 0, 0, 0 },
113 { GRAIL_TYPE_PINCH2, 2, 2, PRIO_GESTURE },
114 { GRAIL_TYPE_PINCH3, 3, 3, PRIO_GESTURE },
115 { GRAIL_TYPE_PINCH4, 4, 4, PRIO_GESTURE },
116 { GRAIL_TYPE_PINCH5, 5, 5, PRIO_GESTURE }
117 },
118 pinch_props
119};
120
121static const struct gesture_handler rotate_handler = {
122 GRAIL_EXPECT_ANGLE,
123 {
124 { -1, 0, 0, 0 },
125 { -1, 0, 0, 0 },
126 { GRAIL_TYPE_ROTATE2, 2, 2, PRIO_GESTURE },
127 { GRAIL_TYPE_ROTATE3, 3, 3, PRIO_GESTURE },
128 { GRAIL_TYPE_ROTATE4, 4, 4, PRIO_GESTURE },
129 { GRAIL_TYPE_ROTATE5, 5, 5, PRIO_GESTURE }
130 },
131 rotate_props
132};
133
134static const struct gesture_handler tap_handler = {
135 GRAIL_EXPECT_MASK,
136 {
137 { -1, 0, 0, 0 },
138 { GRAIL_TYPE_TAP1, 1, 1, PRIO_TAP },
139 { GRAIL_TYPE_TAP2, 2, 2, PRIO_TAP },
140 { GRAIL_TYPE_TAP3, 3, 3, PRIO_TAP },
141 { GRAIL_TYPE_TAP4, 4, 4, PRIO_TAP },
142 { GRAIL_TYPE_TAP5, 5, 5, PRIO_TAP }
143 },
144 tap_props
145};
146
147static const struct gesture_handler wintouch_handler = {
148 GRAIL_EXPECT_X | GRAIL_EXPECT_Y,
149 {
150 { -1, 0, 0, 0 },
151 { -1, 0, 0, 0 },
152 { -1, 0, 0, 0 },
153 { GRAIL_TYPE_ETOUCH, 1, 3, PRIO_ENV },
154 { GRAIL_TYPE_MTOUCH, 1, 4, PRIO_META },
155 { -1, 0, 0, 0 },
156 },
157 touch_props
158};
159
160static const struct gesture_handler windrag_handler = {
161 GRAIL_EXPECT_X | GRAIL_EXPECT_Y,
162 {
163 { -1, 0, 0, 0 },
164 { -1, 0, 0, 0 },
165 { -1, 0, 0, 0 },
166 { GRAIL_TYPE_EDRAG, 1, 3, PRIO_ENV },
167 { GRAIL_TYPE_MDRAG, 1, 4, PRIO_META },
168 { -1, 0, 0, 0 },
169 },
170 drag_props
171};
172
173static const struct gesture_handler winpinch_handler = {
174 GRAIL_EXPECT_SCALE,
175 {
176 { -1, 0, 0, 0 },
177 { -1, 0, 0, 0 },
178 { -1, 0, 0, 0 },
179 { GRAIL_TYPE_EPINCH, 2, 3, PRIO_ENV },
180 { GRAIL_TYPE_MPINCH, 2, 4, PRIO_META },
181 { -1, 0, 0, 0 },
182 },
183 pinch_props
184};
185
186static const struct gesture_handler winrotate_handler = {
187 GRAIL_EXPECT_ANGLE,
188 {
189 { -1, 0, 0, 0 },
190 { -1, 0, 0, 0 },
191 { -1, 0, 0, 0 },
192 { GRAIL_TYPE_EROTATE, 2, 3, PRIO_ENV },
193 { GRAIL_TYPE_MROTATE, 2, 4, PRIO_META },
194 { -1, 0, 0, 0 },
195 },
196 rotate_props
197};
26198
27int gru_init(struct grail *ge)199int gru_init(struct grail *ge)
28{200{
@@ -30,8 +202,18 @@
30 gru = calloc(1, sizeof(struct gesture_recognizer));202 gru = calloc(1, sizeof(struct gesture_recognizer));
31 if (!gru)203 if (!gru)
32 return -ENOMEM;204 return -ENOMEM;
205
206 gru->touch.handler = &touch_handler;
207 gru->drag.handler = &drag_handler;
208 gru->pinch.handler = &pinch_handler;
209 gru->rotate.handler = &rotate_handler;
210 gru->tapping.handler = &tap_handler;
211 gru->wintouch.handler = &wintouch_handler;
212 gru->windrag.handler = &windrag_handler;
213 gru->winpinch.handler = &winpinch_handler;
214 gru->winrotate.handler = &winrotate_handler;
215
33 ge->gru = gru;216 ge->gru = gru;
34 gru_init_motion(ge);
35 return 0;217 return 0;
36}218}
37219
@@ -41,18 +223,173 @@
41 ge->gru = NULL;223 ge->gru = NULL;
42}224}
43225
44void gru_recognize(struct grail *ge, const struct utouch_frame *frame)226static void set_props(struct grail *ge,
45{227 struct combo_model *s,
46 if (!ge->gin || !ge->gru)228 const struct utouch_frame *frame)
47 return;229{
48 gru_motion(ge, frame);230 const struct gesture_handler *gh = s->handler;
49 gru_touch(ge, frame);231 gh->set_props(ge->gin, s, ge->gru->move, frame);
50 gru_drag(ge, frame);232 s->nprop += gin_add_contact_props(ge->gin, s->prop + s->nprop, frame);
51 gru_pinch(ge, frame);233}
52 gru_rotate(ge, frame);234
53 gru_wintouch(ge, frame);235static int gru_touch_handler(struct grail *ge,
54 gru_windrag(ge, frame);236 struct combo_model *state,
55 gru_winpinch(ge, frame);237 const struct utouch_frame *frame)
56 gru_winrotate(ge, frame);238{
57 gru_tapping(ge, frame);239 struct gesture_recognizer *gru = ge->gru;
58}240 struct gesture_inserter *gin = ge->gin;
241 struct grail_element *move = gru->move;
242 const struct gesture_handler *gh = state->handler;
243 int ntouch = move->num_touches;
244 if (frame->slot_revision != frame->prev->slot_revision) {
245 if (state->active) {
246 gin_gid_end(ge, state->gid, move->center.x,
247 move->center.y, ntouch,
248 state->prop, state->nprop);
249 state->active = 0;
250 }
251 }
252 if (ntouch > MAX_TOUCH_GESTURE)
253 return 0;
254 if (!state->active) {
255 struct gesture_head h = gh->getype[ntouch];
256 if (h.type < 0)
257 return 0;
258 state->gid = gin_gid_begin(ge, h.type, -h.priority, frame);
259 state->mintouch = h.mintouch;
260 state->maxtouch = h.maxtouch;
261 state->active = 1;
262 }
263 set_props(ge, state, frame);
264 gin_gid_event(ge, state->gid, move->center.x, move->center.y,
265 ntouch, state->prop, state->nprop, 0);
266 return 1;
267}
268
269static int gru_gesture_handler(struct grail *ge,
270 struct combo_model *state,
271 const struct utouch_frame *frame)
272{
273 struct gesture_recognizer *gru = ge->gru;
274 struct gesture_inserter *gin = ge->gin;
275 struct grail_element *move = gru->move;
276 const struct gesture_handler *gh = state->handler;
277 int expect = move->expect_mask & gh->fm_mask;
278 int active = move->active_mask & gh->fm_mask;
279 int ntouch = move->num_touches;
280 if (state->active &&
281 (!expect || ntouch < state->mintouch || ntouch > state->maxtouch)) {
282 gin_gid_end(ge, state->gid, move->center.x,
283 move->center.y,ntouch,
284 state->prop, state->nprop);
285 state->active = 0;
286 return 0;
287 }
288 if (!expect || !active || ntouch > MAX_TOUCH_GESTURE)
289 return 0;
290 if (!state->active) {
291 struct gesture_head h = gh->getype[ntouch];
292 if (h.type < 0)
293 return 0;
294 state->gid = gin_gid_begin(ge, h.type, h.priority, frame);
295 state->mintouch = h.mintouch;
296 state->maxtouch = h.maxtouch;
297 state->active = 1;
298 }
299 set_props(ge, state, frame);
300 gin_gid_event(ge, state->gid, move->center.x, move->center.y,
301 ntouch, state->prop, state->nprop, 0);
302 return 1;
303}
304
305static int gru_tap_handler(struct grail *ge,
306 struct combo_model *state,
307 const struct utouch_frame *frame)
308{
309 struct gesture_recognizer *gru = ge->gru;
310 struct grail_element *move = gru->move;
311 const struct gesture_handler *gh = state->handler;
312 int active = move->active_mask & gh->fm_mask;
313 int ntouch = move->num_touches;
314 state->tap = 0;
315 if (frame->num_active && !frame->prev->num_active) {
316 state->mintouch = 0;
317 state->maxtouch = 0;
318 }
319 if (ntouch > state->maxtouch) {
320 if (state->active) {
321 gin_gid_discard(ge, state->gid);
322 state->active = 0;
323 }
324 state->start = frame->time;
325 state->maxtouch = ntouch;
326 set_props(ge, state, frame);
327 if (state->maxtouch <= MAX_TOUCH_GESTURE) {
328 struct gesture_head h = gh->getype[ntouch];
329 if (h.type < 0)
330 return 0;
331 state->gid = gin_gid_begin(ge, h.type, h.priority,
332 frame);
333 state->active = 1;
334 }
335 return 0;
336 }
337 if (!state->active) {
338 state->mintouch = ntouch;
339 state->maxtouch = ntouch;
340 return 0;
341 }
342 if (ntouch <= state->mintouch) {
343 int x = state->prop[GRAIL_PROP_TAP_X];
344 int y = state->prop[GRAIL_PROP_TAP_Y];
345 int t = frame->time - state->start;
346 if (t > TAP_TIME_MS) {
347 gin_gid_discard(ge, state->gid);
348 state->mintouch = ntouch;
349 state->maxtouch = ntouch;
350 state->active = 0;
351 return 0;
352 }
353 state->tap = state->maxtouch;
354 state->prop[GRAIL_PROP_TAP_DT] = t;
355 gin_gid_event(ge, state->gid, x, y, state->maxtouch,
356 state->prop, state->nprop, 1);
357 state->mintouch = ntouch;
358 state->maxtouch = ntouch;
359 state->active = 0;
360 return 1;
361 }
362 if (!ntouch)
363 return 0;
364 state->prop[GRAIL_PROP_TAP_DT] = frame->time - state->start;
365 if (active || frame->time - state->start > TAP_TIME_MS) {
366 gin_gid_discard(ge, state->gid);
367 state->mintouch = ntouch;
368 state->maxtouch = ntouch;
369 state->active = 0;
370 }
371 return 0;
372}
373
374void gru_recognize(struct grail *ge,
375 const struct grail_frame *frame,
376 const struct utouch_frame *touch)
377{
378 struct gesture_recognizer *gru = ge->gru;
379
380 if (frame && frame->num_ongoing)
381 gru->slot = frame->ongoing[frame->num_ongoing - 1]->slot;
382
383 gru->move = frame->slots[gru->slot];
384
385 gru_touch_handler(ge, &gru->touch, touch);
386 gru_gesture_handler(ge, &gru->drag, touch);
387 gru_gesture_handler(ge, &gru->pinch, touch);
388 gru_gesture_handler(ge, &gru->rotate, touch);
389 gru_touch_handler(ge, &gru->wintouch, touch);
390 gru_gesture_handler(ge, &gru->windrag, touch);
391 gru_gesture_handler(ge, &gru->winpinch, touch);
392 gru_gesture_handler(ge, &gru->winrotate, touch);
393 gru_tap_handler(ge, &gru->tapping, touch);
394}
395
59396
=== modified file 'src/grail-recognizer.h'
--- src/grail-recognizer.h 2011-04-12 16:35:37 +0000
+++ src/grail-recognizer.h 2011-04-27 19:43:23 +0000
@@ -22,10 +22,26 @@
22#ifndef _GRAIL_RECOGNIZER_H22#ifndef _GRAIL_RECOGNIZER_H
23#define _GRAIL_RECOGNIZER_H23#define _GRAIL_RECOGNIZER_H
2424
25#include "grail-gestures.h"25#include "grail-inserter.h"
26
27#define PRIO_POINTER 1
28#define PRIO_GESTURE 2
29#define PRIO_ENV 3
30#define PRIO_META 4
31#define PRIO_TAP 5
32
33struct combo_model {
34 grail_time_t start;
35 int active, gid, tap;
36 int mintouch, maxtouch;
37 int nprop;
38 grail_prop_t prop[DIM_GRAIL_PROP];
39 const struct gesture_handler *handler;
40};
2641
27struct gesture_recognizer {42struct gesture_recognizer {
28 struct move_model move;43 int slot;
44 struct grail_element *move;
29 struct combo_model touch;45 struct combo_model touch;
30 struct combo_model drag;46 struct combo_model drag;
31 struct combo_model pinch;47 struct combo_model pinch;
@@ -34,11 +50,30 @@
34 struct combo_model windrag;50 struct combo_model windrag;
35 struct combo_model winpinch;51 struct combo_model winpinch;
36 struct combo_model winrotate;52 struct combo_model winrotate;
37 struct tapping_model tapping;53 struct combo_model tapping;
54};
55
56struct gesture_head {
57 int type;
58 int mintouch;
59 int maxtouch;
60 int priority;
61};
62
63struct gesture_handler {
64 int fm_mask;
65 struct gesture_head getype[DIM_TOUCH + 1];
66
67 void (*set_props)(const struct gesture_inserter *gin,
68 struct combo_model *state,
69 const struct grail_element *element,
70 const struct utouch_frame *frame);
38};71};
3972
40int gru_init(struct grail *ge);73int gru_init(struct grail *ge);
41void gru_recognize(struct grail *ge, const struct utouch_frame *frame);74void gru_recognize(struct grail *ge,
75 const struct grail_frame *frame,
76 const struct utouch_frame *touch);
42void gru_destroy(struct grail *ge);77void gru_destroy(struct grail *ge);
4378
44#endif79#endif
4580
=== modified file 'tools/grail-test-mtdev.c'
--- tools/grail-test-mtdev.c 2011-04-12 16:35:37 +0000
+++ tools/grail-test-mtdev.c 2011-04-27 19:43:23 +0000
@@ -120,7 +120,6 @@
120 slot->transform[4], slot->transform[5],120 slot->transform[4], slot->transform[5],
121 slot->transform[6], slot->transform[7],121 slot->transform[6], slot->transform[7],
122 slot->transform[8]);122 slot->transform[8]);
123 fprintf(stderr, " moveness: %f\n", slot->moveness);
124 fprintf(stderr, " pivot.x: %f\n", slot->pivot.x);123 fprintf(stderr, " pivot.x: %f\n", slot->pivot.x);
125 fprintf(stderr, " pivot.y: %f\n", slot->pivot.y);124 fprintf(stderr, " pivot.y: %f\n", slot->pivot.y);
126 fprintf(stderr, " drag.x: %f\n", slot->drag.x);125 fprintf(stderr, " drag.x: %f\n", slot->drag.x);
127126
=== modified file 'tools/grail-transform.c'
--- tools/grail-transform.c 2011-04-12 16:35:37 +0000
+++ tools/grail-transform.c 2011-04-27 19:43:23 +0000
@@ -53,6 +53,7 @@
53 int screen;53 int screen;
54 float off_x, off_y;54 float off_x, off_y;
55 unsigned long white, black;55 unsigned long white, black;
56 XColor red;
56};57};
5758
58static void clear_screen(struct appdata *w)59static void clear_screen(struct appdata *w)
@@ -77,29 +78,29 @@
7778
78static void draw_object(struct appdata *w)79static void draw_object(struct appdata *w)
79{80{
80 static const double frac = 0.01;81 static const double frac = 0.04;
81 const struct utouch_surface *s = utouch_frame_get_surface(w->fh);82 const struct utouch_surface *s = utouch_frame_get_surface(w->fh);
82 double d = frac * (s->mapped_max_x - s->mapped_min_x);83 double d = frac * (s->mapped_max_x - s->mapped_min_x);
83 int i;84 int i;
8485
86 XSetForeground(w->dsp, w->gc, w->black);
85 XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin);87 XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin);
8688
87 if (w->scaling)
88 XFillArc(w->dsp, w->win, w->gc,
89 w->pivot.x - d / 2, w->pivot.y - d / 2,
90 d, d, 0, 360 * 64);
91
92 d *= 4;
93 for (i = 0; i < w->ntouch; i++)89 for (i = 0; i < w->ntouch; i++)
94 XFillArc(w->dsp, w->win, w->gc,90 XFillArc(w->dsp, w->win, w->gc,
95 w->touch[i].x - d / 2, w->touch[i].y - d / 2,91 w->touch[i].x - d / 2, w->touch[i].y - d / 2,
96 d, d, 0, 360 * 64);92 d, d, 0, 360 * 64);
93
94 d /= 4;
95 XSetForeground(w->dsp, w->gc, w->red.pixel);
96 XFillArc(w->dsp, w->win, w->gc,
97 w->pivot.x - d / 2, w->pivot.y - d / 2,
98 d, d, 0, 360 * 64);
97}99}
98100
99static void report_frame(struct appdata *w,101static void report_frame(struct appdata *w,
100 const struct utouch_frame *touch)102 const struct utouch_frame *touch)
101{103{
102 const struct grail_control *ctl = grail_get_control(w->ge);
103 const struct grail_frame *frame;104 const struct grail_frame *frame;
104 const struct grail_element *slot;105 const struct grail_element *slot;
105 struct grail_coord tmp;106 struct grail_coord tmp;
@@ -121,8 +122,7 @@
121 w->pos[i] = tmp;122 w->pos[i] = tmp;
122 }123 }
123124
124 XSetForeground(w->dsp, w->gc, w->white);125 clear_screen(w);
125 draw_object(w);
126126
127 w->ntouch = touch->num_active;127 w->ntouch = touch->num_active;
128 for (i = 0; i < w->ntouch; i++) {128 for (i = 0; i < w->ntouch; i++) {
@@ -130,7 +130,6 @@
130 w->touch[i].y = touch->active[i]->y - w->off_y;130 w->touch[i].y = touch->active[i]->y - w->off_y;
131 }131 }
132132
133 w->scaling = slot->moveness < ctl->thresh_scale;
134 w->pivot.x = slot->pivot.x - w->off_x;133 w->pivot.x = slot->pivot.x - w->off_x;
135 w->pivot.y = slot->pivot.y - w->off_y;134 w->pivot.y = slot->pivot.y - w->off_y;
136135
@@ -148,6 +147,7 @@
148static int init_window(struct appdata *w)147static int init_window(struct appdata *w)
149{148{
150 int event, err;149 int event, err;
150 Colormap colormap;
151151
152 w->pos[0].x = 100;152 w->pos[0].x = 100;
153 w->pos[0].y = 100;153 w->pos[0].y = 100;
@@ -169,6 +169,9 @@
169 w->white = WhitePixel(w->dsp, w->screen);169 w->white = WhitePixel(w->dsp, w->screen);
170 w->black = BlackPixel(w->dsp, w->screen);170 w->black = BlackPixel(w->dsp, w->screen);
171171
172 colormap = DefaultColormap(w->dsp, w->screen);
173 XAllocNamedColor(w->dsp, colormap, "red", &w->red, &w->red);
174
172 w->win = XCreateSimpleWindow(w->dsp, XDefaultRootWindow(w->dsp),175 w->win = XCreateSimpleWindow(w->dsp, XDefaultRootWindow(w->dsp),
173 0, 0, 600, 600, 0, w->black, w->white);176 0, 0, 600, 600, 0, w->black, w->white);
174 w->gc = DefaultGC(w->dsp, w->screen);177 w->gc = DefaultGC(w->dsp, w->screen);
@@ -260,6 +263,7 @@
260 grail_get_control(w->ge)->drop_y_ms = 1e8;263 grail_get_control(w->ge)->drop_y_ms = 1e8;
261 grail_get_control(w->ge)->drop_scale_ms = 1e8;264 grail_get_control(w->ge)->drop_scale_ms = 1e8;
262 grail_get_control(w->ge)->drop_angle_ms = 1e8;265 grail_get_control(w->ge)->drop_angle_ms = 1e8;
266 grail_get_control(w->ge)->pivot_type = GRAIL_CONVEX_HULL_RADIUS;
263267
264 loop_device_mtdev(w);268 loop_device_mtdev(w);
265269
@@ -329,6 +333,8 @@
329 if (!w->ge)333 if (!w->ge)
330 return -1;334 return -1;
331335
336 grail_get_control(w->ge)->pivot_type = GRAIL_CONVEX_HULL_RADIUS;
337
332 loop_device_xi2(w, id);338 loop_device_xi2(w, id);
333339
334 grail_delete(w->ge);340 grail_delete(w->ge);
335341
=== modified file 'utouch-grail.sym.in'
--- utouch-grail.sym.in 2011-04-12 16:35:23 +0000
+++ utouch-grail.sym.in 2011-04-27 19:43:23 +0000
@@ -4,6 +4,7 @@
4grail_get_contact_frame4grail_get_contact_frame
5grail_get_contacts5grail_get_contacts
6grail_get_control6grail_get_control
7grail_get_gesture_frame
7grail_get_units8grail_get_units
8grail_get_version9grail_get_version
9grail_idle10grail_idle
@@ -11,6 +12,7 @@
11grail_mask_count12grail_mask_count
12grail_mask_get_first13grail_mask_get_first
13grail_mask_get_next14grail_mask_get_next
15grail_mask_inner
14grail_mask_set_mask16grail_mask_set_mask
15grail_new_raw17grail_new_raw
16grail_open18grail_open

Subscribers

People subscribed via source and target branches