summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--configure.ac7
-rw-r--r--tools/Makefile.am6
-rw-r--r--tools/grail-transform.c350
4 files changed, 364 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index cac596e..eaf11e6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,6 +79,7 @@ core
79.bzr 79.bzr
80patches 80patches
81tools/grail-gesture 81tools/grail-gesture
82tools/grail-transform
82tools/grail-test-mtdev 83tools/grail-test-mtdev
83utouch-grail.sym 84utouch-grail.sym
84test/*.log 85test/*.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])
26PKG_CHECK_MODULES([EVEMU], [utouch-evemu >= 1.0.5]) 26PKG_CHECK_MODULES([EVEMU], [utouch-evemu >= 1.0.5])
27PKG_CHECK_MODULES([FRAME], [utouch-frame >= 1.0]) 27PKG_CHECK_MODULES([FRAME], [utouch-frame >= 1.0])
28 28
29AC_ARG_WITH([xi], AS_HELP_STRING([--with-xi], [Build with XI2.1 support]))
30AM_CONDITIONAL([HAVE_XI], [test "x$with_xi" != "x"])
31
32AS_IF([test "x$with_xi" = "xyes"], [
33 PKG_CHECK_MODULES(XINPUT, x11 xext [xi >= 1.4.1.99.1] [inputproto >= 2.0.99.1])
34 AC_DEFINE([HAVE_XI], [1], [XI2.1 support])
35])
29# Check for TDD tools 36# Check for TDD tools
30PKG_CHECK_MODULES([CHECK], [check >= 0.9.8], 37PKG_CHECK_MODULES([CHECK], [check >= 0.9.8],
31 [have_check=yes], 38 [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 @@
1bin_PROGRAMS = grail-gesture grail-test-mtdev 1bin_PROGRAMS = grail-gesture grail-test-mtdev
2 2
3if HAVE_XI
4
5bin_PROGRAMS += grail-transform
6
7endif
8
3INCLUDES=-I$(top_srcdir)/include/ 9INCLUDES=-I$(top_srcdir)/include/
4 10
5AM_CFLAGS = $(X11_CFLAGS) $(XINPUT_CFLAGS) 11AM_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 @@
1#include "config.h"
2#include <evemu.h>
3#include <utouch/frame-mtdev.h>
4#include <utouch/frame-xi2.h>
5#include <grail.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <fcntl.h>
10#include <string.h>
11#include <math.h>
12
13struct appdata {
14 int opcode;
15 struct grail_coord min, max;
16 int fd;
17 struct evemu_device *evemu;
18 struct mtdev *mtdev;
19 utouch_frame_handle fh;
20 struct grail *ge;
21
22 struct grail_coord pos[4];
23 struct grail_coord touch[32];
24 struct grail_coord pivot;
25 XPoint pts[5];
26 int ntouch;
27
28 Display *dsp;
29 Window win;
30 GC gc;
31 int screen;
32 float off_x, off_y;
33 unsigned long white, black;
34};
35
36static void clear_screen(struct appdata *w)
37{
38 const struct utouch_surface *s = utouch_frame_get_surface(w->fh);
39 int width = s->mapped_max_x - s->mapped_min_x;
40 int height = s->mapped_max_y - s->mapped_min_y;
41 int i;
42
43 XSetForeground(w->dsp, w->gc, w->white);
44 XFillRectangle(w->dsp, w->win, w->gc, 0, 0, width, height);
45
46 for (i = 0; i < 5; i++) {
47 w->pts[i].x = w->pos[i % 4].x - w->off_x;
48 w->pts[i].y = w->pos[i % 4].y - w->off_y;
49 }
50
51 XSetForeground(w->dsp, w->gc, w->black);
52 XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin);
53
54}
55
56static void draw_object(struct appdata *w)
57{
58 static const double frac = 0.01;
59 const struct utouch_surface *s = utouch_frame_get_surface(w->fh);
60 double d = frac * (s->mapped_max_x - s->mapped_min_x);
61 int i;
62
63 XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin);
64
65 XFillArc(w->dsp, w->win, w->gc,
66 w->pivot.x - d / 2, w->pivot.y - d / 2,
67 d, d, 0, 360 * 64);
68
69 d *= 4;
70 for (i = 0; i < w->ntouch; i++)
71 XFillArc(w->dsp, w->win, w->gc,
72 w->touch[i].x - d / 2, w->touch[i].y - d / 2,
73 d, d, 0, 360 * 64);
74}
75
76static void report_frame(struct appdata *w,
77 const struct utouch_frame *touch)
78{
79 const struct grail_control *ctl = grail_get_control(w->ge);
80 const struct grail_frame *frame;
81 const struct grail_element *slot;
82 struct grail_coord tmp;
83 int i;
84
85 if (!touch)
86 return;
87
88 frame = grail_pump_frame(w->ge, touch);
89 if (!frame || !frame->num_ongoing || !frame->prev->num_ongoing)
90 return;
91
92 slot = frame->ongoing[frame->num_ongoing - 1];
93 if (slot->transform[0] == 0 && slot->transform[1] == 0)
94 return;
95
96 for (i = 0; i < 4; i++) {
97 grail_element_transform(slot, &tmp, &w->pos[i]);
98 w->pos[i] = tmp;
99 }
100
101 XSetForeground(w->dsp, w->gc, w->white);
102 draw_object(w);
103
104 w->ntouch = touch->num_active;
105 for (i = 0; i < w->ntouch; i++) {
106 w->touch[i].x = touch->active[i]->x - w->off_x;
107 w->touch[i].y = touch->active[i]->y - w->off_y;
108 }
109
110 w->pivot.x = slot->pivot.x - w->off_x;
111 w->pivot.y = slot->pivot.y - w->off_y;
112
113 for (i = 0; i < 5; i++) {
114 w->pts[i].x = w->pos[i % 4].x - w->off_x;
115 w->pts[i].y = w->pos[i % 4].y - w->off_y;
116 }
117
118 XSetForeground(w->dsp, w->gc, w->black);
119 draw_object(w);
120
121 XFlush(w->dsp);
122}
123
124static int init_window(struct appdata *w)
125{
126 int event, err;
127
128 w->pos[0].x = 100;
129 w->pos[0].y = 100;
130 w->pos[1].x = 200;
131 w->pos[1].y = 100;
132 w->pos[2].x = 200;
133 w->pos[2].y = 200;
134 w->pos[3].x = 100;
135 w->pos[3].y = 200;
136
137 w->dsp = XOpenDisplay(NULL);
138 if (!w->dsp)
139 return -1;
140 if (!XQueryExtension(w->dsp, "XInputExtension",
141 &w->opcode, &event, &err))
142 return -1;
143
144 w->screen = DefaultScreen(w->dsp);
145 w->white = WhitePixel(w->dsp, w->screen);
146 w->black = BlackPixel(w->dsp, w->screen);
147
148 w->win = XCreateSimpleWindow(w->dsp, XDefaultRootWindow(w->dsp),
149 0, 0, 600, 600, 0, w->black, w->white);
150 w->gc = DefaultGC(w->dsp, w->screen);
151
152 XMapWindow(w->dsp, w->win);
153 XFlush(w->dsp);
154
155 return 0;
156}
157
158static void term_window(struct appdata *w)
159{
160 XDestroyWindow(w->dsp, w->win);
161 XCloseDisplay(w->dsp);
162}
163
164static void set_screen_size_mtdev(struct appdata *w, XEvent *xev)
165{
166 struct utouch_surface *s = utouch_frame_get_surface(w->fh);
167 XConfigureEvent *cev = (XConfigureEvent *)xev;
168
169 s->mapped_min_x = 0;
170 s->mapped_min_y = 0;
171 s->mapped_max_x = DisplayWidth(w->dsp, w->screen);
172 s->mapped_max_y = DisplayHeight(w->dsp, w->screen);
173 s->mapped_max_pressure = 1;
174
175 if (cev) {
176 w->off_x = cev->x;
177 w->off_y = cev->y;
178 }
179}
180
181static void loop_device_mtdev(struct appdata *w)
182{
183 const struct utouch_frame *tf;
184 struct input_event iev;
185 XEvent xev;
186
187 clear_screen(w);
188
189 set_screen_size_mtdev(w, 0);
190 XSelectInput(w->dsp, w->win, StructureNotifyMask);
191
192 while (1) {
193 while (!mtdev_idle(w->mtdev, w->fd, 100)) {
194 while (mtdev_get(w->mtdev, w->fd, &iev, 1) > 0) {
195 tf = utouch_frame_pump_mtdev(w->fh, &iev);
196 report_frame(w, tf);
197 }
198 }
199 while (XPending(w->dsp)) {
200 XNextEvent(w->dsp, &xev);
201 set_screen_size_mtdev(w, &xev);
202 }
203 }
204}
205
206static int run_mtdev(struct appdata *w, const char *path)
207{
208 w->fd = open(path, O_RDONLY | O_NONBLOCK);
209 if (w->fd < 0) {
210 fprintf(stderr, "error: could not open device\n");
211 return -1;
212 }
213 if (ioctl(w->fd, EVIOCGRAB, 1)) {
214 fprintf(stderr, "error: could not grab the device\n");
215 return -1;
216 }
217
218 w->evemu = evemu_new(NULL);
219 if (!w->evemu)
220 return -1;
221 if (evemu_extract(w->evemu, w->fd))
222 return -1;
223 w->mtdev = mtdev_new_open(w->fd);
224 if (!w->mtdev)
225 return -1;
226 w->fh = utouch_frame_new_engine(500, 32, 100);
227 if (!w->fh)
228 return -1;
229 if (utouch_frame_init_mtdev(w->fh, w->evemu))
230 return -1;
231 w->ge = grail_new(w->fh, 100, 0);
232 if (!w->ge)
233 return -1;
234
235 grail_get_control(w->ge)->drop_x_ms = 1e8;
236 grail_get_control(w->ge)->drop_y_ms = 1e8;
237 grail_get_control(w->ge)->drop_scale_ms = 1e8;
238 grail_get_control(w->ge)->drop_angle_ms = 1e8;
239
240 loop_device_mtdev(w);
241
242 grail_delete(w->ge);
243 utouch_frame_delete_engine(w->fh);
244 mtdev_close_delete(w->mtdev);
245 evemu_delete(w->evemu);
246
247 ioctl(w->fd, EVIOCGRAB, 0);
248 close(w->fd);
249}
250
251#if HAVE_XI
252static void loop_device_xi2(struct appdata *w, int id)
253{
254 const struct utouch_frame *tf;
255 XIEventMask mask;
256
257 mask.deviceid = id;
258 mask.mask_len = XIMaskLen(XI_LASTEVENT);
259 mask.mask = calloc(mask.mask_len, sizeof(char));
260
261 XISetMask(mask.mask, XI_TouchBegin);
262 XISetMask(mask.mask, XI_TouchUpdate);
263 XISetMask(mask.mask, XI_TouchEnd);
264 XISetMask(mask.mask, XI_PropertyEvent);
265 XISelectEvents(w->dsp, w->win, &mask, 1);
266
267 XSelectInput(w->dsp, DefaultRootWindow(w->dsp), StructureNotifyMask);
268
269 while (1) {
270 XEvent ev;
271 XIDeviceEvent *event = (void *)&ev;
272 XGenericEventCookie *cookie = &ev.xcookie;
273 XNextEvent(w->dsp, &ev);
274
275 if (XGetEventData(w->dsp, cookie) &&
276 cookie->type == GenericEvent &&
277 cookie->extension == w->opcode) {
278 tf = utouch_frame_pump_xi2(w->fh, cookie->data);
279 report_frame(w, tf);
280 }
281 XFreeEventData(w->dsp, cookie);
282 }
283
284}
285
286static int run_xi2(struct appdata *w, int id)
287{
288 XIDeviceInfo *info, *dev;
289 int ndevices, i;
290
291 info = XIQueryDevice(w->dsp, XIAllDevices, &ndevices);
292 dev = 0;
293 for (i = 0; i < ndevices; i++)
294 if (info[i].deviceid == id)
295 dev = &info[i];
296 if (!dev)
297 return -1;
298
299 w->fh = utouch_frame_new_engine(500, 32, 100);
300 if (!w->fh)
301 return -1;
302 if (utouch_frame_init_xi2(w->fh, w->dsp, dev))
303 return -1;
304 w->ge = grail_new(w->fh, 100, 0);
305 if (!w->ge)
306 return -1;
307
308 loop_device_xi2(w, id);
309
310 grail_delete(w->ge);
311 utouch_frame_delete_engine(w->fh);
312
313 XIFreeDeviceInfo(info);
314
315 return 0;
316}
317#else
318static int run_xi2(struct appdata *w, int id)
319{
320 fprintf(stderr, "X not supported in this build (use --with-xi)\n");
321 return 0;
322}
323#endif
324
325int main(int argc, char **argv)
326{
327 struct appdata w;
328 int id, ret;
329
330 if (argc < 2) {
331 fprintf(stderr, "Usage: %s <device>\n", argv[0]);
332 return -1;
333 }
334
335 memset(&w, 0, sizeof(w));
336
337 if (init_window(&w))
338 return -1;
339
340 id = atoi(argv[1]);
341
342 if (id)
343 ret = run_xi2(&w, id);
344 else
345 ret = run_mtdev(&w, argv[1]);
346
347 term_window(&w);
348
349 return ret;
350}