/*****************************************************************************
*
* utouch-frame - Touch Frame 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 .
*
****************************************************************************/
#include
#include
#include
#include "frame-impl.h"
#include
#include
#include
#include
#include
#include
static Atom transform_atom;
#define set_field(fh, name, number, field) \
if (!strcmp(name, AXIS_LABEL_PROP_##field) && \
(fh->evmap[number] = field))
int utouch_frame_is_supported_xi2(Display *dpy, const XIDeviceInfo *dev)
{
int i;
for (i = 0; i < dev->num_classes; i++)
if (dev->classes[i]->type == XITouchClass)
return 1;
return 0;
}
static void init_properties(utouch_frame_handle fh,
Display *dpy, const XIDeviceInfo *dev)
{
struct utouch_surface *s = fh->surface;
XITouchClassInfo *v;
int i;
for (i = 0; i < dev->num_classes; i++) {
v = (void *)dev->classes[i];
if (v->type != XITouchClass)
continue;
switch(v->mode) {
case XIDependentTouch:
s->needs_pointer = 1;
break;
case XIDirectTouch:
s->is_direct = 1;
break;
default:
fprintf(stderr, "unknown mode\n");
break;
}
}
if (transform_atom == None)
transform_atom = XInternAtom(dpy, XI_PROP_TRANSFORM, True);
fh->map[0] = fh->map[4] = fh->map[8] = 1;
}
static void update_transform(utouch_frame_handle fh, Display *dpy, int devid)
{
unsigned long nitem, nbyte;
unsigned char *data;
int format;
Atom type;
if (transform_atom == None)
return;
XIGetProperty(dpy, devid, transform_atom, 0, 9, False,
AnyPropertyType, &type, &format, &nitem, &nbyte, &data);
if (format == 32 && nitem == 9 && nbyte == 0)
memcpy(fh->map, data, sizeof(fh->map));
else
fprintf(stderr, "Invalid transform matrix\n");
XFree(data);
}
static void update_screen(utouch_frame_handle fh, Display *dpy)
{
struct utouch_surface *s = fh->surface;
XWindowAttributes attrs;
float x1, y1, x2, y2;
XGetWindowAttributes(dpy, XDefaultRootWindow(dpy), &attrs);
x1 = 0;
y1 = 0;
x2 = attrs.width;
y2 = attrs.height;
s->mapped_min_x = fh->map[0] * x1 + fh->map[1] * y1 + fh->map[2];
s->mapped_min_y = fh->map[3] * x1 + fh->map[4] * y1 + fh->map[5];
s->mapped_max_x = fh->map[0] * x2 + fh->map[1] * y2 + fh->map[2];
s->mapped_max_y = fh->map[3] * x2 + fh->map[4] * y2 + fh->map[5];
s->mapped_max_pressure = 1;
fprintf(stderr, "frame map: %f %f %f %f %f\n",
s->mapped_min_x, s->mapped_min_y,
s->mapped_max_x, s->mapped_max_y, s->mapped_max_pressure);
}
static void init_valuators(utouch_frame_handle fh,
Display *dpy, const XIDeviceInfo *dev)
{
struct utouch_surface *s = fh->surface;
XITouchValuatorClassInfo *v;
char *name;
int i;
s->phys_width = 100;
s->phys_height = 65;
s->phys_pressure = 10;
s->max_x = 1024;
s->max_y = 768;
s->max_pressure = 256;
s->max_orient = 1;
for (i = 0; i < dev->num_classes; i++) {
v = (void *)dev->classes[i];
if (v->type != XITouchValuatorClass)
continue;
name = XGetAtomName(dpy, v->label);
set_field(fh, name, v->number, ABS_MT_POSITION_X) {
s->min_x = v->min;
s->max_x = v->max;
if (v->resolution > 0)
s->phys_width = (v->max - v->min) /
v->resolution;
}
set_field(fh, name, v->number, ABS_MT_POSITION_Y) {
s->min_y = v->min;
s->max_y = v->max;
if (v->resolution > 0)
s->phys_height = (v->max - v->min) /
v->resolution;
}
set_field(fh, name, v->number, ABS_MT_TOUCH_MAJOR) {
s->use_touch_major = 1;
}
set_field(fh, name, v->number, ABS_MT_TOUCH_MINOR) {
s->use_touch_minor = 1;
}
set_field(fh, name, v->number, ABS_MT_WIDTH_MAJOR) {
s->use_width_major = 1;
}
set_field(fh, name, v->number, ABS_MT_WIDTH_MINOR) {
s->use_width_minor = 1;
}
set_field(fh, name, v->number, ABS_MT_ORIENTATION) {
s->use_orientation = 1;
s->max_orient = v->max > 0 ? v->max : 1;
}
set_field(fh, name, v->number, ABS_MT_PRESSURE) {
s->use_pressure = 1;
s->max_pressure = v->max > 0 ? v->max : 256;
if (v->resolution > 0)
s->phys_pressure = v->max / v->resolution;
}
#if 0
set_field(fh, name, v->number, ABS_MT_DISTANCE) {
s->use_distance = 1;
}
#endif
XFree(name);
}
}
int utouch_frame_init_xi2(utouch_frame_handle fh,
Display *dpy, const XIDeviceInfo *dev)
{
int event;
int err;
free(fh->evmap);
fh->evmap =calloc(dev->num_classes, sizeof(int));
if (!fh->evmap)
return -ENOMEM;
if (!utouch_frame_is_supported_xi2(dpy, dev))
return -ENODEV;
init_properties(fh, dpy, dev);
init_valuators(fh, dpy, dev);
update_transform(fh, dpy, dev->deviceid);
update_screen(fh, dpy);
return 0;
}
static int handle_event(utouch_frame_handle fh,
struct utouch_contact *slot,
int ix, float value)
{
switch (fh->evmap[ix]) {
case ABS_MT_POSITION_X:
slot->x = value;
return 1;
case ABS_MT_POSITION_Y:
slot->y = value;
return 1;
case ABS_MT_TOUCH_MAJOR:
slot->touch_major = value;
return 1;
case ABS_MT_TOUCH_MINOR:
slot->touch_minor = value;
return 1;
case ABS_MT_WIDTH_MAJOR:
slot->width_major = value;
return 1;
case ABS_MT_WIDTH_MINOR:
slot->width_minor = value;
return 1;
case ABS_MT_ORIENTATION:
slot->orientation = value;
return 1;
case ABS_MT_PRESSURE:
slot->pressure = value;
return 1;
#ifdef ABS_MT_DISTANCE
case ABS_MT_DISTANCE:
slot->distance = value;
return 1;
#endif
case ABS_MT_TOOL_TYPE:
slot->tool_type = value;
return 1;
default:
fprintf(stderr, "did not get that one: %d\n", ix);
return 0;
}
}
int utouch_frame_configure_xi2(utouch_frame_handle fh,
const XConfigureEvent *ev)
{
if (ev->display)
update_screen(fh, ev->display);
return 1;
}
const struct utouch_frame *
utouch_frame_pump_xi2(utouch_frame_handle fh, const XIDeviceEvent *ev)
{
const XIPropertyEvent *prop_ev;
const double *value;
const unsigned char *mask;
struct utouch_contact *slot;
int touchid, nbyte, nbit, num, i;
switch (ev->evtype) {
case XI_TouchBegin:
case XI_TouchMotion:
case XI_TouchEnd:
value = ev->valuators.values;
mask = ev->valuators.mask;
touchid = ev->detail;
nbyte = ev->valuators.mask_len;
nbit = nbyte << 3;
utouch_frame_set_current_id(fh, touchid);
slot = utouch_frame_get_current_slot(fh);
num = 0;
for (i = 0; i < nbit; i++)
if (XIMaskIsSet(mask, i))
handle_event(fh, slot, i, value[num++]);
if (ev->evtype == XI_TouchEnd)
utouch_frame_get_current_slot(fh)->id = -1;
return utouch_frame_sync(fh, ev->time);
case XI_PropertyEvent:
prop_ev = (XIPropertyEvent *)ev;
if (prop_ev->property == transform_atom && ev->display) {
update_transform(fh, ev->display, ev->deviceid);
update_screen(fh, ev->display);
}
break;
}
return 0;
}