#include "config.h" #include #include #include #include #include #include #include #include #include #include struct appdata { int opcode; struct grail_coord min, max; int fd; struct evemu_device *evemu; struct mtdev *mtdev; utouch_frame_handle fh; struct grail *ge; struct grail_coord pos[4]; struct grail_coord touch[32]; struct grail_coord pivot; XPoint pts[5]; int ntouch; Display *dsp; Window win; GC gc; int screen; float off_x, off_y; unsigned long white, black; }; static void clear_screen(struct appdata *w) { const struct utouch_surface *s = utouch_frame_get_surface(w->fh); int width = s->mapped_max_x - s->mapped_min_x; int height = s->mapped_max_y - s->mapped_min_y; int i; XSetForeground(w->dsp, w->gc, w->white); XFillRectangle(w->dsp, w->win, w->gc, 0, 0, width, height); for (i = 0; i < 5; i++) { w->pts[i].x = w->pos[i % 4].x - w->off_x; w->pts[i].y = w->pos[i % 4].y - w->off_y; } XSetForeground(w->dsp, w->gc, w->black); XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin); } static void draw_object(struct appdata *w) { static const double frac = 0.01; const struct utouch_surface *s = utouch_frame_get_surface(w->fh); double d = frac * (s->mapped_max_x - s->mapped_min_x); int i; XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin); XFillArc(w->dsp, w->win, w->gc, w->pivot.x - d / 2, w->pivot.y - d / 2, d, d, 0, 360 * 64); d *= 4; for (i = 0; i < w->ntouch; i++) XFillArc(w->dsp, w->win, w->gc, w->touch[i].x - d / 2, w->touch[i].y - d / 2, d, d, 0, 360 * 64); } static void report_frame(struct appdata *w, const struct utouch_frame *touch) { const struct grail_control *ctl = grail_get_control(w->ge); const struct grail_frame *frame; const struct grail_element *slot; struct grail_coord tmp; int i; if (!touch) return; frame = grail_pump_frame(w->ge, touch); if (!frame || !frame->num_ongoing || !frame->prev->num_ongoing) return; slot = frame->ongoing[frame->num_ongoing - 1]; if (slot->transform[0] == 0 && slot->transform[1] == 0) return; for (i = 0; i < 4; i++) { grail_element_transform(slot, &tmp, &w->pos[i]); w->pos[i] = tmp; } XSetForeground(w->dsp, w->gc, w->white); draw_object(w); w->ntouch = touch->num_active; for (i = 0; i < w->ntouch; i++) { w->touch[i].x = touch->active[i]->x - w->off_x; w->touch[i].y = touch->active[i]->y - w->off_y; } w->pivot.x = slot->pivot.x - w->off_x; w->pivot.y = slot->pivot.y - w->off_y; for (i = 0; i < 5; i++) { w->pts[i].x = w->pos[i % 4].x - w->off_x; w->pts[i].y = w->pos[i % 4].y - w->off_y; } XSetForeground(w->dsp, w->gc, w->black); draw_object(w); XFlush(w->dsp); } static int init_window(struct appdata *w) { int event, err; w->pos[0].x = 100; w->pos[0].y = 100; w->pos[1].x = 200; w->pos[1].y = 100; w->pos[2].x = 200; w->pos[2].y = 200; w->pos[3].x = 100; w->pos[3].y = 200; w->dsp = XOpenDisplay(NULL); if (!w->dsp) return -1; if (!XQueryExtension(w->dsp, "XInputExtension", &w->opcode, &event, &err)) return -1; w->screen = DefaultScreen(w->dsp); w->white = WhitePixel(w->dsp, w->screen); w->black = BlackPixel(w->dsp, w->screen); w->win = XCreateSimpleWindow(w->dsp, XDefaultRootWindow(w->dsp), 0, 0, 600, 600, 0, w->black, w->white); w->gc = DefaultGC(w->dsp, w->screen); XMapWindow(w->dsp, w->win); XFlush(w->dsp); return 0; } static void term_window(struct appdata *w) { XDestroyWindow(w->dsp, w->win); XCloseDisplay(w->dsp); } static void set_screen_size_mtdev(struct appdata *w, XEvent *xev) { struct utouch_surface *s = utouch_frame_get_surface(w->fh); XConfigureEvent *cev = (XConfigureEvent *)xev; s->mapped_min_x = 0; s->mapped_min_y = 0; s->mapped_max_x = DisplayWidth(w->dsp, w->screen); s->mapped_max_y = DisplayHeight(w->dsp, w->screen); s->mapped_max_pressure = 1; if (cev) { w->off_x = cev->x; w->off_y = cev->y; } } static void loop_device_mtdev(struct appdata *w) { const struct utouch_frame *tf; struct input_event iev; XEvent xev; clear_screen(w); set_screen_size_mtdev(w, 0); XSelectInput(w->dsp, w->win, StructureNotifyMask); while (1) { while (!mtdev_idle(w->mtdev, w->fd, 100)) { while (mtdev_get(w->mtdev, w->fd, &iev, 1) > 0) { tf = utouch_frame_pump_mtdev(w->fh, &iev); report_frame(w, tf); } } while (XPending(w->dsp)) { XNextEvent(w->dsp, &xev); set_screen_size_mtdev(w, &xev); } } } static int run_mtdev(struct appdata *w, const char *path) { w->fd = open(path, O_RDONLY | O_NONBLOCK); if (w->fd < 0) { fprintf(stderr, "error: could not open device\n"); return -1; } if (ioctl(w->fd, EVIOCGRAB, 1)) { fprintf(stderr, "error: could not grab the device\n"); return -1; } w->evemu = evemu_new(NULL); if (!w->evemu) return -1; if (evemu_extract(w->evemu, w->fd)) return -1; w->mtdev = mtdev_new_open(w->fd); if (!w->mtdev) return -1; w->fh = utouch_frame_new_engine(500, 32, 100); if (!w->fh) return -1; if (utouch_frame_init_mtdev(w->fh, w->evemu)) return -1; w->ge = grail_new(w->fh, 100, 0); if (!w->ge) return -1; grail_get_control(w->ge)->drop_x_ms = 1e8; grail_get_control(w->ge)->drop_y_ms = 1e8; grail_get_control(w->ge)->drop_scale_ms = 1e8; grail_get_control(w->ge)->drop_angle_ms = 1e8; loop_device_mtdev(w); grail_delete(w->ge); utouch_frame_delete_engine(w->fh); mtdev_close_delete(w->mtdev); evemu_delete(w->evemu); ioctl(w->fd, EVIOCGRAB, 0); close(w->fd); } #if HAVE_XI static void loop_device_xi2(struct appdata *w, int id) { const struct utouch_frame *tf; XIEventMask mask; mask.deviceid = id; mask.mask_len = XIMaskLen(XI_LASTEVENT); mask.mask = calloc(mask.mask_len, sizeof(char)); XISetMask(mask.mask, XI_TouchBegin); XISetMask(mask.mask, XI_TouchUpdate); XISetMask(mask.mask, XI_TouchEnd); XISetMask(mask.mask, XI_PropertyEvent); XISelectEvents(w->dsp, w->win, &mask, 1); XSelectInput(w->dsp, DefaultRootWindow(w->dsp), StructureNotifyMask); while (1) { XEvent ev; XIDeviceEvent *event = (void *)&ev; XGenericEventCookie *cookie = &ev.xcookie; XNextEvent(w->dsp, &ev); if (XGetEventData(w->dsp, cookie) && cookie->type == GenericEvent && cookie->extension == w->opcode) { tf = utouch_frame_pump_xi2(w->fh, cookie->data); report_frame(w, tf); } XFreeEventData(w->dsp, cookie); } } static int run_xi2(struct appdata *w, int id) { XIDeviceInfo *info, *dev; int ndevices, i; info = XIQueryDevice(w->dsp, XIAllDevices, &ndevices); dev = 0; for (i = 0; i < ndevices; i++) if (info[i].deviceid == id) dev = &info[i]; if (!dev) return -1; w->fh = utouch_frame_new_engine(500, 32, 100); if (!w->fh) return -1; if (utouch_frame_init_xi2(w->fh, w->dsp, dev)) return -1; w->ge = grail_new(w->fh, 100, 0); if (!w->ge) return -1; loop_device_xi2(w, id); grail_delete(w->ge); utouch_frame_delete_engine(w->fh); XIFreeDeviceInfo(info); return 0; } #else static int run_xi2(struct appdata *w, int id) { fprintf(stderr, "X not supported in this build (use --with-xi)\n"); return 0; } #endif int main(int argc, char **argv) { struct appdata w; int id, ret; if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return -1; } memset(&w, 0, sizeof(w)); if (init_window(&w)) return -1; id = atoi(argv[1]); if (id) ret = run_xi2(&w, id); else ret = run_mtdev(&w, argv[1]); term_window(&w); return ret; }