summaryrefslogtreecommitdiff
path: root/src/grail-inserter.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/grail-inserter.c')
-rw-r--r--src/grail-inserter.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/src/grail-inserter.c b/src/grail-inserter.c
new file mode 100644
index 0000000..724052c
--- /dev/null
+++ b/src/grail-inserter.c
@@ -0,0 +1,282 @@
1/*****************************************************************************
2 *
3 * grail - Gesture Recognition And Instantiation Library
4 *
5 * Copyright (C) 2010 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 * Authors:
21 * Henrik Rydberg <rydberg@bitmath.org>
22 *
23 ****************************************************************************/
24
25#include "grail-inserter.h"
26#include <malloc.h>
27#include <string.h>
28#include <errno.h>
29
30static const int MAX_GESTURE_ID = 0xfff;
31
32struct gesture_inserter {
33 struct slot_state state[DIM_INSTANCE];
34 grail_mask_t unused[DIM_INSTANCE_BYTES];
35 grail_mask_t fresh[DIM_INSTANCE_BYTES];
36 grail_mask_t used[DIM_INSTANCE_BYTES];
37 grail_time_t time;
38 int gestureid;
39};
40
41static int find_gslot(const struct gesture_inserter *gin, int gid)
42{
43 int i;
44 grail_mask_foreach(i, gin->used, sizeof(gin->used))
45 if (gin->state[i].id == gid)
46 return i;
47 return -1;
48}
49
50static void send_event(struct grail *ge, struct slot_state *s,
51 const struct gesture_event *ev)
52{
53 struct grail_event gev;
54 int i;
55 if (!ge->gesture)
56 return;
57 gev.type = s->type;
58 gev.id = s->id;
59 gev.status = s->status;
60 gev.ntouch = ev->ntouch;
61 gev.nprop = ev->nprop;
62 gev.time = ev->time;
63 gev.pos = ev->pos;
64 memcpy(gev.prop, ev->prop, ev->nprop * sizeof(grail_prop_t));
65 for (i = 0; i < s->nclient; i++) {
66 gev.client_id = s->client_id[i];
67 ge->gesture(ge, &gev);
68 }
69}
70
71// todo: spanning tree for multi-user case
72static void setup_new_gestures(struct grail *ge,
73 const struct touch_frame *frame)
74{
75 struct gesture_inserter *gin = ge->gin;
76 grail_mask_t types[DIM_GRAIL_TYPE_BYTES];
77 grail_mask_t span[DIM_TOUCH_BYTES];
78 struct grail_client_info info[DIM_CLIENT];
79 int i, j, nclient = 0;
80 int nfresh = grail_mask_count(gin->fresh, sizeof(gin->fresh));
81 if (!nfresh)
82 return;
83
84 memset(types, 0, sizeof(types));
85 memset(span, 0, sizeof(span));
86
87 grail_mask_foreach(i, gin->fresh, sizeof(gin->fresh)) {
88 struct slot_state *s = &gin->state[i];
89 grail_mask_set(types, s->type);
90 grail_mask_set_mask(span, s->span, sizeof(span));
91 }
92
93 if (ge->get_clients) {
94 struct grail_coord coord[DIM_CLIENT];
95 int ncoord = 0;
96 grail_mask_foreach(i, span, sizeof(span)) {
97 const struct touch *t = &frame->touch[i];
98 coord[ncoord].x = t->prop[TP_POS_X];
99 coord[ncoord].y = t->prop[TP_POS_Y];
100 ncoord++;
101 }
102 nclient = ge->get_clients(ge, info, DIM_CLIENT,
103 coord, ncoord, types, sizeof(types));
104 }
105
106 grail_mask_foreach(i, gin->fresh, sizeof(gin->fresh)) {
107 struct slot_state *s = &gin->state[i];
108 s->nclient = 0;
109 for (j = 0; j < nclient; j++) {
110 if (!grail_mask_get(info[j].mask, s->type))
111 continue;
112 s->client_id[s->nclient++] = info[j].id;
113 }
114 }
115
116 memset(gin->fresh, 0, sizeof(gin->fresh));
117}
118
119int gin_init(struct grail *ge)
120{
121 struct gesture_inserter *gin;
122 int i;
123 gin = calloc(1, sizeof(*gin));
124 if (!gin)
125 return -ENOMEM;
126 for (i = 0; i < DIM_INSTANCE; i++)
127 grail_mask_set(gin->unused, i);
128 ge->gin = gin;
129 return 0;
130}
131
132void gin_destroy(struct grail *ge)
133{
134 free(ge->gin);
135 ge->gin = NULL;
136}
137
138void gin_frame_begin(struct grail *ge, const struct touch_frame *frame)
139{
140 struct gesture_inserter *gin = ge->gin;
141 gin->time = frame->time;
142}
143
144void gin_frame_end(struct grail *ge,
145 grail_mask_t *filtered, int max_filtered,
146 const struct touch_frame *frame)
147{
148 struct gesture_inserter *gin = ge->gin;
149 grail_mask_t span[DIM_INSTANCE_BYTES];
150 int i, hold = 0, discard = 0;
151
152 memset(filtered, 0, max_filtered);
153 memset(span, 0, sizeof(span));
154
155 setup_new_gestures(ge, frame);
156
157 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
158 struct slot_state *s = &gin->state[i];
159 if (!s->nclient)
160 continue;
161 if (s->priority > hold)
162 hold = s->priority;
163 if (s->status == GRAIL_STATUS_BEGIN)
164 continue;
165 if (s->priority > discard)
166 discard = s->priority;
167 }
168
169 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
170 struct slot_state *s = &gin->state[i];
171 if (!s->nclient || s->priority < discard)
172 gin_gid_discard(ge, s->id);
173 }
174
175 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
176 struct slot_state *s = &gin->state[i];
177 struct gesture_event ev;
178 grail_mask_set_mask(span, s->span, sizeof(span));
179 if (s->priority < hold)
180 continue;
181 while (!gebuf_empty(&s->buf)) {
182 gebuf_get(&s->buf, &ev);
183 send_event(ge, s, &ev);
184 }
185 }
186
187 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
188 struct slot_state *s = &gin->state[i];
189 if (s->status == GRAIL_STATUS_END)
190 gin_gid_discard(ge, s->id);
191 }
192
193 if (grail_mask_count(span, sizeof(span)))
194 grail_mask_set(filtered, EV_ABS);
195}
196
197int gin_gid_begin_select(struct grail *ge, int type, int priority,
198 const grail_mask_t *span, int nspan)
199{
200 struct gesture_inserter *gin = ge->gin;
201 struct slot_state *s;
202 int i = grail_mask_get_first(gin->unused, sizeof(gin->unused));
203 if (i < 0)
204 return -1;
205 s = &gin->state[i];
206 s->type = type;
207 s->priority = priority;
208 s->id = gin->gestureid++ & MAX_GESTURE_ID;
209 s->status = GRAIL_STATUS_BEGIN;
210 s->nclient = 0;
211 memcpy(s->span, span, nspan);
212 gebuf_clear(&s->buf);
213 grail_mask_clear(gin->unused, i);
214 grail_mask_set(gin->fresh, i);
215 grail_mask_set(gin->used, i);
216 return s->id;
217}
218
219int gin_gid_begin(struct grail *ge, int type, int priority,
220 const struct touch_frame *frame)
221{
222 return gin_gid_begin_select(ge, type, priority,
223 frame->touches, sizeof(frame->touches));
224}
225
226void gin_gid_discard(struct grail *ge, int gid)
227{
228 struct gesture_inserter *gin = ge->gin;
229 struct slot_state *s;
230 int i = find_gslot(gin, gid);
231 if (i < 0)
232 return;
233 s = &gin->state[i];
234 gebuf_clear(&s->buf);
235 s->status = GRAIL_STATUS_END;
236 grail_mask_clear(gin->used, i);
237 grail_mask_set(gin->unused, i);
238}
239
240void gin_gid_event(struct grail *ge, int gid,
241 float x, float y, int ntouch,
242 const grail_prop_t *prop, int nprop,
243 int status)
244{
245 struct gesture_inserter *gin = ge->gin;
246 struct gesture_event ev;
247 struct slot_state *s;
248 int i = find_gslot(gin, gid);
249 if (i < 0)
250 return;
251 s = &gin->state[i];
252 ev.ntouch = ntouch;
253 ev.nprop = nprop;
254 ev.time = gin->time;
255 ev.pos.x = x;
256 ev.pos.y = y;
257 memcpy(ev.prop, prop, nprop * sizeof(grail_prop_t));
258 gebuf_put(&s->buf, &ev);
259 if (s->status == GRAIL_STATUS_BEGIN)
260 s->status = status;
261}
262
263void gin_gid_end(struct grail *ge, int gid,
264 float x, float y, int ntouch)
265{
266 struct gesture_inserter *gin = ge->gin;
267 struct gesture_event ev;
268 struct slot_state *s;
269 int i = find_gslot(gin, gid);
270 if (i < 0)
271 return;
272 s = &gin->state[i];
273 if (s->status != GRAIL_STATUS_BEGIN) {
274 ev.ntouch = ntouch;
275 ev.nprop = 0;
276 ev.time = gin->time;
277 ev.pos.x = x;
278 ev.pos.y = y;
279 gebuf_put(&s->buf, &ev);
280 }
281 s->status = GRAIL_STATUS_END;
282}