/***************************************************************************** * * grail - Gesture Recognition And Instantiation Library * * Copyright (C) 2010 Canonical Ltd. * Copyright (C) 2010 Henrik Rydberg * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * ****************************************************************************/ #include "grail-inserter.h" #include #include #include static const int MAX_GESTURE_ID = 0xfff; struct gesture_inserter { struct slot_state state[DIM_INSTANCE]; grail_mask_t unused[DIM_INSTANCE_BYTES]; grail_mask_t fresh[DIM_INSTANCE_BYTES]; grail_mask_t used[DIM_INSTANCE_BYTES]; grail_time_t time; int gestureid; }; static int find_gslot(const struct gesture_inserter *gin, int gid) { int i; grail_mask_foreach(i, gin->used, sizeof(gin->used)) if (gin->state[i].id == gid) return i; return -1; } static void send_event(struct grail *ge, struct slot_state *s, const struct gesture_event *ev) { struct grail_event gev; int i; if (!ge->gesture) return; gev.type = s->type; gev.id = s->id; gev.status = ev->status; gev.ntouch = ev->ntouch; gev.nprop = ev->nprop; gev.time = ev->time; gev.pos = ev->pos; memcpy(gev.prop, ev->prop, ev->nprop * sizeof(grail_prop_t)); for (i = 0; i < s->nclient; i++) { gev.client_id = s->client_id[i]; ge->gesture(ge, &gev); } } // todo: spanning tree for multi-user case static void setup_new_gestures(struct grail *ge, const struct touch_frame *frame) { struct gesture_inserter *gin = ge->gin; grail_mask_t types[DIM_GRAIL_TYPE_BYTES]; grail_mask_t span[DIM_TOUCH_BYTES]; struct grail_client_info info[DIM_CLIENT]; int i, j, nclient = 0; int nfresh = grail_mask_count(gin->fresh, sizeof(gin->fresh)); if (!nfresh) return; memset(types, 0, sizeof(types)); memset(span, 0, sizeof(span)); grail_mask_foreach(i, gin->fresh, sizeof(gin->fresh)) { struct slot_state *s = &gin->state[i]; grail_mask_set(types, s->type); grail_mask_set_mask(span, s->span, sizeof(span)); } if (ge->get_clients) { struct grail_coord coord[DIM_CLIENT]; int ncoord = 0; grail_mask_foreach(i, span, sizeof(span)) { const struct touch *t = &frame->touch[i]; coord[ncoord].x = t->prop[TP_POS_X]; coord[ncoord].y = t->prop[TP_POS_Y]; ncoord++; } nclient = ge->get_clients(ge, info, DIM_CLIENT, coord, ncoord, types, sizeof(types)); } grail_mask_foreach(i, gin->fresh, sizeof(gin->fresh)) { struct slot_state *s = &gin->state[i]; s->nclient = 0; for (j = 0; j < nclient; j++) { if (!grail_mask_get(info[j].mask, s->type)) continue; s->client_id[s->nclient++] = info[j].id; } } memset(gin->fresh, 0, sizeof(gin->fresh)); } int gin_init(struct grail *ge) { struct gesture_inserter *gin; int i; gin = calloc(1, sizeof(*gin)); if (!gin) return -ENOMEM; for (i = 0; i < DIM_INSTANCE; i++) grail_mask_set(gin->unused, i); ge->gin = gin; return 0; } void gin_destroy(struct grail *ge) { free(ge->gin); ge->gin = NULL; } void gin_frame_begin(struct grail *ge, const struct touch_frame *frame) { struct gesture_inserter *gin = ge->gin; gin->time = frame->time; } void gin_frame_end(struct grail *ge, grail_mask_t *filtered, int max_filtered, const struct touch_frame *frame) { struct gesture_inserter *gin = ge->gin; grail_mask_t span[DIM_INSTANCE_BYTES]; int i, hold = 0, discard = 0; memset(filtered, 0, max_filtered); memset(span, 0, sizeof(span)); setup_new_gestures(ge, frame); grail_mask_foreach(i, gin->used, sizeof(gin->used)) { struct slot_state *s = &gin->state[i]; if (!s->nclient) continue; if (s->priority > hold) hold = s->priority; if (s->status == GRAIL_STATUS_BEGIN) continue; if (s->priority > discard) discard = s->priority; } grail_mask_foreach(i, gin->used, sizeof(gin->used)) { struct slot_state *s = &gin->state[i]; if (!s->nclient || s->priority < discard) gin_gid_discard(ge, s->id); } grail_mask_foreach(i, gin->used, sizeof(gin->used)) { struct slot_state *s = &gin->state[i]; struct gesture_event ev; grail_mask_set_mask(span, s->span, sizeof(span)); if (s->priority < hold) continue; while (!gebuf_empty(&s->buf)) { gebuf_get(&s->buf, &ev); send_event(ge, s, &ev); } } grail_mask_foreach(i, gin->used, sizeof(gin->used)) { struct slot_state *s = &gin->state[i]; if (s->status == GRAIL_STATUS_END) gin_gid_discard(ge, s->id); } if (grail_mask_count(span, sizeof(span))) grail_mask_set(filtered, EV_ABS); } int gin_gid_begin_select(struct grail *ge, int type, int priority, const grail_mask_t *span, int nspan) { struct gesture_inserter *gin = ge->gin; struct slot_state *s; int i = grail_mask_get_first(gin->unused, sizeof(gin->unused)); if (i < 0) return -1; s = &gin->state[i]; s->type = type; s->priority = priority; s->id = gin->gestureid++ & MAX_GESTURE_ID; s->status = GRAIL_STATUS_BEGIN; s->nclient = 0; memcpy(s->span, span, nspan); gebuf_clear(&s->buf); grail_mask_clear(gin->unused, i); grail_mask_set(gin->fresh, i); grail_mask_set(gin->used, i); return s->id; } int gin_gid_begin(struct grail *ge, int type, int priority, const struct touch_frame *frame) { return gin_gid_begin_select(ge, type, priority, frame->touches, sizeof(frame->touches)); } void gin_gid_discard(struct grail *ge, int gid) { struct gesture_inserter *gin = ge->gin; struct slot_state *s; int i = find_gslot(gin, gid); if (i < 0) return; s = &gin->state[i]; gebuf_clear(&s->buf); s->status = GRAIL_STATUS_END; grail_mask_clear(gin->used, i); grail_mask_set(gin->unused, i); } void gin_gid_event(struct grail *ge, int gid, float x, float y, int ntouch, const grail_prop_t *prop, int nprop, int transient) { struct gesture_inserter *gin = ge->gin; struct gesture_event ev; struct slot_state *s; int i = find_gslot(gin, gid); if (i < 0) return; s = &gin->state[i]; ev.status = transient ? GRAIL_STATUS_UPDATE : s->status; ev.ntouch = ntouch; ev.nprop = nprop; ev.time = gin->time; ev.pos.x = x; ev.pos.y = y; memcpy(ev.prop, prop, nprop * sizeof(grail_prop_t)); gebuf_put(&s->buf, &ev); if (transient) s->status = GRAIL_STATUS_END; else if (s->status == GRAIL_STATUS_BEGIN) s->status = GRAIL_STATUS_UPDATE; } void gin_gid_end(struct grail *ge, int gid, float x, float y, int ntouch) { struct gesture_inserter *gin = ge->gin; struct gesture_event ev; struct slot_state *s; int i = find_gslot(gin, gid); if (i < 0) return; s = &gin->state[i]; if (s->status != GRAIL_STATUS_BEGIN) { ev.status = GRAIL_STATUS_END; ev.ntouch = ntouch; ev.nprop = 0; ev.time = gin->time; ev.pos.x = x; ev.pos.y = y; gebuf_put(&s->buf, &ev); } s->status = GRAIL_STATUS_END; }