/***************************************************************************** * * grail - Gesture Recognition And Instantiation Library * * Copyright (C) 2010-2011 Canonical Ltd. * * 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-gestures.h" #include "grail-inserter.h" #include "grail-impl.h" #include #include #include #include static const int MAX_GESTURE_ID = 0xfff; 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 int mask_overlap(const grail_mask_t *a, const grail_mask_t *b, int bytes) { int i; for (i = 0; i < bytes; i++) if (a[i] & b[i]) return 1; return 0; } // todo: spanning tree for multi-user case static void setup_new_gestures(struct grail *ge, const struct utouch_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)); } nclient = gin_get_clients(ge, info, DIM_CLIENT, types, sizeof(types), span, sizeof(span), frame); 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; if (gin->grab_active && info[j].id.client != gin->grab_client) continue; if (grail_mask_get(info[j].mask, GRAIL_TYPE_SYSFLAG1)) { gin->grab_active = 1; gin->grab_client = info[j].id.client; } 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 utouch_frame *frame) { struct gesture_inserter *gin = ge->gin; memset(gin->types, 0, sizeof(gin->types)); gin->time = frame->time; if (frame->num_active && !frame->prev->num_active) gin->grab_active = 0; } void gin_frame_end(struct grail *ge, const struct utouch_frame *frame) { struct gesture_inserter *gin = ge->gin; grail_mask_t keep[DIM_TOUCH_BYTES]; int i, hold[2] = { 0, 0 }, discard[2] = { 0, 0 }; memset(keep, 0, sizeof(keep)); 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[s->slice]) hold[s->slice] = s->priority; if (s->status != GRAIL_STATUS_UPDATE) continue; if (s->priority > discard[s->slice]) discard[s->slice] = s->priority; } grail_mask_foreach(i, gin->used, sizeof(gin->used)) { struct slot_state *s = &gin->state[i]; if (!s->nclient || s->priority < discard[s->slice] && !s->sent) gin_gid_discard(ge, s->id); } grail_mask_foreach(i, gin->used, sizeof(gin->used)) { struct slot_state *s = &gin->state[i]; if (s->slice == 1) grail_mask_set_mask(keep, s->span, sizeof(keep)); } grail_mask_foreach(i, gin->used, sizeof(gin->used)) { struct slot_state *s = &gin->state[i]; if (!s->timeout) continue; if (mask_overlap(keep, s->span, sizeof(keep))) continue; 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(gin->types, s->type); if (s->priority < hold[s->slice] && !s->sent) continue; while (!gebuf_empty(&s->buf)) { gebuf_get(&s->buf, &ev); gin_send_event(ge, s, &ev, frame); } s->sent = 1; } 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); } } int gin_gid_begin(struct grail *ge, int type, int priority, const struct utouch_frame *frame) { struct gesture_inserter *gin = ge->gin; struct slot_state *s; int slot; int i = grail_mask_get_first(gin->unused, sizeof(gin->unused)); if (i < 0) return -1; s = &gin->state[i]; s->type = type; if (priority < 0) { s->priority = -priority; s->slice = 1; } else { s->priority = priority; s->slice = 0; } s->timeout = 0; s->sent = 0; s->id = gin->gestureid++ & MAX_GESTURE_ID; s->status = GRAIL_STATUS_BEGIN; s->nclient = 0; for (slot = 0; slot < DIM_TOUCH; slot++) grail_mask_modify(s->span, slot, frame->slots[slot]->active); 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; } 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_timeout(struct grail *ge, int gid) { int i = find_gslot(ge->gin, gid); if (i >= 0) ge->gin->state[i].timeout = 1; } 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, const grail_prop_t *prop, int nprop) { 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 = 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); } s->status = GRAIL_STATUS_END; } void GRAIL_PUBLIC grail_set_bbox(struct grail *ge, const struct grail_coord *tmin, const struct grail_coord *tmax) { struct utouch_surface *s = utouch_frame_get_surface(ge->impl->fh); s->mapped_min_x = tmin->x; s->mapped_min_y = tmin->y; s->mapped_max_x = tmax->x; s->mapped_max_y = tmax->y; if (ge->gru) gru_init_motion(ge); }