From 8d80a4768a2fb4beef81a6cf9ebd93bcd812c8d4 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Thu, 28 Apr 2011 16:16:56 +0200 Subject: Introduce the grail transform tool This tool tests the transform capabilities of grail. Similar to a map application, one can use a single finger, two fingers, a whole hand or two hands to move the rectangle around, scale and rotate it. Signed-off-by: Henrik Rydberg --- .gitignore | 1 + configure.ac | 7 + tools/Makefile.am | 6 + tools/grail-transform.c | 350 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 364 insertions(+) create mode 100644 tools/grail-transform.c diff --git a/.gitignore b/.gitignore index cac596e..eaf11e6 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,7 @@ core .bzr patches tools/grail-gesture +tools/grail-transform tools/grail-test-mtdev utouch-grail.sym test/*.log diff --git a/configure.ac b/configure.ac index 99569cc..dad13ac 100644 --- a/configure.ac +++ b/configure.ac @@ -26,6 +26,13 @@ PKG_CHECK_MODULES([MTDEV], [mtdev >= 1.1]) PKG_CHECK_MODULES([EVEMU], [utouch-evemu >= 1.0.5]) PKG_CHECK_MODULES([FRAME], [utouch-frame >= 1.0]) +AC_ARG_WITH([xi], AS_HELP_STRING([--with-xi], [Build with XI2.1 support])) +AM_CONDITIONAL([HAVE_XI], [test "x$with_xi" != "x"]) + +AS_IF([test "x$with_xi" = "xyes"], [ + PKG_CHECK_MODULES(XINPUT, x11 xext [xi >= 1.4.1.99.1] [inputproto >= 2.0.99.1]) + AC_DEFINE([HAVE_XI], [1], [XI2.1 support]) +]) # Check for TDD tools PKG_CHECK_MODULES([CHECK], [check >= 0.9.8], [have_check=yes], diff --git a/tools/Makefile.am b/tools/Makefile.am index 667fbb2..c333a2c 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,5 +1,11 @@ bin_PROGRAMS = grail-gesture grail-test-mtdev +if HAVE_XI + +bin_PROGRAMS += grail-transform + +endif + INCLUDES=-I$(top_srcdir)/include/ AM_CFLAGS = $(X11_CFLAGS) $(XINPUT_CFLAGS) diff --git a/tools/grail-transform.c b/tools/grail-transform.c new file mode 100644 index 0000000..2a1d676 --- /dev/null +++ b/tools/grail-transform.c @@ -0,0 +1,350 @@ +#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; +} -- cgit v1.2.3