Removed FseqCheck option and instead replaced with FseqThreshold option
[xf86-input-tuio.git] / src / tuio.c
blob09aa6bbbfbb087a6ec4aa8c4c3b1c7dbd54f2a42
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>
31 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
32 #include <X11/extensions/XInput2.h>
33 #endif
35 #include <xf86_OSlib.h>
37 #include "tuio.h"
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
43 /* InputInfoPtr for main tuio device */
44 static TuioDevicePtr g_pTuio;
45 static int pipefd[2] = {-1, -1};
47 /* Module Functions */
48 static pointer
49 TuioPlug(pointer, pointer, int *, int *);
51 static void
52 TuioUnplug(pointer);
54 /* Driver Functions */
55 static InputInfoPtr
56 TuioPreInit(InputDriverPtr, IDevPtr, int);
58 static void
59 TuioUnInit(InputDriverPtr, InputInfoPtr, int);
61 static void
62 TuioObjReadInput(InputInfoPtr pInfo);
64 static void
65 TuioReadInput(InputInfoPtr);
67 static int
68 TuioControl(DeviceIntPtr, int);
70 /* Internal Functions */
71 static int
72 _init_devices(InputInfoPtr pInfo, int num);
74 static int
75 _tuio_init_buttons(DeviceIntPtr device);
77 static int
78 _tuio_init_axes(DeviceIntPtr device);
80 static int
81 _tuio_lo_cur2d_handle(const char *path,
82 const char *types,
83 lo_arg **argv,
84 int argc,
85 void *data,
86 void *user_data);
88 static void
89 _free_tuiodev(TuioDevicePtr pTuio);
91 static void
92 _lo_error(int num,
93 const char *msg,
94 const char *path);
96 /* Object list manipulation functions */
97 static ObjectPtr
98 _object_get(ObjectPtr head, int id);
100 static ObjectPtr
101 _object_new(int id);
103 static void
104 _object_add(ObjectPtr *obj_list, ObjectPtr obj);
106 static ObjectPtr
107 _object_remove(ObjectPtr *obj_list, int id);
109 static void
110 _subdev_add(SubDevicePtr *subdev_list, SubDevicePtr subdev);
112 static SubDevicePtr
113 _subdev_remove(SubDevicePtr *subdev_list);
115 static SubDevicePtr
116 _subdev_remove_sd(SubDevicePtr *subdev_list, SubDevicePtr subdev);
118 /* Driver information */
119 static XF86ModuleVersionInfo TuioVersionRec =
121 "tuio",
122 MODULEVENDORSTRING,
123 MODINFOSTRING1,
124 MODINFOSTRING2,
125 XORG_VERSION_CURRENT,
126 PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
127 ABI_CLASS_XINPUT,
128 ABI_XINPUT_VERSION,
129 MOD_CLASS_XINPUT,
130 {0, 0, 0, 0}
133 _X_EXPORT InputDriverRec TUIO =
136 "tuio",
137 NULL,
138 TuioPreInit,
139 TuioUnInit,
140 NULL,
144 _X_EXPORT XF86ModuleData tuioModuleData =
146 &TuioVersionRec,
147 TuioPlug,
148 TuioUnplug
151 static pointer
152 TuioPlug(pointer module,
153 pointer options,
154 int *errmaj,
155 int *errmin)
157 xf86AddInputDriver(&TUIO, module, 0);
158 return module;
162 * Unplug
164 static void
165 TuioUnplug(pointer p)
170 * Pre-initialization of new device
171 * This can be entered by either a "core" tuio device
172 * or an extension "Object" device that is used for routing individual object
173 * events through.
175 static InputInfoPtr
176 TuioPreInit(InputDriverPtr drv,
177 IDevPtr dev,
178 int flags)
180 InputInfoPtr pInfo;
181 TuioDevicePtr pTuio = NULL;
182 ObjectPtr obj;
183 SubDevicePtr subdev;
184 char *type;
185 int id;
186 int num_subdev, tuio_port;
188 if (!(pInfo = xf86AllocateInput(drv, 0)))
189 return NULL;
191 /* If Type == Object, this is a device for an object to use */
192 type = xf86CheckStrOption(dev->commonOptions, "Type", NULL);
194 if (type != NULL && strcmp(type, "Object") == 0) {
196 xf86Msg(X_INFO, "%s: Object device found\n", dev->identifier);
198 } else {
200 if (!(pTuio = xcalloc(1, sizeof(TuioDeviceRec)))) {
201 xf86DeleteInput(pInfo, 0);
202 return NULL;
204 g_pTuio = pTuio;
206 pInfo->private = pTuio;
208 /* Get the number of subdevices we need to create */
209 num_subdev = xf86CheckIntOption(dev->commonOptions, "SubDevices", 5);
210 if (num_subdev > MAX_SUBDEVICES) {
211 num_subdev = MAX_SUBDEVICES;
212 } else if (num_subdev < MIN_SUBDEVICES) {
213 num_subdev = MIN_SUBDEVICES;
215 pTuio->num_subdev = num_subdev;
217 /* Get the TUIO port number to use */
218 tuio_port = xf86CheckIntOption(dev->commonOptions, "Port", DEFAULT_PORT);
219 if (tuio_port < 0 || tuio_port > 65535) {
220 xf86Msg(X_INFO, "%s: Invalid port number (%i), defaulting to %i\n",
221 dev->identifier, tuio_port, DEFAULT_PORT);
222 tuio_port = DEFAULT_PORT;
224 pTuio->tuio_port = tuio_port;
226 /* Get setting for checking fseq numbers in TUIO packets */
227 pTuio->fseq_threshold= xf86CheckIntOption(dev->commonOptions,
228 "FseqThreshold", 100);
229 if (pTuio->fseq_threshold != 100) {
230 xf86Msg(X_INFO, "%s: FseqThreshold set to %i\n",
231 dev->identifier, pTuio->fseq_threshold);
235 /* Allocate device storage and add to device list */
236 subdev = xcalloc(1, sizeof(SubDeviceRec));
237 subdev->pInfo = pInfo;
238 _subdev_add(&g_pTuio->subdev_list, subdev);
240 /* Set up InputInfoPtr */
241 pInfo->name = xstrdup(dev->identifier);
242 pInfo->flags = 0;
243 pInfo->type_name = XI_TOUCHSCREEN; /* FIXME: Correct type? */
244 pInfo->conf_idev = dev;
245 pInfo->read_input = pTuio ? TuioReadInput : TuioObjReadInput; /* Set callback */
246 pInfo->device_control = TuioControl; /* Set callback */
247 pInfo->switch_mode = NULL;
249 /* Process common device options */
250 xf86CollectInputOptions(pInfo, NULL, NULL);
251 xf86ProcessCommonOptions(pInfo, pInfo->options);
253 pInfo->flags |= XI86_OPEN_ON_INIT;
254 pInfo->flags |= XI86_CONFIGURED;
256 return pInfo;
260 * Clean up
262 static void
263 TuioUnInit(InputDriverPtr drv,
264 InputInfoPtr pInfo,
265 int flags)
267 xf86DeleteInput(pInfo, 0);
271 * Empty callback for object device.
273 static void
274 TuioObjReadInput(InputInfoPtr pInfo) {
275 return;
279 * Handle new TUIO data on the socket
281 static void
282 TuioReadInput(InputInfoPtr pInfo)
284 TuioDevicePtr pTuio = pInfo->private;
285 ObjectPtr *obj_list = &pTuio->obj_list;
286 ObjectPtr obj = pTuio->obj_list;
287 SubDevicePtr *subdev_list = &pTuio->subdev_list;
288 ObjectPtr objtmp;
289 int valuators[2];
291 while(xf86WaitForInput(pInfo->fd, 0) > 0)
293 /* The liblo handler will set this flag if anything was processed */
294 pTuio->processed = 0;
296 /* liblo will receive a message and call the appropriate
297 * handlers (i.e. _tuio_lo_cur2d_hande()) */
298 lo_server_recv_noblock(pTuio->server, 0);
300 /* During the processing of the previous message/bundle,
301 * any "active" messages will be handled by flagging
302 * the listed object ids. Now that processing is done,
303 * remove any dead object ids and set any pending changes.
304 * Also check to make sure the processed data was newer than
305 * the last processed data */
306 if (pTuio->processed &&
307 (pTuio->fseq_new > pTuio->fseq_old ||
308 pTuio->fseq_old - pTuio->fseq_new > pTuio->fseq_threshold)) {
310 while (obj != NULL) {
311 if (!obj->alive) {
312 if (obj->subdev) {
313 /* Post button "up" event */
314 xf86PostButtonEvent(obj->subdev->pInfo->dev, TRUE, 1, FALSE, 0, 0);
316 objtmp = obj->next;
317 obj = _object_remove(obj_list, obj->id);
318 _subdev_add(subdev_list, obj->subdev);
319 xfree(obj);
320 obj = objtmp;
322 } else {
323 if (obj->pending.set && obj->subdev) {
324 obj->x = obj->pending.x;
325 obj->y = obj->pending.y;
326 obj->pending.set = False;
328 if (obj->subdev) {
329 /* OKAY FOR NOW, MAYBE UPDATE */
330 /* TODO: Add more valuators with additional information */
331 valuators[0] = obj->x * 0x7FFFFFFF;
332 valuators[1] = obj->y * 0x7FFFFFFF;
334 xf86PostMotionEventP(obj->subdev->pInfo->dev,
335 TRUE, /* is_absolute */
336 0, /* first_valuator */
337 2, /* num_valuators */
338 valuators);
341 obj->alive = 0; /* Reset for next message */
342 obj = obj->next;
345 pTuio->fseq_old = pTuio->fseq_new;
351 * Handle device state changes
353 static int
354 TuioControl(DeviceIntPtr device,
355 int what)
357 InputInfoPtr pInfo = device->public.devicePrivate;
358 TuioDevicePtr pTuio = pInfo->private;
359 char *tuio_port;
360 int res;
362 switch (what)
364 case DEVICE_INIT:
365 xf86Msg(X_INFO, "%s: Init\n", pInfo->name);
366 _tuio_init_buttons(device);
367 _tuio_init_axes(device);
369 /* If this is a "core" device, create object devices */
370 if (pTuio) {
371 _init_devices(pInfo, pTuio->num_subdev - 1);
373 break;
375 case DEVICE_ON: /* Open socket and start listening! */
376 xf86Msg(X_INFO, "%s: On.\n", pInfo->name);
377 if (device->public.on)
378 break;
380 /* If this is an object device, use a dummy pipe */
381 if (!pTuio) {
382 if (pipefd[0] == -1) {
383 SYSCALL(res = pipe(pipefd));
384 if (res == -1) {
385 xf86Msg(X_ERROR, "%s: failed to open pipe\n",
386 pInfo->name);
387 return BadAlloc;
391 pInfo->fd = pipefd[0];
393 goto finish;
396 /* Setup server */
397 asprintf(&tuio_port, "%i", pTuio->tuio_port);
398 pTuio->server = lo_server_new_with_proto(tuio_port, LO_UDP, _lo_error);
399 if (pTuio->server == NULL) {
400 xf86Msg(X_ERROR, "%s: Error allocating new lo_server\n",
401 pInfo->name);
402 return BadAlloc;
405 /* Register to receive all /tuio/2Dcur messages */
406 lo_server_add_method(pTuio->server, "/tuio/2Dcur", NULL,
407 _tuio_lo_cur2d_handle, pInfo);
409 pInfo->fd = lo_server_get_socket_fd(pTuio->server);
411 xf86FlushInput(pInfo->fd);
413 finish: xf86AddEnabledDevice(pInfo);
414 device->public.on = TRUE;
415 break;
417 case DEVICE_OFF:
418 xf86Msg(X_INFO, "%s: Off\n", pInfo->name);
419 if (!device->public.on)
420 break;
422 xf86RemoveEnabledDevice(pInfo);
424 if (pTuio) {
425 lo_server_free(pTuio->server);
426 pInfo->fd = -1;
429 device->public.on = FALSE;
430 break;
432 case DEVICE_CLOSE:
433 xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
434 break;
437 return Success;
441 * Initialize the device properties
442 * TODO
444 TuioPropertyInit() {
448 * Free a TuioDeviceRec
450 static void
451 _free_tuiodev(TuioDevicePtr pTuio) {
452 ObjectPtr obj = pTuio->obj_list;
453 ObjectPtr tmp;
455 while (obj != NULL) {
456 tmp = obj->next;
457 xfree(obj);
458 obj = tmp;
461 xfree(pTuio);
465 * Handles OSC messages in the /tuio/2Dcur address space
467 static int
468 _tuio_lo_cur2d_handle(const char *path,
469 const char *types,
470 lo_arg **argv,
471 int argc,
472 void *data,
473 void *user_data) {
474 InputInfoPtr pInfo = user_data;
475 TuioDevicePtr pTuio = pInfo->private;
476 ObjectPtr *obj_list = &pTuio->obj_list;
477 ObjectPtr obj, objtemp;
478 char *act;
479 int i;
481 if (argc == 0) {
482 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d (argc == 0)\n",
483 pInfo->name);
484 return 0;
485 } else if(*types != 's') {
486 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d (types[0] != 's')\n",
487 pInfo->name);
488 return 0;
491 /* Flag as being processed, used in TuioReadInput() */
492 pTuio->processed = 1;
494 /* Parse message type */
495 /* Set message type: */
496 if (strcmp((char *)argv[0], "set") == 0) {
498 /* Simple type check */
499 if (strcmp(types, "sifffff")) {
500 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d set msg (types == %s)\n",
501 pInfo->name, types);
502 return 0;
505 obj = _object_get(*obj_list, argv[1]->i);
507 /* If not found, create a new object */
508 if (obj == NULL) {
509 obj = _object_new(argv[1]->i);
510 _object_add(obj_list, obj);
511 obj->subdev = _subdev_remove(&pTuio->subdev_list);
512 if (obj->subdev)
513 xf86PostButtonEvent(obj->subdev->pInfo->dev, TRUE, 1, TRUE, 0, 0);
516 obj->pending.x = argv[2]->f;
517 obj->pending.y = argv[3]->f;
518 obj->pending.set = True;
520 } else if (strcmp((char *)argv[0], "alive") == 0) {
522 /* Mark all objects that are still alive */
523 obj = *obj_list;
524 while (obj != NULL) {
525 for (i=1; i<argc; i++) {
526 if (argv[i]->i == obj->id) {
527 obj->alive = True;
528 break;
531 obj = obj->next;
534 } else if (strcmp((char *)argv[0], "fseq") == 0) {
535 /* Simple type check */
536 if (strcmp(types, "si")) {
537 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d fseq msg (types == %s)\n",
538 pInfo->name, types);
539 return 0;
541 pTuio->fseq_new = argv[1]->i;
544 return 0;
548 * liblo error handler
550 static void
551 _lo_error(int num,
552 const char *msg,
553 const char *path)
555 xf86Msg(X_ERROR, "liblo: %s\n", msg);
559 * Retrieves an object from a list based on its id.
561 * @return NULL if not found.
563 static ObjectPtr
564 _object_get(ObjectPtr head, int id) {
565 ObjectPtr obj = head;
567 while (obj != NULL && obj->id != id) {
568 obj = obj->next;
571 return obj;
575 * Allocates and inserts a new object at the beginning of a list.
576 * Pointer to the new object is returned.
577 * Doesn't check for duplicate ids, so call _object_get() beforehand
578 * to make sure it doesn't exist already!!
580 * @return ptr to newly inserted object
582 static ObjectPtr
583 _object_new(int id) {
584 ObjectPtr new_obj = xcalloc(1, sizeof(ObjectRec));
586 new_obj->id = id;
587 new_obj->alive = True;
589 return new_obj;
593 * Adds a SubDevice to the beginning of the subdev_list list
595 static void
596 _object_add(ObjectPtr *obj_list, ObjectPtr obj) {
597 if (obj_list == NULL || obj == NULL)
598 return;
600 if (*obj_list != NULL) {
601 obj->next = *obj_list;
603 *obj_list = obj;
608 * Removes an Object with a specific id from a list.
610 static ObjectPtr
611 _object_remove(ObjectPtr *obj_list, int id) {
612 ObjectPtr obj = *obj_list;
613 ObjectPtr objtmp;
615 if (obj == NULL) return; /* Empty list */
617 if (obj->id == id) { /* Remove from head */
618 *obj_list = obj->next;
619 } else {
620 while (obj->next != NULL) {
621 if (obj->next->id == id) {
622 objtmp = obj->next;
623 obj->next = objtmp->next;
624 obj = objtmp;
625 obj->next = NULL;
626 return obj;
628 obj = obj->next;
630 obj = NULL;
633 return obj;
637 * Adds a SubDevice to the beginning of the subdev_list list
639 static void
640 _subdev_add(SubDevicePtr *subdev_list, SubDevicePtr subdev) {
641 if (subdev_list == NULL || subdev == NULL)
642 return;
644 if (*subdev_list != NULL) {
645 subdev->next = *subdev_list;
647 *subdev_list = subdev;
651 * Removes a SubDevice from the subdev_list list
653 static SubDevicePtr
654 _subdev_remove(SubDevicePtr *subdev_list) {
655 SubDevicePtr subdev;
657 if (subdev_list == NULL || *subdev_list == NULL)
658 return NULL;
660 subdev = *subdev_list;
661 *subdev_list = subdev->next;
662 subdev->next = NULL;
664 return subdev;
668 * Init the button map device. We only use one button.
670 static int
671 _tuio_init_buttons(DeviceIntPtr device)
673 InputInfoPtr pInfo = device->public.devicePrivate;
674 CARD8 *map;
675 Atom *labels;
676 int numbuttons = 4;
677 int ret = Success;
678 int i;
680 map = xcalloc(numbuttons, sizeof(CARD8));
681 labels = xcalloc(1, sizeof(Atom));
682 for (i=0; i<numbuttons; i++)
683 map[i] = i;
685 if (!InitButtonClassDeviceStruct(device, numbuttons /* 1 button */,
686 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
687 labels,
688 #endif
689 map)) {
690 xf86Msg(X_ERROR, "%s: Failed to register buttons.\n", pInfo->name);
691 ret = BadAlloc;
694 xfree(labels);
695 return ret;
699 * Init valuators for device, use x/y coordinates.
701 static int
702 _tuio_init_axes(DeviceIntPtr device)
704 InputInfoPtr pInfo = device->public.devicePrivate;
705 int i;
706 const int num_axes = 2;
707 Atom *atoms;
709 atoms = xcalloc(num_axes, sizeof(Atom));
711 if (!InitValuatorClassDeviceStruct(device,
712 num_axes,
713 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
714 atoms,
715 #endif
716 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
717 GetMotionHistory,
718 #endif
719 GetMotionHistorySize(),
721 return BadAlloc;
723 /* Use absolute mode. Currently, TUIO coords are mapped to the
724 * full screen area */
725 pInfo->dev->valuator->mode = Absolute;
726 if (!InitAbsoluteClassDeviceStruct(device))
727 return BadAlloc;
729 for (i = 0; i < num_axes; i++)
731 xf86InitValuatorAxisStruct(device, i,
732 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
733 atoms[i],
734 #endif
735 0, 0x7FFFFFFF, 1, 1, 1);
736 xf86InitValuatorDefaults(device, i);
738 return Success;
742 * New device creation through hal
743 * I referenced the wacom hal-setup patch while writing this:
744 * http://cvs.fedoraproject.org/viewvc/rpms/linuxwacom/devel/linuxwacom-0.8.2.2-hal-setup.patch?revision=1.1&view=markup
746 * @return 0 if successful, 1 if failure
748 static int
749 _init_devices(InputInfoPtr pInfo, int num) {
750 DBusError error;
751 DBusConnection *conn;
752 LibHalContext *ctx;
753 char *newdev;
754 char *name;
755 int i;
757 /* We need a new device to send motion/button events through.
758 * There isn't a great way to do this right now without native
759 * blob events, so just hack it out for now. Woot. */
761 /* Open connection to dbus and create contex */
762 dbus_error_init(&error);
763 if ((conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) {
764 xf86Msg(X_ERROR, "%s: Failed to open dbus connection: %s\n",
765 pInfo->name, error.message);
766 return 1;
768 if ((ctx = libhal_ctx_new()) == NULL) {
769 xf86Msg(X_ERROR, "%s: Failed to obtain hal context: %s\n",
770 pInfo->name, error.message);
771 return 1;
774 dbus_error_init(&error);
775 libhal_ctx_set_dbus_connection(ctx, conn);
776 if (!libhal_ctx_init(ctx, &error)) {
777 xf86Msg(X_ERROR, "%s: Failed to initialize hal context: %s\n",
778 pInfo->name, error.message);
779 return 1;
782 /* Create new devices through hal */
783 for (i=0; i<num; i++) {
785 dbus_error_init(&error);
786 newdev = libhal_new_device(ctx, &error);
787 if (dbus_error_is_set(&error) == TRUE) {
788 xf86Msg(X_ERROR, "%s: Failed to create input device: %s\n",
789 pInfo->name, error.message);
790 return 1;
793 dbus_error_init(&error);
794 libhal_device_set_property_string(ctx, newdev, "input.device",
795 "blob", &error);
796 if (dbus_error_is_set(&error) == TRUE) {
797 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
798 pInfo->name, error.message);
799 return 1;
802 dbus_error_init(&error);
803 libhal_device_set_property_string(ctx, newdev,
804 "input.x11_driver", "tuio",
805 &error);
806 if (dbus_error_is_set(&error) == TRUE) {
807 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
808 pInfo->name, error.message);
809 return 1;
812 /* Set "Type" property. This will be used in TuioPreInit to determine
813 * whether the new device is an object device or not */
814 dbus_error_init(&error);
815 libhal_device_set_property_string(ctx, newdev,
816 "input.x11_options.Type",
817 "Object", &error);
818 if (dbus_error_is_set(&error) == TRUE) {
819 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
820 pInfo->name, error.message);
821 return 1;
824 asprintf(&name, "%s subdev %i", pInfo->name, i);
826 /* Set name */
827 dbus_error_init(&error);
828 libhal_device_set_property_string(ctx, newdev,
829 "info.product", name,
830 &error);
831 if (dbus_error_is_set(&error) == TRUE) {
832 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
833 pInfo->name, error.message);
834 return 1;
837 /* Finalize creation of new device */
838 dbus_error_init(&error);
839 libhal_device_commit_to_gdl(ctx, newdev, "/org/freedesktop/Hal/devices/tuio_subdev", &error);
840 if (dbus_error_is_set (&error) == TRUE) {
841 xf86Msg(X_ERROR, "%s: Failed to add input device: %s\n",
842 pInfo->name, error.message);
843 return 1;
846 xfree(name);
849 //libhal_context_free(ctx);
851 return 0;