/*****************************************************************************
*
* 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;
int gin_init(struct grail *ge)
{
struct gesture_inserter *x;
x = calloc(1, sizeof(*x));
if (!x)
return -ENOMEM;
ge->gin = x;
return 0;
}
void gin_destroy(struct grail *ge)
{
free(ge->gin);
ge->gin = NULL;
}
void gin_frame_begin(struct grail *ge, grail_time_t time)
{
struct gesture_inserter *gin = ge->gin;
gin->time = time;
}
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.pos.x = s->x;
gev.pos.y = s->x;
gev.time = ev->time;
memcpy(gev.prop, ev->prop, DIM_GRAIL_PROP * sizeof(gev.prop[0]));
for (i = 0; i < s->nclient; i++) {
gev.client_id = s->client_id[i];
ge->gesture(ge, &gev);
}
}
void gin_frame_end(struct grail *ge, grail_mask_t *filtered)
{
struct gesture_inserter *gin = ge->gin;
struct gesture_event ev;
grail_mask_t span[DIM_SLOT_BYTES];
int i, slot, spanned = 0;
memset(filtered, 0, DIM_EV_TYPE_BYTES);
memset(span, 0, sizeof(span));
for (slot = 0; slot < DIM_SLOT; slot++) {
struct slot_state *s = &gin->state[slot];
if (!grail_get_mask(gin->used, slot))
continue;
if (!s->nclient)
gin_gesture_discard(gin, slot);
}
for (slot = 0; slot < DIM_SLOT; slot++) {
struct slot_state *s = &gin->state[slot];
if (!grail_get_mask(gin->used, slot))
continue;
for (i = 0; i < DIM_SLOT_BYTES; i++) {
span[i] |= s->span[i];
spanned += !!span[i];
}
while (!gebuf_empty(&s->buf)) {
gebuf_get(&s->buf, &ev);
send_event(ge, s, &ev);
}
if (s->status == GRAIL_STATUS_BEGIN)
s->status = GRAIL_STATUS_UPDATE;
}
if (spanned)
grail_set_mask(filtered, EV_ABS);
}
int gin_gesture_begin(struct grail *ge, const struct touch_frame *frame,
int type, int x, int y, const grail_mask_t *span)
{
struct grail_client_info info[DIM_CLIENT];
struct grail_coord coord[DIM_CLIENT];
struct gesture_inserter *gin = ge->gin;
struct slot_state *s;
int i, slot, nc, ncoord = 0;
for (slot = 0; slot < DIM_SLOT; slot++)
if (!grail_get_mask(gin->used, slot))
break;
if (slot >= DIM_SLOT)
return -1;
s = &gin->state[slot];
s->type = type;
s->id = gin->gestureid++ & MAX_GESTURE_ID;
s->status = GRAIL_STATUS_BEGIN;
s->x = x;
s->y = y;
s->nclient = 0;
if (ge->get_clients) {
grail_mask_t tps[DIM_GRAIL_TYPE_BYTES];
memset(tps, 0, sizeof(tps));
grail_set_mask(tps, type);
for (i = 0; i < DIM_SLOT; i++) {
const struct touch *t = &frame->touch[i];
if (!grail_get_mask(span, i))
continue;
coord[ncoord].x = t->prop[TP_POS_X];
coord[ncoord].y = t->prop[TP_POS_Y];
ncoord++;
}
nc = ge->get_clients(ge, info, DIM_CLIENT, coord, ncoord, tps);
for (i = 0; i < nc; i++) {
if (!grail_get_mask(info[i].mask, type))
continue;
s->client_id[s->nclient] = info[i].id;
s->nclient++;
}
}
memcpy(s->span, span, sizeof(s->span));
gebuf_clear(&s->buf);
grail_set_mask(gin->used, slot);
return slot;
}
void gin_gesture_end(struct gesture_inserter *gin, int slot)
{
struct slot_state *s = &gin->state[slot];
s->status = GRAIL_STATUS_END;
grail_clear_mask(gin->used, slot);
}
void gin_gesture_discard(struct gesture_inserter *gin, int slot)
{
struct slot_state *s = &gin->state[slot];
gebuf_clear(&s->buf);
gin_gesture_end(gin, slot);
}
void gin_gesture_end_all(struct gesture_inserter *gin)
{
int slot;
for (slot = 0; slot < DIM_SLOT; slot++)
gin_gesture_end(gin, slot);
}
void gin_gesture_event(struct gesture_inserter *gin, int slot,
const grail_prop_t *prop)
{
struct slot_state *s = &gin->state[slot];
struct gesture_event ev;
ev.time = gin->time;
memcpy(ev.prop, prop, sizeof(ev.prop));
gebuf_put(&s->buf, &ev);
}