/*****************************************************************************
*
* grail - Gesture Recognition And Instantiation Library
*
* Copyright (C) 2010 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 .
*
* Authors:
* Henrik Rydberg
*
****************************************************************************/
#include "grail-inserter.h"
#include
#include
#include
static const int MAX_GESTURE_ID = 0xfff;
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 = s->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_gesture_discard(gin, i);
}
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_gesture_discard(gin, i);
}
if (grail_mask_count(span, sizeof(span)))
grail_mask_set(filtered, EV_ABS);
}
int gin_gesture_begin(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 geslot = grail_mask_get_first(gin->unused, sizeof(gin->unused));
if (geslot < 0)
return -1;
s = &gin->state[geslot];
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, geslot);
grail_mask_set(gin->fresh, geslot);
grail_mask_set(gin->used, geslot);
return geslot;
}
void gin_gesture_end(struct gesture_inserter *gin, int geslot)
{
gin->state[geslot].status = GRAIL_STATUS_END;
}
void gin_gesture_discard(struct gesture_inserter *gin, int geslot)
{
gebuf_clear(&gin->state[geslot].buf);
gin_gesture_end(gin, geslot);
grail_mask_clear(gin->used, geslot);
grail_mask_set(gin->unused, geslot);
}
void gin_gesture_discard_type(struct gesture_inserter *gin, int type)
{
int i;
grail_mask_foreach(i, gin->used, sizeof(gin->used))
if (gin->state[i].type == type)
gin_gesture_discard(gin, i);
}
void gin_gesture_event(struct gesture_inserter *gin, int geslot,
float x, float y, int ntouch,
const grail_prop_t *prop, int nprop)
{
struct slot_state *s = &gin->state[geslot];
struct gesture_event ev;
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));
if (s->status == GRAIL_STATUS_BEGIN)
s->status = GRAIL_STATUS_UPDATE;
gebuf_put(&s->buf, &ev);
}