Fixed bug in _subdev_remove when subdev list is empty
[xf86-input-tuio.git] / src / tuio.c
blob947a68121cdf0a852b3c9467830bea78c2d52ffe
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 void
110 _subdev_remove(InputInfoPtr pInfo, InputInfoPtr sub_pInfo);
112 static SubDevicePtr
113 _subdev_get(InputInfoPtr pInfo, SubDevicePtr *subdev_list);
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 char *type;
184 int num_subdev, tuio_port;
186 if (!(pInfo = xf86AllocateInput(drv, 0)))
187 return NULL;
189 /* If Type == Object, this is a device for an object to use */
190 type = xf86CheckStrOption(dev->commonOptions, "Type", NULL);
192 if (type != NULL && strcmp(type, "Object") == 0) {
193 xf86Msg(X_INFO, "%s: TUIO subdevice found\n", dev->identifier);
195 } else {
197 if (!(pTuio = xcalloc(1, sizeof(TuioDeviceRec)))) {
198 xf86DeleteInput(pInfo, 0);
199 return NULL;
201 g_pInfo = pInfo;
203 pInfo->private = pTuio;
205 pTuio->num_subdev = 0;
207 /* Get the number of subdevices we need to create */
208 num_subdev = xf86CheckIntOption(dev->commonOptions, "SubDevices",
209 DEFAULT_SUBDEVICES);
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->init_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 xf86Msg(X_INFO, "%s: TUIO UDP Port set to %i\n",
225 dev->identifier, tuio_port);
226 pTuio->tuio_port = tuio_port;
228 /* Get setting for checking fseq numbers in TUIO packets */
229 pTuio->fseq_threshold= xf86CheckIntOption(dev->commonOptions,
230 "FseqThreshold", 100);
231 if (pTuio->fseq_threshold < 0) {
232 pTuio->fseq_threshold = 0;
234 xf86Msg(X_INFO, "%s: FseqThreshold set to %i\n",
235 dev->identifier, pTuio->fseq_threshold);
237 /* Get setting for whether to send button events or not with
238 * object add & remove */
239 pTuio->post_button_events = xf86CheckBoolOption(dev->commonOptions,
240 "PostButtonEvents", True);
243 /* Set up InputInfoPtr */
244 pInfo->name = xstrdup(dev->identifier);
245 pInfo->flags = 0;
246 pInfo->type_name = XI_TOUCHSCREEN; /* FIXME: Correct type? */
247 pInfo->conf_idev = dev;
248 pInfo->read_input = pTuio ? TuioReadInput : TuioObjReadInput; /* Set callback */
249 pInfo->device_control = TuioControl; /* Set callback */
250 pInfo->switch_mode = NULL;
252 /* Process common device options */
253 xf86CollectInputOptions(pInfo, NULL, NULL);
254 xf86ProcessCommonOptions(pInfo, pInfo->options);
256 pInfo->flags |= XI86_OPEN_ON_INIT;
257 pInfo->flags |= XI86_CONFIGURED;
259 return pInfo;
263 * Clean up
265 static void
266 TuioUnInit(InputDriverPtr drv,
267 InputInfoPtr pInfo,
268 int flags)
270 xf86DeleteInput(pInfo, 0);
274 * Empty callback for object device.
276 static void
277 TuioObjReadInput(InputInfoPtr pInfo) {
278 return;
282 * Handle new TUIO data on the socket
284 static void
285 TuioReadInput(InputInfoPtr pInfo)
287 TuioDevicePtr pTuio = pInfo->private;
288 ObjectPtr *obj_list = &pTuio->obj_list;
289 ObjectPtr obj = pTuio->obj_list;
290 SubDevicePtr *subdev_list = &pTuio->subdev_list;
291 ObjectPtr objtmp;
292 int valuators[2];
294 while (xf86WaitForInput(pInfo->fd, 0) > 0)
296 /* The liblo handler will set this flag if anything was processed */
297 pTuio->processed = 0;
299 /* liblo will receive a message and call the appropriate
300 * handlers (i.e. _tuio_lo_cur2d_hande()) */
301 lo_server_recv_noblock(pTuio->server, 0);
303 /* During the processing of the previous message/bundle,
304 * any "active" messages will be handled by flagging
305 * the listed object ids. Now that processing is done,
306 * remove any dead object ids and set any pending changes.
307 * Also check to make sure the processed data was newer than
308 * the last processed data */
309 if (pTuio->processed &&
310 (pTuio->fseq_new > pTuio->fseq_old ||
311 pTuio->fseq_old - pTuio->fseq_new > pTuio->fseq_threshold)) {
313 while (obj != NULL) {
314 if (!obj->alive) {
315 if (obj->subdev && pTuio->post_button_events) {
316 /* Post button "up" event */
317 xf86PostButtonEvent(obj->subdev->pInfo->dev, TRUE, 1, FALSE, 0, 0);
319 objtmp = obj->next;
320 obj = _object_remove(obj_list, obj->id);
321 _subdev_add(pInfo, obj->subdev);
322 xfree(obj);
323 obj = objtmp;
325 } else {
326 /* Object is alive. Check to see if an update has been set.
327 * If it has been updated and it has a subdevice to send
328 * events on, send the event) */
329 if (obj->pending.set && obj->subdev) {
330 obj->x = obj->pending.x;
331 obj->y = obj->pending.y;
332 obj->pending.set = False;
334 /* OKAY FOR NOW, maybe update with a better range? */
335 /* TODO: Add more valuators with additional information */
336 valuators[0] = obj->x * 0x7FFFFFFF;
337 valuators[1] = obj->y * 0x7FFFFFFF;
339 xf86PostMotionEventP(obj->subdev->pInfo->dev,
340 TRUE, /* is_absolute */
341 0, /* first_valuator */
342 2, /* num_valuators */
343 valuators);
345 if (obj->pending.button) {
346 xf86PostButtonEvent(obj->subdev->pInfo->dev, TRUE, 1, TRUE, 0, 0);
347 obj->pending.button = False;
350 obj->alive = 0; /* Reset for next message */
351 obj = obj->next;
354 pTuio->fseq_old = pTuio->fseq_new;
360 * Handle device state changes
362 static int
363 TuioControl(DeviceIntPtr device,
364 int what)
366 InputInfoPtr pInfo = device->public.devicePrivate;
367 TuioDevicePtr pTuio = pInfo->private;
368 SubDevicePtr subdev;
369 char *tuio_port;
370 int res;
372 switch (what)
374 case DEVICE_INIT:
375 xf86Msg(X_INFO, "%s: Init\n", pInfo->name);
376 _init_buttons(device);
377 _init_axes(device);
379 /* If this is a "core" device, create object devices */
380 if (pTuio) {
381 _hal_create_devices(pInfo, pTuio->init_num_subdev);
383 break;
385 case DEVICE_ON: /* Open socket and start listening! */
386 xf86Msg(X_INFO, "%s: On.\n", pInfo->name);
387 if (device->public.on)
388 break;
390 /* If this is an object device, use a dummy pipe,
391 * and add device to subdev list */
392 if (!pTuio) {
393 if (pipefd[0] == -1) {
394 SYSCALL(res = pipe(pipefd));
395 if (res == -1) {
396 xf86Msg(X_ERROR, "%s: failed to open pipe\n",
397 pInfo->name);
398 return BadAlloc;
402 pInfo->fd = pipefd[0];
404 goto finish;
407 /* Setup server */
408 asprintf(&tuio_port, "%i", pTuio->tuio_port);
409 pTuio->server = lo_server_new_with_proto(tuio_port, LO_UDP, _lo_error);
410 if (pTuio->server == NULL) {
411 xf86Msg(X_ERROR, "%s: Error allocating new lo_server\n",
412 pInfo->name);
413 return BadAlloc;
416 /* Register to receive all /tuio/2Dcur messages */
417 lo_server_add_method(pTuio->server, "/tuio/2Dcur", NULL,
418 _tuio_lo_2dcur_handle, pInfo);
420 pInfo->fd = lo_server_get_socket_fd(pTuio->server);
422 xf86FlushInput(pInfo->fd);
424 finish: xf86AddEnabledDevice(pInfo);
425 device->public.on = TRUE;
427 /* Allocate device storage and add to device list */
428 subdev = xcalloc(1, sizeof(SubDeviceRec));
429 subdev->pInfo = pInfo;
430 _subdev_add(g_pInfo, subdev);
431 break;
433 case DEVICE_OFF:
434 xf86Msg(X_INFO, "%s: Off\n", pInfo->name);
435 if (!device->public.on)
436 break;
438 xf86RemoveEnabledDevice(pInfo);
440 if (pTuio) {
441 lo_server_free(pTuio->server);
442 pInfo->fd = -1;
444 /* Remove subdev from list - This applies for both subdevices
445 * and the "core" device */
446 _subdev_remove(g_pInfo, pInfo);
448 device->public.on = FALSE;
449 break;
451 case DEVICE_CLOSE:
452 xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
453 _hal_remove_device(pInfo);
454 break;
457 return Success;
461 * Initialize the device properties
462 * TODO
464 TuioPropertyInit() {
468 * Free a TuioDeviceRec
470 static void
471 _free_tuiodev(TuioDevicePtr pTuio) {
472 ObjectPtr obj = pTuio->obj_list;
473 ObjectPtr tmp;
475 while (obj != NULL) {
476 tmp = obj->next;
477 xfree(obj);
478 obj = tmp;
481 xfree(pTuio);
485 * Handles OSC messages in the /tuio/2Dcur address space
487 static int
488 _tuio_lo_2dcur_handle(const char *path,
489 const char *types,
490 lo_arg **argv,
491 int argc,
492 void *data,
493 void *user_data) {
494 InputInfoPtr pInfo = user_data;
495 TuioDevicePtr pTuio = pInfo->private;
496 ObjectPtr *obj_list = &pTuio->obj_list;
497 ObjectPtr obj, objtemp;
498 char *act;
499 int i;
501 if (argc == 0) {
502 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d (argc == 0)\n",
503 pInfo->name);
504 return 0;
505 } else if(*types != 's') {
506 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d (types[0] != 's')\n",
507 pInfo->name);
508 return 0;
511 /* Flag as being processed, used in TuioReadInput() */
512 pTuio->processed = 1;
514 /* Parse message type */
515 /* Set message type: */
516 if (strcmp((char *)argv[0], "set") == 0) {
518 /* Simple type check */
519 if (strcmp(types, "sifffff")) {
520 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d set msg (types == %s)\n",
521 pInfo->name, types);
522 return 0;
525 obj = _object_get(*obj_list, argv[1]->i);
527 /* If not found, create a new object */
528 if (obj == NULL) {
529 obj = _object_new(argv[1]->i);
530 _object_add(obj_list, obj);
531 obj->subdev = _subdev_get(pInfo, &pTuio->subdev_list);
532 if (obj->subdev && pTuio->post_button_events)
533 obj->pending.button = True;
536 obj->pending.x = argv[2]->f;
537 obj->pending.y = argv[3]->f;
538 obj->pending.set = True;
540 } else if (strcmp((char *)argv[0], "alive") == 0) {
541 /* Mark all objects that are still alive */
542 obj = *obj_list;
543 while (obj != NULL) {
544 for (i=1; i<argc; i++) {
545 if (argv[i]->i == obj->id) {
546 obj->alive = True;
547 break;
550 obj = obj->next;
553 } else if (strcmp((char *)argv[0], "fseq") == 0) {
554 /* Simple type check */
555 if (strcmp(types, "si")) {
556 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d fseq msg (types == %s)\n",
557 pInfo->name, types);
558 return 0;
560 pTuio->fseq_new = argv[1]->i;
563 return 0;
567 * liblo error handler
569 static void
570 _lo_error(int num,
571 const char *msg,
572 const char *path)
574 xf86Msg(X_ERROR, "liblo: %s\n", msg);
578 * Retrieves an object from a list based on its id.
580 * @return NULL if not found.
582 static ObjectPtr
583 _object_get(ObjectPtr head, int id) {
584 ObjectPtr obj = head;
586 while (obj != NULL && obj->id != id) {
587 obj = obj->next;
590 return obj;
594 * Allocates and inserts a new object at the beginning of a list.
595 * Pointer to the new object is returned.
596 * Doesn't check for duplicate ids, so call _object_get() beforehand
597 * to make sure it doesn't exist already!!
599 * @return ptr to newly inserted object
601 static ObjectPtr
602 _object_new(int id) {
603 ObjectPtr new_obj = xcalloc(1, sizeof(ObjectRec));
605 new_obj->id = id;
606 new_obj->alive = True;
608 return new_obj;
612 * Adds a SubDevice to the beginning of the subdev_list list
614 static void
615 _object_add(ObjectPtr *obj_list, ObjectPtr obj) {
617 if (obj_list == NULL || obj == NULL)
618 return;
620 if (*obj_list != NULL) {
621 obj->next = *obj_list;
623 *obj_list = obj;
628 * Removes an Object with a specific id from a list.
630 static ObjectPtr
631 _object_remove(ObjectPtr *obj_list, int id) {
632 ObjectPtr obj = *obj_list;
633 ObjectPtr objtmp;
635 if (obj == NULL) return; /* Empty list */
637 if (obj->id == id) { /* Remove from head */
638 *obj_list = obj->next;
639 } else {
640 while (obj->next != NULL) {
641 if (obj->next->id == id) {
642 objtmp = obj->next;
643 obj->next = objtmp->next;
644 obj = objtmp;
645 obj->next = NULL;
646 return obj;
648 obj = obj->next;
650 obj = NULL;
653 return obj;
657 * Adds a SubDevice to the beginning of the subdev_list list
659 static void
660 _subdev_add(InputInfoPtr pInfo, SubDevicePtr subdev) {
661 TuioDevicePtr pTuio = pInfo->private;
662 SubDevicePtr *subdev_list = &pTuio->subdev_list;
663 ObjectPtr obj = pTuio->obj_list;
665 if (subdev_list == NULL || subdev == NULL)
666 return;
668 /* First check to see if there are any objects that don't have a
669 * subdevice that we can assign this subdevice to */
670 while (obj != NULL) {
671 if (obj->subdev == NULL) {
672 obj->subdev = subdev;
673 if (pTuio->post_button_events)
674 obj->pending.button = True;
675 obj->pending.set = True;
676 return;
678 obj = obj->next;
681 /* No subdevice-less objects, add to front of subdev list */
682 if (*subdev_list != NULL) {
683 subdev->next = *subdev_list;
685 *subdev_list = subdev;
689 * Gets any available subdevice
691 static SubDevicePtr
692 _subdev_get(InputInfoPtr pInfo, SubDevicePtr *subdev_list) {
693 SubDevicePtr subdev;
695 if (subdev_list == NULL || *subdev_list == NULL) {
696 _hal_create_devices(pInfo, 1); /* Create one new subdevice */
697 return NULL;
700 subdev = *subdev_list;
701 *subdev_list = subdev->next;
702 subdev->next = NULL;
704 return subdev;
707 static void
708 _subdev_remove(InputInfoPtr pInfo, InputInfoPtr sub_pInfo)
710 TuioDevicePtr pTuio = pInfo->private;
711 SubDevicePtr *subdev_list = &pTuio->subdev_list;
712 SubDevicePtr subdev = *subdev_list, last;
713 ObjectPtr obj = pTuio->obj_list;
714 Bool found = False;
716 /* First try to find it in the list of subdevices */
717 if (subdev != NULL && subdev->pInfo == sub_pInfo) {
718 found = True;
719 *subdev_list = subdev->next;
720 xfree(subdev);
721 } else if (subdev != NULL) {
722 last = subdev;
723 subdev = subdev->next;
724 while (subdev != NULL) {
725 if (subdev->pInfo == sub_pInfo) {
726 last->next = subdev->next;
727 found = True;
728 xfree(subdev);
729 break;
731 last = subdev;
732 subdev = subdev->next;
736 /* If it still hasn't been found, find the object that is holding
737 * it */
738 if (!found) {
739 while (obj != NULL) {
740 if (obj->subdev != NULL && obj->subdev->pInfo == sub_pInfo) {
741 xfree(obj->subdev);
742 obj->subdev = NULL;
743 found = True;
744 break;
746 obj = obj->next;
752 * Init the button map device. We only use one button.
754 static int
755 _init_buttons(DeviceIntPtr device)
757 InputInfoPtr pInfo = device->public.devicePrivate;
758 CARD8 *map;
759 Atom *labels;
760 int numbuttons = 4;
761 int ret = Success;
762 int i;
764 map = xcalloc(numbuttons, sizeof(CARD8));
765 labels = xcalloc(numbuttons, sizeof(Atom));
766 for (i=0; i<numbuttons; i++)
767 map[i] = i;
769 if (!InitButtonClassDeviceStruct(device, numbuttons /* 1 button */,
770 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
771 labels,
772 #endif
773 map)) {
774 xf86Msg(X_ERROR, "%s: Failed to register buttons.\n", pInfo->name);
775 ret = BadAlloc;
778 xfree(labels);
779 return ret;
783 * Init valuators for device, use x/y coordinates.
785 static int
786 _init_axes(DeviceIntPtr device)
788 InputInfoPtr pInfo = device->public.devicePrivate;
789 int i;
790 const int num_axes = 2;
791 Atom *atoms;
793 atoms = xcalloc(num_axes, sizeof(Atom));
795 if (!InitValuatorClassDeviceStruct(device,
796 num_axes,
797 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
798 atoms,
799 #endif
800 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
801 GetMotionHistory,
802 #endif
803 GetMotionHistorySize(),
805 return BadAlloc;
807 for (i = 0; i < num_axes; i++)
809 xf86InitValuatorAxisStruct(device, i,
810 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
811 atoms[i],
812 #endif
813 0, 0x7FFFFFFF, 1, 1, 1);
814 xf86InitValuatorDefaults(device, i);
817 /* Use absolute mode. Currently, TUIO coords are mapped to the
818 * full screen area */
819 pInfo->dev->valuator->mode = Absolute;
820 if (!InitAbsoluteClassDeviceStruct(device))
821 return BadAlloc;
823 return Success;
827 * New device creation through hal
828 * I referenced the wacom hal-setup patch while writing this:
829 * http://cvs.fedoraproject.org/viewvc/rpms/linuxwacom/devel/linuxwacom-0.8.2.2-hal-setup.patch?revision=1.1&view=markup
831 * @return 0 if successful, 1 if failure
833 static int
834 _hal_create_devices(InputInfoPtr pInfo, int num) {
835 TuioDevicePtr pTuio = pInfo->private;
836 DBusError error;
837 DBusConnection *conn;
838 LibHalContext *ctx;
839 char *newdev;
840 char *name;
841 int i;
843 /* We need a new device to send motion/button events through.
844 * There isn't a great way to do this right now without native
845 * blob events, so just hack it out for now. Woot. */
847 /* Open connection to dbus and create contex */
848 dbus_error_init(&error);
849 if ((conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) {
850 xf86Msg(X_ERROR, "%s: Failed to open dbus connection: %s\n",
851 pInfo->name, error.message);
852 return 1;
855 if ((ctx = libhal_ctx_new()) == NULL) {
856 xf86Msg(X_ERROR, "%s: Failed to obtain hal context\n",
857 pInfo->name);
858 return 1;
861 dbus_error_init(&error);
862 libhal_ctx_set_dbus_connection(ctx, conn);
863 if (!libhal_ctx_init(ctx, &error)) {
864 xf86Msg(X_ERROR, "%s: Failed to initialize hal context: %s\n",
865 pInfo->name, error.message);
866 return 1;
869 /* Create new devices through hal */
870 for (i=0; i<num; i++) {
872 dbus_error_init(&error);
873 newdev = libhal_new_device(ctx, &error);
874 if (dbus_error_is_set(&error) == TRUE) {
875 xf86Msg(X_ERROR, "%s: Failed to create input device: %s\n",
876 pInfo->name, error.message);
877 return 1;
880 dbus_error_init(&error);
881 libhal_device_set_property_string(ctx, newdev, "input.device",
882 "tuio_subdevice", &error);
883 if (dbus_error_is_set(&error) == TRUE) {
884 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
885 pInfo->name, error.message);
886 return 1;
889 dbus_error_init(&error);
890 libhal_device_set_property_bool(ctx, newdev, "RequireEnable",
891 False, &error);
892 if (dbus_error_is_set(&error) == TRUE) {
893 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
894 pInfo->name, error.message);
895 return 1;
898 dbus_error_init(&error);
899 libhal_device_set_property_string(ctx, newdev,
900 "input.x11_driver", "tuio",
901 &error);
902 if (dbus_error_is_set(&error) == TRUE) {
903 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
904 pInfo->name, error.message);
905 return 1;
908 /* Set "Type" property. This will be used in TuioPreInit to determine
909 * whether the new device is a subdev or not */
910 dbus_error_init(&error);
911 libhal_device_set_property_string(ctx, newdev,
912 "input.x11_options.Type",
913 "Object", &error);
914 if (dbus_error_is_set(&error) == TRUE) {
915 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
916 pInfo->name, error.message);
917 return 1;
920 asprintf(&name, "%s subdev %i", pInfo->name, pTuio->num_subdev);
922 /* Set name */
923 dbus_error_init(&error);
924 libhal_device_set_property_string(ctx, newdev,
925 "info.product", name,
926 &error);
927 if (dbus_error_is_set(&error) == TRUE) {
928 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
929 pInfo->name, error.message);
930 return 1;
933 /* Finalize creation of new device */
934 dbus_error_init(&error);
935 libhal_device_commit_to_gdl(ctx, newdev, "/org/freedesktop/Hal/devices/tuio_subdev", &error);
936 if (dbus_error_is_set (&error) == TRUE) {
937 xf86Msg(X_ERROR, "%s: Failed to add input device: %s\n",
938 pInfo->name, error.message);
939 return 1;
942 xfree(name);
943 pTuio->num_subdev++;
946 if (!libhal_ctx_shutdown(ctx, &error)) {
947 xf86Msg(X_ERROR, "%s: Unable to shutdown hal context: %s\n",
948 pInfo->name, error.message);
949 return 1;
951 libhal_ctx_free(ctx);
953 return 0;
956 static int
957 _hal_remove_device(InputInfoPtr pInfo) {
958 DBusError error;
959 DBusConnection *conn;
960 LibHalContext *ctx;
961 char** devices;
962 int i, num_devices;
964 xf86Msg(X_INFO, "%s: Removing subdevice\n",
965 pInfo->name);
967 /* Open connection to dbus and create contex */
968 dbus_error_init(&error);
969 if ((conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) {
970 xf86Msg(X_ERROR, "%s: Failed to open dbus connection: %s\n",
971 pInfo->name, error.message);
972 return 1;
975 if ((ctx = libhal_ctx_new()) == NULL) {
976 xf86Msg(X_ERROR, "%s: Failed to obtain hal context\n",
977 pInfo->name);
978 return 1;
981 dbus_error_init(&error);
982 libhal_ctx_set_dbus_connection(ctx, conn);
983 if (!libhal_ctx_init(ctx, &error)) {
984 xf86Msg(X_ERROR, "%s: Failed to initialize hal context: %s\n",
985 pInfo->name, error.message);
986 return 1;
989 devices = libhal_manager_find_device_string_match(ctx, "info.product",
990 pInfo->name,
991 &num_devices,
992 &error);
993 if (dbus_error_is_set(&error) == TRUE) {
994 xf86Msg(X_ERROR, "%s: Failed when trying to find device: %s\n",
995 pInfo->name, error.message);
996 return 1;
999 if (num_devices == 0) {
1000 xf86Msg(X_ERROR, "%s: Unable to find subdevice in HAL GDL\n",
1001 pInfo->name);
1002 } else {
1003 for (i=0; i<num_devices; i++) {
1004 xf86Msg(X_INFO, "%s: Removing subdevice with udi '%s'\n",
1005 pInfo->name, devices[i]);
1006 if (!libhal_remove_device(ctx, devices[i], &error)) {
1007 xf86Msg(X_ERROR, "%s: Unable to remove subdevice: %s\n",
1008 pInfo->name, error.message);
1013 if (!libhal_ctx_shutdown(ctx, &error)) {
1014 xf86Msg(X_ERROR, "%s: Unable to shutdown hal context: %s\n",
1015 pInfo->name, error.message);
1016 return 1;
1018 libhal_ctx_free(ctx);
1020 return 0;