Fixed typos, thanks Martin
[xf86-input-tuio.git] / src / tuio.c
blob7372f1d790e0e7dd07bb12d87a04eb5f50ac650d
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>
32 #include <xf86_OSlib.h>
34 #include "tuio.h"
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
40 /* InputInfoPtr for main tuio device */
41 static InputInfoPtr g_pInfo;
42 static int pipefd[2] = {-1, -1};
44 /* Module Functions */
45 static pointer
46 TuioPlug(pointer, pointer, int *, int *);
48 static void
49 TuioUnplug(pointer);
51 /* Driver Functions */
52 static InputInfoPtr
53 TuioPreInit(InputDriverPtr, IDevPtr, int);
55 static void
56 TuioUnInit(InputDriverPtr, InputInfoPtr, int);
58 static void
59 TuioObjReadInput(InputInfoPtr pInfo);
61 static void
62 TuioReadInput(InputInfoPtr);
64 static int
65 TuioControl(DeviceIntPtr, int);
67 /* Internal Functions */
68 static int
69 _hal_create_devices(InputInfoPtr pInfo, int num);
71 static int
72 _init_buttons(DeviceIntPtr device);
74 static int
75 _init_axes(DeviceIntPtr device);
77 static int
78 _tuio_lo_2dcur_handle(const char *path,
79 const char *types,
80 lo_arg **argv,
81 int argc,
82 void *data,
83 void *user_data);
85 static void
86 _free_tuiodev(TuioDevicePtr pTuio);
88 static void
89 _lo_error(int num,
90 const char *msg,
91 const char *path);
93 /* Object and Subdev list manipulation functions */
94 static ObjectPtr
95 _object_get(ObjectPtr head, int id);
97 static ObjectPtr
98 _object_new(int id);
100 static void
101 _object_add(ObjectPtr *obj_list, ObjectPtr obj);
103 static ObjectPtr
104 _object_remove(ObjectPtr *obj_list, int id);
106 static void
107 _subdev_add(InputInfoPtr pInfo, SubDevicePtr subdev);
109 static SubDevicePtr
110 _subdev_remove(InputInfoPtr pInfo, SubDevicePtr *subdev_list);
112 static SubDevicePtr
113 _subdev_remove_sd(SubDevicePtr *subdev_list, SubDevicePtr subdev);
115 static int
116 _hal_remove_device(InputInfoPtr pInfo);
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 num_subdev, tuio_port;
187 if (!(pInfo = xf86AllocateInput(drv, 0)))
188 return NULL;
190 /* If Type == Object, this is a device for an object to use */
191 type = xf86CheckStrOption(dev->commonOptions, "Type", NULL);
193 if (type != NULL && strcmp(type, "Object") == 0) {
194 xf86Msg(X_INFO, "%s: TUIO subdevice found\n", dev->identifier);
196 } else {
198 if (!(pTuio = xcalloc(1, sizeof(TuioDeviceRec)))) {
199 xf86DeleteInput(pInfo, 0);
200 return NULL;
202 g_pInfo = pInfo;
204 pInfo->private = pTuio;
206 pTuio->num_subdev = 0;
208 /* Get the number of subdevices we need to create */
209 num_subdev = xf86CheckIntOption(dev->commonOptions, "SubDevices",
210 DEFAULT_SUBDEVICES);
211 if (num_subdev > MAX_SUBDEVICES) {
212 num_subdev = MAX_SUBDEVICES;
213 } else if (num_subdev < MIN_SUBDEVICES) {
214 num_subdev = MIN_SUBDEVICES;
216 pTuio->init_num_subdev = num_subdev;
218 /* Get the TUIO port number to use */
219 tuio_port = xf86CheckIntOption(dev->commonOptions, "Port", DEFAULT_PORT);
220 if (tuio_port < 0 || tuio_port > 65535) {
221 xf86Msg(X_INFO, "%s: Invalid port number (%i), defaulting to %i\n",
222 dev->identifier, tuio_port, DEFAULT_PORT);
223 tuio_port = DEFAULT_PORT;
225 xf86Msg(X_INFO, "%s: TUIO UDP Port set to %i\n",
226 dev->identifier, tuio_port);
227 pTuio->tuio_port = tuio_port;
229 /* Get setting for checking fseq numbers in TUIO packets */
230 pTuio->fseq_threshold= xf86CheckIntOption(dev->commonOptions,
231 "FseqThreshold", 100);
232 if (pTuio->fseq_threshold < 0) {
233 pTuio->fseq_threshold = 0;
235 xf86Msg(X_INFO, "%s: FseqThreshold set to %i\n",
236 dev->identifier, pTuio->fseq_threshold);
238 /* Get setting for whether to send button events or not with
239 * object add & remove */
240 pTuio->post_button_events = xf86CheckBoolOption(dev->commonOptions,
241 "PostButtonEvents", True);
244 /* Allocate device storage and add to device list */
245 subdev = xcalloc(1, sizeof(SubDeviceRec));
246 subdev->pInfo = pInfo;
247 _subdev_add(g_pInfo, subdev);
249 /* Set up InputInfoPtr */
250 pInfo->name = xstrdup(dev->identifier);
251 pInfo->flags = 0;
252 pInfo->type_name = XI_TOUCHSCREEN; /* FIXME: Correct type? */
253 pInfo->conf_idev = dev;
254 pInfo->read_input = pTuio ? TuioReadInput : TuioObjReadInput; /* Set callback */
255 pInfo->device_control = TuioControl; /* Set callback */
256 pInfo->switch_mode = NULL;
258 /* Process common device options */
259 xf86CollectInputOptions(pInfo, NULL, NULL);
260 xf86ProcessCommonOptions(pInfo, pInfo->options);
262 pInfo->flags |= XI86_OPEN_ON_INIT;
263 pInfo->flags |= XI86_CONFIGURED;
265 return pInfo;
269 * Clean up
271 static void
272 TuioUnInit(InputDriverPtr drv,
273 InputInfoPtr pInfo,
274 int flags)
276 xf86DeleteInput(pInfo, 0);
280 * Empty callback for object device.
282 static void
283 TuioObjReadInput(InputInfoPtr pInfo) {
284 return;
288 * Handle new TUIO data on the socket
290 static void
291 TuioReadInput(InputInfoPtr pInfo)
293 TuioDevicePtr pTuio = pInfo->private;
294 ObjectPtr *obj_list = &pTuio->obj_list;
295 ObjectPtr obj = pTuio->obj_list;
296 SubDevicePtr *subdev_list = &pTuio->subdev_list;
297 ObjectPtr objtmp;
298 int valuators[2];
300 while (xf86WaitForInput(pInfo->fd, 0) > 0)
302 /* The liblo handler will set this flag if anything was processed */
303 pTuio->processed = 0;
305 /* liblo will receive a message and call the appropriate
306 * handlers (i.e. _tuio_lo_cur2d_hande()) */
307 lo_server_recv_noblock(pTuio->server, 0);
309 /* During the processing of the previous message/bundle,
310 * any "active" messages will be handled by flagging
311 * the listed object ids. Now that processing is done,
312 * remove any dead object ids and set any pending changes.
313 * Also check to make sure the processed data was newer than
314 * the last processed data */
315 if (pTuio->processed &&
316 (pTuio->fseq_new > pTuio->fseq_old ||
317 pTuio->fseq_old - pTuio->fseq_new > pTuio->fseq_threshold)) {
319 while (obj != NULL) {
320 if (!obj->alive) {
321 if (obj->subdev && pTuio->post_button_events) {
322 /* Post button "up" event */
323 xf86PostButtonEvent(obj->subdev->pInfo->dev, TRUE, 1, FALSE, 0, 0);
325 objtmp = obj->next;
326 obj = _object_remove(obj_list, obj->id);
327 _subdev_add(pInfo, obj->subdev);
328 xfree(obj);
329 obj = objtmp;
331 } else {
332 /* Object is alive. Check to see if an update has been set.
333 * If it has been updated and it has a subdevice to send
334 * events on, send the event) */
335 if (obj->pending.set && obj->subdev) {
336 obj->x = obj->pending.x;
337 obj->y = obj->pending.y;
338 obj->pending.set = False;
340 /* OKAY FOR NOW, maybe update with a better range? */
341 /* TODO: Add more valuators with additional information */
342 valuators[0] = obj->x * 0x7FFFFFFF;
343 valuators[1] = obj->y * 0x7FFFFFFF;
345 xf86PostMotionEventP(obj->subdev->pInfo->dev,
346 TRUE, /* is_absolute */
347 0, /* first_valuator */
348 2, /* num_valuators */
349 valuators);
351 if (obj->pending.button) {
352 xf86PostButtonEvent(obj->subdev->pInfo->dev, TRUE, 1, TRUE, 0, 0);
353 obj->pending.button = False;
356 obj->alive = 0; /* Reset for next message */
357 obj = obj->next;
360 pTuio->fseq_old = pTuio->fseq_new;
366 * Handle device state changes
368 static int
369 TuioControl(DeviceIntPtr device,
370 int what)
372 InputInfoPtr pInfo = device->public.devicePrivate;
373 TuioDevicePtr pTuio = pInfo->private;
374 char *tuio_port;
375 int res;
377 switch (what)
379 case DEVICE_INIT:
380 xf86Msg(X_INFO, "%s: Init\n", pInfo->name);
381 _init_buttons(device);
382 _init_axes(device);
384 /* If this is a "core" device, create object devices */
385 if (pTuio) {
386 _hal_create_devices(pInfo, pTuio->init_num_subdev);
388 break;
390 case DEVICE_ON: /* Open socket and start listening! */
391 xf86Msg(X_INFO, "%s: On.\n", pInfo->name);
392 if (device->public.on)
393 break;
395 /* If this is an object device, use a dummy pipe */
396 if (!pTuio) {
397 if (pipefd[0] == -1) {
398 SYSCALL(res = pipe(pipefd));
399 if (res == -1) {
400 xf86Msg(X_ERROR, "%s: failed to open pipe\n",
401 pInfo->name);
402 return BadAlloc;
406 pInfo->fd = pipefd[0];
408 goto finish;
411 /* Setup server */
412 asprintf(&tuio_port, "%i", pTuio->tuio_port);
413 pTuio->server = lo_server_new_with_proto(tuio_port, LO_UDP, _lo_error);
414 if (pTuio->server == NULL) {
415 xf86Msg(X_ERROR, "%s: Error allocating new lo_server\n",
416 pInfo->name);
417 return BadAlloc;
420 /* Register to receive all /tuio/2Dcur messages */
421 lo_server_add_method(pTuio->server, "/tuio/2Dcur", NULL,
422 _tuio_lo_2dcur_handle, pInfo);
424 pInfo->fd = lo_server_get_socket_fd(pTuio->server);
426 xf86FlushInput(pInfo->fd);
428 finish: xf86AddEnabledDevice(pInfo);
429 device->public.on = TRUE;
430 break;
432 case DEVICE_OFF:
433 xf86Msg(X_INFO, "%s: Off\n", pInfo->name);
434 if (!device->public.on)
435 break;
437 xf86RemoveEnabledDevice(pInfo);
439 if (pTuio) {
440 lo_server_free(pTuio->server);
441 pInfo->fd = -1;
444 device->public.on = FALSE;
445 break;
447 case DEVICE_CLOSE:
448 xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
449 _hal_remove_device(pInfo);
450 break;
453 return Success;
457 * Initialize the device properties
458 * TODO
460 TuioPropertyInit() {
464 * Free a TuioDeviceRec
466 static void
467 _free_tuiodev(TuioDevicePtr pTuio) {
468 ObjectPtr obj = pTuio->obj_list;
469 ObjectPtr tmp;
471 while (obj != NULL) {
472 tmp = obj->next;
473 xfree(obj);
474 obj = tmp;
477 xfree(pTuio);
481 * Handles OSC messages in the /tuio/2Dcur address space
483 static int
484 _tuio_lo_2dcur_handle(const char *path,
485 const char *types,
486 lo_arg **argv,
487 int argc,
488 void *data,
489 void *user_data) {
490 InputInfoPtr pInfo = user_data;
491 TuioDevicePtr pTuio = pInfo->private;
492 ObjectPtr *obj_list = &pTuio->obj_list;
493 ObjectPtr obj, objtemp;
494 char *act;
495 int i;
497 if (argc == 0) {
498 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d (argc == 0)\n",
499 pInfo->name);
500 return 0;
501 } else if(*types != 's') {
502 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d (types[0] != 's')\n",
503 pInfo->name);
504 return 0;
507 /* Flag as being processed, used in TuioReadInput() */
508 pTuio->processed = 1;
510 /* Parse message type */
511 /* Set message type: */
512 if (strcmp((char *)argv[0], "set") == 0) {
514 /* Simple type check */
515 if (strcmp(types, "sifffff")) {
516 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d set msg (types == %s)\n",
517 pInfo->name, types);
518 return 0;
521 obj = _object_get(*obj_list, argv[1]->i);
523 /* If not found, create a new object */
524 if (obj == NULL) {
525 obj = _object_new(argv[1]->i);
526 _object_add(obj_list, obj);
527 obj->subdev = _subdev_remove(pInfo, &pTuio->subdev_list);
528 if (obj->subdev && pTuio->post_button_events)
529 obj->pending.button = True;
532 obj->pending.x = argv[2]->f;
533 obj->pending.y = argv[3]->f;
534 obj->pending.set = True;
536 } else if (strcmp((char *)argv[0], "alive") == 0) {
537 /* Mark all objects that are still alive */
538 obj = *obj_list;
539 while (obj != NULL) {
540 for (i=1; i<argc; i++) {
541 if (argv[i]->i == obj->id) {
542 obj->alive = True;
543 break;
546 obj = obj->next;
549 } else if (strcmp((char *)argv[0], "fseq") == 0) {
550 /* Simple type check */
551 if (strcmp(types, "si")) {
552 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d fseq msg (types == %s)\n",
553 pInfo->name, types);
554 return 0;
556 pTuio->fseq_new = argv[1]->i;
559 return 0;
563 * liblo error handler
565 static void
566 _lo_error(int num,
567 const char *msg,
568 const char *path)
570 xf86Msg(X_ERROR, "liblo: %s\n", msg);
574 * Retrieves an object from a list based on its id.
576 * @return NULL if not found.
578 static ObjectPtr
579 _object_get(ObjectPtr head, int id) {
580 ObjectPtr obj = head;
582 while (obj != NULL && obj->id != id) {
583 obj = obj->next;
586 return obj;
590 * Allocates and inserts a new object at the beginning of a list.
591 * Pointer to the new object is returned.
592 * Doesn't check for duplicate ids, so call _object_get() beforehand
593 * to make sure it doesn't exist already!!
595 * @return ptr to newly inserted object
597 static ObjectPtr
598 _object_new(int id) {
599 ObjectPtr new_obj = xcalloc(1, sizeof(ObjectRec));
601 new_obj->id = id;
602 new_obj->alive = True;
604 return new_obj;
608 * Adds a SubDevice to the beginning of the subdev_list list
610 static void
611 _object_add(ObjectPtr *obj_list, ObjectPtr obj) {
613 if (obj_list == NULL || obj == NULL)
614 return;
616 if (*obj_list != NULL) {
617 obj->next = *obj_list;
619 *obj_list = obj;
624 * Removes an Object with a specific id from a list.
626 static ObjectPtr
627 _object_remove(ObjectPtr *obj_list, int id) {
628 ObjectPtr obj = *obj_list;
629 ObjectPtr objtmp;
631 if (obj == NULL) return; /* Empty list */
633 if (obj->id == id) { /* Remove from head */
634 *obj_list = obj->next;
635 } else {
636 while (obj->next != NULL) {
637 if (obj->next->id == id) {
638 objtmp = obj->next;
639 obj->next = objtmp->next;
640 obj = objtmp;
641 obj->next = NULL;
642 return obj;
644 obj = obj->next;
646 obj = NULL;
649 return obj;
653 * Adds a SubDevice to the beginning of the subdev_list list
655 static void
656 _subdev_add(InputInfoPtr pInfo, SubDevicePtr subdev) {
657 TuioDevicePtr pTuio = pInfo->private;
658 SubDevicePtr *subdev_list = &pTuio->subdev_list;
659 ObjectPtr obj = pTuio->obj_list;
661 if (subdev_list == NULL || subdev == NULL)
662 return;
664 /* First check to see if there are any objects that don't have a
665 * subdevice that we can assign this subdevice to */
666 while (obj != NULL) {
667 if (obj->subdev == NULL) {
668 obj->subdev = subdev;
669 if (pTuio->post_button_events)
670 obj->pending.button = True;
671 obj->pending.set = True;
672 return;
674 obj = obj->next;
677 /* No subdevice-less objects, add to front of subdev list */
678 if (*subdev_list != NULL) {
679 subdev->next = *subdev_list;
681 *subdev_list = subdev;
685 * Removes a SubDevice from the subdev_list list
687 static SubDevicePtr
688 _subdev_remove(InputInfoPtr pInfo, SubDevicePtr *subdev_list) {
689 SubDevicePtr subdev;
691 if (subdev_list == NULL || *subdev_list == NULL) {
692 _hal_create_devices(pInfo, 1); /* Create one new subdevice */
693 return NULL;
696 subdev = *subdev_list;
697 *subdev_list = subdev->next;
698 subdev->next = NULL;
700 return subdev;
704 * Init the button map device. We only use one button.
706 static int
707 _init_buttons(DeviceIntPtr device)
709 InputInfoPtr pInfo = device->public.devicePrivate;
710 CARD8 *map;
711 Atom *labels;
712 int numbuttons = 4;
713 int ret = Success;
714 int i;
716 map = xcalloc(numbuttons, sizeof(CARD8));
717 labels = xcalloc(numbuttons, sizeof(Atom));
718 for (i=0; i<numbuttons; i++)
719 map[i] = i;
721 if (!InitButtonClassDeviceStruct(device, numbuttons /* 1 button */,
722 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
723 labels,
724 #endif
725 map)) {
726 xf86Msg(X_ERROR, "%s: Failed to register buttons.\n", pInfo->name);
727 ret = BadAlloc;
730 xfree(labels);
731 return ret;
735 * Init valuators for device, use x/y coordinates.
737 static int
738 _init_axes(DeviceIntPtr device)
740 InputInfoPtr pInfo = device->public.devicePrivate;
741 int i;
742 const int num_axes = 2;
743 Atom *atoms;
745 atoms = xcalloc(num_axes, sizeof(Atom));
747 if (!InitValuatorClassDeviceStruct(device,
748 num_axes,
749 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
750 atoms,
751 #endif
752 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
753 GetMotionHistory,
754 #endif
755 GetMotionHistorySize(),
757 return BadAlloc;
759 /* Use absolute mode. Currently, TUIO coords are mapped to the
760 * full screen area */
761 pInfo->dev->valuator->mode = Absolute;
762 if (!InitAbsoluteClassDeviceStruct(device))
763 return BadAlloc;
765 for (i = 0; i < num_axes; i++)
767 xf86InitValuatorAxisStruct(device, i,
768 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
769 atoms[i],
770 #endif
771 0, 0x7FFFFFFF, 1, 1, 1);
772 xf86InitValuatorDefaults(device, i);
774 return Success;
778 * New device creation through hal
779 * I referenced the wacom hal-setup patch while writing this:
780 * http://cvs.fedoraproject.org/viewvc/rpms/linuxwacom/devel/linuxwacom-0.8.2.2-hal-setup.patch?revision=1.1&view=markup
782 * @return 0 if successful, 1 if failure
784 static int
785 _hal_create_devices(InputInfoPtr pInfo, int num) {
786 TuioDevicePtr pTuio = pInfo->private;
787 DBusError error;
788 DBusConnection *conn;
789 LibHalContext *ctx;
790 char *newdev;
791 char *name;
792 int i;
794 /* We need a new device to send motion/button events through.
795 * There isn't a great way to do this right now without native
796 * blob events, so just hack it out for now. Woot. */
798 /* Open connection to dbus and create contex */
799 dbus_error_init(&error);
800 if ((conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) {
801 xf86Msg(X_ERROR, "%s: Failed to open dbus connection: %s\n",
802 pInfo->name, error.message);
803 return 1;
806 if ((ctx = libhal_ctx_new()) == NULL) {
807 xf86Msg(X_ERROR, "%s: Failed to obtain hal context\n",
808 pInfo->name);
809 return 1;
812 dbus_error_init(&error);
813 libhal_ctx_set_dbus_connection(ctx, conn);
814 if (!libhal_ctx_init(ctx, &error)) {
815 xf86Msg(X_ERROR, "%s: Failed to initialize hal context: %s\n",
816 pInfo->name, error.message);
817 return 1;
820 /* Create new devices through hal */
821 for (i=0; i<num; i++) {
823 dbus_error_init(&error);
824 newdev = libhal_new_device(ctx, &error);
825 if (dbus_error_is_set(&error) == TRUE) {
826 xf86Msg(X_ERROR, "%s: Failed to create input device: %s\n",
827 pInfo->name, error.message);
828 return 1;
831 dbus_error_init(&error);
832 libhal_device_set_property_string(ctx, newdev, "input.device",
833 "tuio_subdevice", &error);
834 if (dbus_error_is_set(&error) == TRUE) {
835 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
836 pInfo->name, error.message);
837 return 1;
840 dbus_error_init(&error);
841 libhal_device_set_property_bool(ctx, newdev, "RequireEnable",
842 False, &error);
843 if (dbus_error_is_set(&error) == TRUE) {
844 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
845 pInfo->name, error.message);
846 return 1;
849 dbus_error_init(&error);
850 libhal_device_set_property_string(ctx, newdev,
851 "input.x11_driver", "tuio",
852 &error);
853 if (dbus_error_is_set(&error) == TRUE) {
854 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
855 pInfo->name, error.message);
856 return 1;
859 /* Set "Type" property. This will be used in TuioPreInit to determine
860 * whether the new device is a subdev or not */
861 dbus_error_init(&error);
862 libhal_device_set_property_string(ctx, newdev,
863 "input.x11_options.Type",
864 "Object", &error);
865 if (dbus_error_is_set(&error) == TRUE) {
866 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
867 pInfo->name, error.message);
868 return 1;
871 asprintf(&name, "%s subdev %i", pInfo->name, pTuio->num_subdev);
873 /* Set name */
874 dbus_error_init(&error);
875 libhal_device_set_property_string(ctx, newdev,
876 "info.product", name,
877 &error);
878 if (dbus_error_is_set(&error) == TRUE) {
879 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
880 pInfo->name, error.message);
881 return 1;
884 /* Finalize creation of new device */
885 dbus_error_init(&error);
886 libhal_device_commit_to_gdl(ctx, newdev, "/org/freedesktop/Hal/devices/tuio_subdev", &error);
887 if (dbus_error_is_set (&error) == TRUE) {
888 xf86Msg(X_ERROR, "%s: Failed to add input device: %s\n",
889 pInfo->name, error.message);
890 return 1;
893 xfree(name);
894 pTuio->num_subdev++;
897 if (!libhal_ctx_shutdown(ctx, &error)) {
898 xf86Msg(X_ERROR, "%s: Unable to shutdown hal context: %s\n",
899 pInfo->name, error.message);
900 return 1;
902 libhal_ctx_free(ctx);
904 return 0;
907 static int
908 _hal_remove_device(InputInfoPtr pInfo) {
909 DBusError error;
910 DBusConnection *conn;
911 LibHalContext *ctx;
912 char** devices;
913 int i, num_devices;
915 xf86Msg(X_INFO, "%s: Removing subdevice\n",
916 pInfo->name);
918 /* Open connection to dbus and create contex */
919 dbus_error_init(&error);
920 if ((conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) {
921 xf86Msg(X_ERROR, "%s: Failed to open dbus connection: %s\n",
922 pInfo->name, error.message);
923 return 1;
926 if ((ctx = libhal_ctx_new()) == NULL) {
927 xf86Msg(X_ERROR, "%s: Failed to obtain hal context\n",
928 pInfo->name);
929 return 1;
932 dbus_error_init(&error);
933 libhal_ctx_set_dbus_connection(ctx, conn);
934 if (!libhal_ctx_init(ctx, &error)) {
935 xf86Msg(X_ERROR, "%s: Failed to initialize hal context: %s\n",
936 pInfo->name, error.message);
937 return 1;
940 devices = libhal_manager_find_device_string_match(ctx, "info.product",
941 pInfo->name,
942 &num_devices,
943 &error);
944 if (dbus_error_is_set(&error) == TRUE) {
945 xf86Msg(X_ERROR, "%s: Failed when trying to find device: %s\n",
946 pInfo->name, error.message);
947 return 1;
950 if (num_devices == 0) {
951 xf86Msg(X_ERROR, "%s: Unable to find subdevice in HAL GDL\n",
952 pInfo->name);
953 } else {
954 for (i=0; i<num_devices; i++) {
955 xf86Msg(X_INFO, "%s: Removing subdevice with udi '%s'\n",
956 pInfo->name, devices[i]);
957 if (!libhal_remove_device(ctx, devices[i], &error)) {
958 xf86Msg(X_ERROR, "%s: Unable to remove subdevice: %s\n",
959 pInfo->name, error.message);
964 if (!libhal_ctx_shutdown(ctx, &error)) {
965 xf86Msg(X_ERROR, "%s: Unable to shutdown hal context: %s\n",
966 pInfo->name, error.message);
967 return 1;
969 libhal_ctx_free(ctx);
971 return 0;