Removed redundant deallocation
[xf86-input-tuio.git] / src / tuio.c
blobd6ee01b76456a03b2287d7fe8edf60a4b5b71bec
1 /*
2 * Copyright (c) 2009 Ryan Huffman
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
22 * Authors:
23 * Ryan Huffman (ryanhuffman@gmail.com)
26 #include <unistd.h>
28 #include <xf86Xinput.h>
29 #include <X11/extensions/XIproto.h>
30 #include <X11/extensions/XInput2.h>
31 #include <xf86_OSlib.h>
33 #include "tuio.h"
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
39 /* Module Functions */
40 static pointer
41 TuioPlug(pointer, pointer, int *, int *);
43 static void
44 TuioUnplug(pointer);
46 /* Driver Functions */
47 static InputInfoPtr
48 TuioPreInit(InputDriverPtr, IDevPtr, int);
50 static void
51 TuioUnInit(InputDriverPtr, InputInfoPtr, int);
53 static void
54 TuioReadInput(InputInfoPtr);
56 static int
57 TuioControl(DeviceIntPtr, int);
59 /* Internal Functions */
60 static int
61 _tuio_init_buttons(DeviceIntPtr device);
63 static int
64 _tuio_init_axes(DeviceIntPtr device);
66 static int
67 _tuio_lo_cur2d_handle(const char *path,
68 const char *types,
69 lo_arg **argv,
70 int argc,
71 void *data,
72 void *user_data);
74 static void
75 lo_error(int num,
76 const char *msg,
77 const char *path);
79 /* Object list manipulation functions */
80 static ObjectPtr
81 _object_get(ObjectPtr head, int id);
83 static ObjectPtr
84 _object_insert(ObjectPtr head);
86 static void
87 _object_remove(ObjectPtr head, int id);
89 /* Driver information */
90 static XF86ModuleVersionInfo TuioVersionRec =
92 "tuio",
93 MODULEVENDORSTRING,
94 MODINFOSTRING1,
95 MODINFOSTRING2,
96 XORG_VERSION_CURRENT,
97 PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
98 ABI_CLASS_XINPUT,
99 ABI_XINPUT_VERSION,
100 MOD_CLASS_XINPUT,
101 {0, 0, 0, 0}
104 _X_EXPORT InputDriverRec TUIO =
107 "tuio",
108 NULL,
109 TuioPreInit,
110 TuioUnInit,
111 NULL,
115 _X_EXPORT XF86ModuleData tuioModuleData =
117 &TuioVersionRec,
118 TuioPlug,
119 TuioUnplug
122 static pointer
123 TuioPlug(pointer module,
124 pointer options,
125 int *errmaj,
126 int *errmin)
128 xf86AddInputDriver(&TUIO, module, 0);
129 return module;
132 /* Remove this? */
133 static void
134 TuioUnplug(pointer p)
139 * Pre-initialization of new device
141 * TODO:
142 * - Parse configuration options
144 static InputInfoPtr
145 TuioPreInit(InputDriverPtr drv,
146 IDevPtr dev,
147 int flags)
149 InputInfoPtr pInfo;
150 TuioDevicePtr pTuio;
152 if (!(pInfo = xf86AllocateInput(drv, 0)))
153 return NULL;
155 /* The TuioDevicePtr will hold object and other
156 * information */
157 pTuio = xcalloc(1, sizeof(TuioDeviceRec));
158 if (!pTuio) {
159 pInfo->private = NULL;
160 xf86DeleteInput(pInfo, 0);
161 return NULL;
164 pTuio->list_head = xcalloc(1, sizeof(ObjectRec));
165 if (!pTuio->list_head) {
166 xfree(pTuio);
167 pInfo->private = NULL;
168 xf86DeleteInput(pInfo, 0);
169 return NULL;
171 pTuio->list_head->id = -1;
172 pTuio->list_head->next = NULL;
174 pInfo->private = pTuio;
176 /* Set up InputInfoPtr */
177 pInfo->name = xstrdup(dev->identifier);
178 pInfo->flags = 0;
179 pInfo->type_name = XI_TOUCHSCREEN; /* FIXME: Correct type? */
180 pInfo->conf_idev = dev;
181 pInfo->read_input = TuioReadInput; /* Set callback */
182 pInfo->device_control = TuioControl; /* Set callback */
183 pInfo->switch_mode = NULL;
185 /* Process common device options */
186 xf86CollectInputOptions(pInfo, NULL, NULL);
187 xf86ProcessCommonOptions(pInfo, pInfo->options);
189 pInfo->flags |= XI86_OPEN_ON_INIT;
190 pInfo->flags |= XI86_CONFIGURED;
192 return pInfo;
196 * Clean up
198 static void
199 TuioUnInit(InputDriverPtr drv,
200 InputInfoPtr pInfo,
201 int flags)
203 TuioDevicePtr pTuio = pInfo->private;
205 xfree(pTuio);
206 xf86DeleteInput(pInfo, 0);
210 * Handle new data on the socket
212 static void
213 TuioReadInput(InputInfoPtr pInfo)
215 TuioDevicePtr pTuio = pInfo->private;
216 ObjectPtr head = pTuio->list_head;
217 ObjectPtr obj = head->next;
218 ObjectPtr objtemp;
220 while(xf86WaitForInput(pInfo->fd, 0) > 0)
222 /* liblo will receive a message and call the appropriate
223 * handlers (i.e. _tuio_lo_cur2d_hande())
224 * If nothing is found (this SHOULDN'T happen, but if it did,
225 * all the objects would be deleted), just return */
226 if(!lo_server_recv_noblock(pTuio->server, 0))
227 return;
229 /* During the processing of the previous message/bundle,
230 * any "active" messages will be handled by flagging
231 * the listed object ids. Now that processing is done,
232 * remove any dead object ids. */
233 while (obj != NULL) {
234 if (!obj->alive) {
235 objtemp = obj->next;
236 _object_remove(head, obj->id);
237 obj = objtemp;
238 } else {
239 obj->alive = 0; /* Reset for next message */
240 obj = obj->next;
247 * Handle device state changes
249 static int
250 TuioControl(DeviceIntPtr device,
251 int what)
253 InputInfoPtr pInfo = device->public.devicePrivate;
254 TuioDevicePtr pTuio = pInfo->private;
256 switch (what)
258 case DEVICE_INIT:
259 xf86Msg(X_INFO, "%s: Init\n", pInfo->name);
260 _tuio_init_buttons(device);
261 _tuio_init_axes(device);
262 break;
264 case DEVICE_ON: /* Open device socket and start listening! */
265 xf86Msg(X_INFO, "%s: On.\n", pInfo->name);
266 if (device->public.on) /* already on! */
267 break;
269 /* Setup server */
270 pTuio->server = lo_server_new_with_proto("3333", LO_UDP, lo_error);
271 if (pTuio->server == NULL) {
272 xf86Msg(X_ERROR, "%s: Error allocating new lo_server\n",
273 pInfo->name);
274 return BadAlloc;
277 /* Register to receive all /tuio/2Dcur messages */
278 lo_server_add_method(pTuio->server, "/tuio/2Dcur", NULL,
279 _tuio_lo_cur2d_handle, pInfo);
281 pInfo->fd = lo_server_get_socket_fd(pTuio->server);
282 xf86Msg(X_INFO, "%s: Socket = %i\n", pInfo->name, pInfo->fd);
284 xf86FlushInput(pInfo->fd);
285 xf86AddEnabledDevice(pInfo);
286 device->public.on = TRUE;
287 break;
289 case DEVICE_OFF:
290 xf86Msg(X_INFO, "%s: Off\n", pInfo->name);
291 if (!device->public.on)
292 break;
294 xf86RemoveEnabledDevice(pInfo);
296 lo_server_free(pTuio->server);
297 pInfo->fd = -1;
298 device->public.on = FALSE;
299 break;
301 case DEVICE_CLOSE:
302 xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
304 xfree(pTuio);
305 break;
308 return Success;
311 static int
312 _tuio_create_master() {
313 //XICreateMasterInfo ci;
314 //unsigned int blobid;
315 //char cur_name[21]; /* Max len: 20 char + \0 */
317 //sprintf(cur_name, "tuio_blob_%u", blobid);
319 //c.type = XICreateMaster;
320 //c.name = cur_name;
324 * Handles OSC messages in the /tuio/2Dcur address space
326 static int
327 _tuio_lo_cur2d_handle(const char *path,
328 const char *types,
329 lo_arg **argv,
330 int argc,
331 void *data,
332 void *user_data)
334 InputInfoPtr pInfo = user_data;
335 TuioDevicePtr pTuio = pInfo->private;
336 ObjectPtr head = pTuio->list_head;
337 ObjectPtr obj, objtemp;
338 int valuators[2];
339 int i;
341 if (argc < 1) {
342 xf86Msg(X_ERROR, "%s: \n", pInfo->name);
343 return 1;
346 /* Parse message type */
348 /* Set message type: */
349 if (strcmp(argv[0], "set") == 0) {
350 obj = _object_get(head, argv[1]->i);
351 if(obj == NULL) {
352 obj = _object_insert(head);
353 obj->id = argv[1]->i;
356 obj->x = argv[2]->f;
357 obj->y = argv[3]->f;
359 /* OKAY FOR NOW, MAYBE UPDATE */
360 valuators[0] = obj->x * 0x7FFFFFFF;
361 valuators[1] = obj->y * 0x7FFFFFFF;
363 xf86PostMotionEventP(pInfo->dev,
364 TRUE, /* is_absolute */
365 0, /* first_valuator */
366 2, /* num_valuators */
367 valuators);
369 } else if (strcmp(argv[0], "alive") == 0) {
370 obj = head->next;
371 while (obj != NULL) {
372 for (i=1; i<argc; i++) {
373 if (argv[i]->i == obj->id) {
374 obj->alive = 1;
375 break;
378 obj = obj->next;
381 } else if (strcmp(argv[0], "fseq") == 0) {
382 pTuio->fseq_old = pTuio->fseq_new;
383 pTuio->fseq_new = argv[1]->i;
386 return 0;
390 * liblo error handler
392 static void
393 lo_error(int num,
394 const char *msg,
395 const char *path)
397 xf86Msg(X_ERROR, "liblo: %s\n", msg);
401 * Retrieves an object from a list based on its id. Returns NULL if
402 * not found.
404 static ObjectPtr
405 _object_get(ObjectPtr head, int id) {
406 ObjectPtr obj = head->next;
408 while (obj != NULL && obj->id != id) {
409 obj = obj->next;
412 return obj;
416 * Allocates and inserts a new object at the beginning of a list.
417 * Pointer to the new object is returned.
418 * Doesn't check for duplicate ids, so call _object_get() beforehand
419 * to make sure it doesn't exist already!!
421 * @return ptr to new object
423 static ObjectPtr
424 _object_insert(ObjectPtr head) {
425 ObjectPtr obj = xcalloc(1, sizeof(ObjectRec));
426 obj->next = head->next;
427 head->next = obj;
428 return obj;
432 * Removes an object from a list. It is assumed that the object
433 * is in the list
435 static void
436 _object_remove(ObjectPtr head, int id) {
437 ObjectPtr obj = head;
438 ObjectPtr objtmp;
440 while (obj->next != NULL) {
441 if (obj->next->id == id) {
442 objtmp = obj->next;
443 obj->next = objtmp->next;
444 xfree(objtmp);
445 break;
447 obj = obj->next;
452 * Init the button map device. We only use one button.
454 static int
455 _tuio_init_buttons(DeviceIntPtr device)
457 InputInfoPtr pInfo = device->public.devicePrivate;
458 CARD8 *map;
459 Atom *labels;
460 const int num_buttons = 1; /* left-click */
461 int ret = Success;
462 int i;
464 map = xcalloc(num_buttons, sizeof(CARD8));
465 labels = xcalloc(num_buttons, sizeof(Atom));
467 for (i = 0; i < num_buttons; i++)
468 map[i] = i;
470 if (!InitButtonClassDeviceStruct(device, num_buttons,
471 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
472 labels,
473 #endif
474 map)) {
475 xf86Msg(X_ERROR, "%s: Failed to register buttons.\n", pInfo->name);
476 ret = BadAlloc;
479 xfree(labels);
480 xfree(map);
481 return ret;
485 * Init valuators for device, use x/y coordinates.
487 static int
488 _tuio_init_axes(DeviceIntPtr device)
490 InputInfoPtr pInfo = device->public.devicePrivate;
491 int i;
492 const int num_axes = 2;
493 Atom *atoms;
495 atoms = xcalloc(2, sizeof(Atom));
497 if (!InitValuatorClassDeviceStruct(device,
498 num_axes,
499 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
500 atoms,
501 #endif
502 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
503 GetMotionHistory,
504 #endif
505 GetMotionHistorySize(),
507 return BadAlloc;
509 /* Use absolute mode. Currently, TUIO coords are mapped to the
510 * full screen area */
511 pInfo->dev->valuator->mode = Absolute;
512 if (!InitAbsoluteClassDeviceStruct(device))
513 return BadAlloc;
515 for (i = 0; i < num_axes; i++)
517 xf86InitValuatorAxisStruct(device, i,
518 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
519 atoms[i],
520 #endif
521 0, 0x7FFFFFFF, 1, 1, 1);
522 xf86InitValuatorDefaults(device, i);
524 return Success;