diff options
Diffstat (limited to 'src/frame-xi2.c')
| -rw-r--r-- | src/frame-xi2.c | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/src/frame-xi2.c b/src/frame-xi2.c new file mode 100644 index 0000000..a78d9bf --- /dev/null +++ b/src/frame-xi2.c | |||
| @@ -0,0 +1,302 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * utouch-frame - Touch Frame Library | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Canonical Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License as published by the | ||
| 9 | * Free Software Foundation, either version 3 of the License, or (at your | ||
| 10 | * option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along | ||
| 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | * | ||
| 20 | ****************************************************************************/ | ||
| 21 | #include <utouch/frame-xi2.h> | ||
| 22 | #include <xorg/xserver-properties.h> | ||
| 23 | #include <linux/input.h> | ||
| 24 | #include "frame-impl.h" | ||
| 25 | #include <stdlib.h> | ||
| 26 | #include <stdio.h> | ||
| 27 | #include <errno.h> | ||
| 28 | #include <math.h> | ||
| 29 | #include <string.h> | ||
| 30 | #include <X11/Xlib.h> | ||
| 31 | |||
| 32 | static Atom transform_atom; | ||
| 33 | |||
| 34 | #define set_field(fh, name, number, field) \ | ||
| 35 | if (!strcmp(name, AXIS_LABEL_PROP_##field) && \ | ||
| 36 | (fh->evmap[number] = field)) | ||
| 37 | |||
| 38 | int utouch_frame_is_supported_xi2(Display *dpy, const XIDeviceInfo *dev) | ||
| 39 | { | ||
| 40 | |||
| 41 | int i; | ||
| 42 | |||
| 43 | for (i = 0; i < dev->num_classes; i++) | ||
| 44 | if (dev->classes[i]->type == XITouchClass) | ||
| 45 | return 1; | ||
| 46 | |||
| 47 | return 0; | ||
| 48 | } | ||
| 49 | |||
| 50 | static void init_properties(utouch_frame_handle fh, | ||
| 51 | Display *dpy, const XIDeviceInfo *dev) | ||
| 52 | { | ||
| 53 | struct utouch_surface *s = fh->surface; | ||
| 54 | XITouchClassInfo *v; | ||
| 55 | int i; | ||
| 56 | |||
| 57 | for (i = 0; i < dev->num_classes; i++) { | ||
| 58 | v = (void *)dev->classes[i]; | ||
| 59 | if (v->type != XITouchClass) | ||
| 60 | continue; | ||
| 61 | switch(v->mode) { | ||
| 62 | case XIDependentTouch: | ||
| 63 | s->needs_pointer = 1; | ||
| 64 | break; | ||
| 65 | case XIDirectTouch: | ||
| 66 | s->is_direct = 1; | ||
| 67 | break; | ||
| 68 | default: | ||
| 69 | fprintf(stderr, "unknown mode\n"); | ||
| 70 | break; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | if (transform_atom == None) | ||
| 75 | transform_atom = XInternAtom(dpy, XI_PROP_TRANSFORM, True); | ||
| 76 | |||
| 77 | fh->map[0] = fh->map[4] = fh->map[8] = 1; | ||
| 78 | } | ||
| 79 | |||
| 80 | static void update_transform(utouch_frame_handle fh, Display *dpy, int devid) | ||
| 81 | { | ||
| 82 | unsigned long nitem, nbyte; | ||
| 83 | unsigned char *data; | ||
| 84 | int format; | ||
| 85 | Atom type; | ||
| 86 | |||
| 87 | if (transform_atom == None) | ||
| 88 | return; | ||
| 89 | |||
| 90 | XIGetProperty(dpy, devid, transform_atom, 0, 9, False, | ||
| 91 | AnyPropertyType, &type, &format, &nitem, &nbyte, &data); | ||
| 92 | |||
| 93 | if (format == 32 && nitem == 9 && nbyte == 0) | ||
| 94 | memcpy(fh->map, data, sizeof(fh->map)); | ||
| 95 | else | ||
| 96 | fprintf(stderr, "Invalid transform matrix\n"); | ||
| 97 | |||
| 98 | XFree(data); | ||
| 99 | } | ||
| 100 | |||
| 101 | static void update_screen(utouch_frame_handle fh, Display *dpy) | ||
| 102 | { | ||
| 103 | struct utouch_surface *s = fh->surface; | ||
| 104 | XWindowAttributes attrs; | ||
| 105 | float x1, y1, x2, y2; | ||
| 106 | |||
| 107 | XGetWindowAttributes(dpy, XDefaultRootWindow(dpy), &attrs); | ||
| 108 | |||
| 109 | x1 = 0; | ||
| 110 | y1 = 0; | ||
| 111 | x2 = attrs.width; | ||
| 112 | y2 = attrs.height; | ||
| 113 | |||
| 114 | s->mapped_min_x = fh->map[0] * x1 + fh->map[1] * y1 + fh->map[2]; | ||
| 115 | s->mapped_min_y = fh->map[3] * x1 + fh->map[4] * y1 + fh->map[5]; | ||
| 116 | s->mapped_max_x = fh->map[0] * x2 + fh->map[1] * y2 + fh->map[2]; | ||
| 117 | s->mapped_max_y = fh->map[3] * x2 + fh->map[4] * y2 + fh->map[5]; | ||
| 118 | s->mapped_max_pressure = 1; | ||
| 119 | |||
| 120 | fprintf(stderr, "frame map: %f %f %f %f %f\n", | ||
| 121 | s->mapped_min_x, s->mapped_min_y, | ||
| 122 | s->mapped_max_x, s->mapped_max_y, s->mapped_max_pressure); | ||
| 123 | } | ||
| 124 | |||
| 125 | static void init_valuators(utouch_frame_handle fh, | ||
| 126 | Display *dpy, const XIDeviceInfo *dev) | ||
| 127 | { | ||
| 128 | struct utouch_surface *s = fh->surface; | ||
| 129 | XITouchValuatorClassInfo *v; | ||
| 130 | char *name; | ||
| 131 | int i; | ||
| 132 | |||
| 133 | s->phys_width = 100; | ||
| 134 | s->phys_height = 65; | ||
| 135 | s->phys_pressure = 10; | ||
| 136 | s->max_x = 1024; | ||
| 137 | s->max_y = 768; | ||
| 138 | s->max_pressure = 256; | ||
| 139 | s->max_orient = 1; | ||
| 140 | |||
| 141 | for (i = 0; i < dev->num_classes; i++) { | ||
| 142 | v = (void *)dev->classes[i]; | ||
| 143 | if (v->type != XITouchValuatorClass) | ||
| 144 | continue; | ||
| 145 | name = XGetAtomName(dpy, v->label); | ||
| 146 | set_field(fh, name, v->number, ABS_MT_POSITION_X) { | ||
| 147 | s->min_x = v->min; | ||
| 148 | s->max_x = v->max; | ||
| 149 | if (v->resolution > 0) | ||
| 150 | s->phys_width = (v->max - v->min) / | ||
| 151 | v->resolution; | ||
| 152 | } | ||
| 153 | set_field(fh, name, v->number, ABS_MT_POSITION_Y) { | ||
| 154 | s->min_y = v->min; | ||
| 155 | s->max_y = v->max; | ||
| 156 | if (v->resolution > 0) | ||
| 157 | s->phys_height = (v->max - v->min) / | ||
| 158 | v->resolution; | ||
| 159 | } | ||
| 160 | set_field(fh, name, v->number, ABS_MT_TOUCH_MAJOR) { | ||
| 161 | s->use_touch_major = 1; | ||
| 162 | } | ||
| 163 | set_field(fh, name, v->number, ABS_MT_TOUCH_MINOR) { | ||
| 164 | s->use_touch_minor = 1; | ||
| 165 | } | ||
| 166 | set_field(fh, name, v->number, ABS_MT_WIDTH_MAJOR) { | ||
| 167 | s->use_width_major = 1; | ||
| 168 | } | ||
| 169 | set_field(fh, name, v->number, ABS_MT_WIDTH_MINOR) { | ||
| 170 | s->use_width_minor = 1; | ||
| 171 | } | ||
| 172 | set_field(fh, name, v->number, ABS_MT_ORIENTATION) { | ||
| 173 | s->use_orientation = 1; | ||
| 174 | s->max_orient = v->max > 0 ? v->max : 1; | ||
| 175 | } | ||
| 176 | set_field(fh, name, v->number, ABS_MT_PRESSURE) { | ||
| 177 | s->use_pressure = 1; | ||
| 178 | s->max_pressure = v->max > 0 ? v->max : 256; | ||
| 179 | if (v->resolution > 0) | ||
| 180 | s->phys_pressure = v->max / v->resolution; | ||
| 181 | } | ||
| 182 | #if 0 | ||
| 183 | set_field(fh, name, v->number, ABS_MT_DISTANCE) { | ||
| 184 | s->use_distance = 1; | ||
| 185 | } | ||
| 186 | #endif | ||
| 187 | XFree(name); | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | int utouch_frame_init_xi2(utouch_frame_handle fh, | ||
| 192 | Display *dpy, const XIDeviceInfo *dev) | ||
| 193 | { | ||
| 194 | int event; | ||
| 195 | int err; | ||
| 196 | |||
| 197 | free(fh->evmap); | ||
| 198 | fh->evmap =calloc(dev->num_classes, sizeof(int)); | ||
| 199 | if (!fh->evmap) | ||
| 200 | return -ENOMEM; | ||
| 201 | |||
| 202 | if (!utouch_frame_is_supported_xi2(dpy, dev)) | ||
| 203 | return -ENODEV; | ||
| 204 | |||
| 205 | init_properties(fh, dpy, dev); | ||
| 206 | init_valuators(fh, dpy, dev); | ||
| 207 | update_transform(fh, dpy, dev->deviceid); | ||
| 208 | update_screen(fh, dpy); | ||
| 209 | |||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | |||
| 213 | static int handle_event(utouch_frame_handle fh, | ||
| 214 | struct utouch_contact *slot, | ||
| 215 | int ix, float value) | ||
| 216 | { | ||
| 217 | switch (fh->evmap[ix]) { | ||
| 218 | case ABS_MT_POSITION_X: | ||
| 219 | slot->x = value; | ||
| 220 | return 1; | ||
| 221 | case ABS_MT_POSITION_Y: | ||
| 222 | slot->y = value; | ||
| 223 | return 1; | ||
| 224 | case ABS_MT_TOUCH_MAJOR: | ||
| 225 | slot->touch_major = value; | ||
| 226 | return 1; | ||
| 227 | case ABS_MT_TOUCH_MINOR: | ||
| 228 | slot->touch_minor = value; | ||
| 229 | return 1; | ||
| 230 | case ABS_MT_WIDTH_MAJOR: | ||
| 231 | slot->width_major = value; | ||
| 232 | return 1; | ||
| 233 | case ABS_MT_WIDTH_MINOR: | ||
| 234 | slot->width_minor = value; | ||
| 235 | return 1; | ||
| 236 | case ABS_MT_ORIENTATION: | ||
| 237 | slot->orientation = value; | ||
| 238 | return 1; | ||
| 239 | case ABS_MT_PRESSURE: | ||
| 240 | slot->pressure = value; | ||
| 241 | return 1; | ||
| 242 | #ifdef ABS_MT_DISTANCE | ||
| 243 | case ABS_MT_DISTANCE: | ||
| 244 | slot->distance = value; | ||
| 245 | return 1; | ||
| 246 | #endif | ||
| 247 | case ABS_MT_TOOL_TYPE: | ||
| 248 | slot->tool_type = value; | ||
| 249 | return 1; | ||
| 250 | default: | ||
| 251 | fprintf(stderr, "did not get that one: %d\n", ix); | ||
| 252 | return 0; | ||
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 256 | int utouch_frame_configure_xi2(utouch_frame_handle fh, | ||
| 257 | const XConfigureEvent *ev) | ||
| 258 | { | ||
| 259 | if (ev->display) | ||
| 260 | update_screen(fh, ev->display); | ||
| 261 | return 1; | ||
| 262 | } | ||
| 263 | |||
| 264 | const struct utouch_frame * | ||
| 265 | utouch_frame_pump_xi2(utouch_frame_handle fh, const XIDeviceEvent *ev) | ||
| 266 | { | ||
| 267 | const XIPropertyEvent *prop_ev; | ||
| 268 | const double *value; | ||
| 269 | const unsigned char *mask; | ||
| 270 | struct utouch_contact *slot; | ||
| 271 | int touchid, nbyte, nbit, num, i; | ||
| 272 | |||
| 273 | switch (ev->evtype) { | ||
| 274 | case XI_TouchBegin: | ||
| 275 | case XI_TouchMotion: | ||
| 276 | case XI_TouchEnd: | ||
| 277 | value = ev->valuators.values; | ||
| 278 | mask = ev->valuators.mask; | ||
| 279 | touchid = ev->detail; | ||
| 280 | nbyte = ev->valuators.mask_len; | ||
| 281 | nbit = nbyte << 3; | ||
| 282 | |||
| 283 | utouch_frame_set_current_id(fh, touchid); | ||
| 284 | slot = utouch_frame_get_current_slot(fh); | ||
| 285 | num = 0; | ||
| 286 | for (i = 0; i < nbit; i++) | ||
| 287 | if (XIMaskIsSet(mask, i)) | ||
| 288 | handle_event(fh, slot, i, value[num++]); | ||
| 289 | if (ev->evtype == XI_TouchEnd) | ||
| 290 | utouch_frame_get_current_slot(fh)->id = -1; | ||
| 291 | return utouch_frame_sync(fh, ev->time); | ||
| 292 | case XI_PropertyEvent: | ||
| 293 | prop_ev = (XIPropertyEvent *)ev; | ||
| 294 | if (prop_ev->property == transform_atom && ev->display) { | ||
| 295 | update_transform(fh, ev->display, ev->deviceid); | ||
| 296 | update_screen(fh, ev->display); | ||
| 297 | } | ||
| 298 | break; | ||
| 299 | } | ||
| 300 | |||
| 301 | return 0; | ||
| 302 | } | ||
