/***************************************************************************** * * 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; slot->vx = 0; return 1; case ABS_MT_POSITION_Y: slot->y = value; slot->vy = 0; 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; }