Removed unused includes; removed inputproto from configure.ac
[xf86-input-tuio.git] / src / tuio.c
blob634f45a45aa06b43051dfc933bfd107e06ca8fcb
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>
30 #include <xf86_OSlib.h>
32 #include "tuio.h"
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
38 /* InputInfoPtr for main tuio device */
39 static InputInfoPtr g_pInfo;
40 static int pipefd[2] = {-1, -1};
42 /* Module Functions */
43 static pointer
44 TuioPlug(pointer, pointer, int *, int *);
46 static void
47 TuioUnplug(pointer);
49 /* Driver Functions */
50 static InputInfoPtr
51 TuioPreInit(InputDriverPtr, IDevPtr, int);
53 static void
54 TuioUnInit(InputDriverPtr, InputInfoPtr, int);
56 static void
57 TuioObjReadInput(InputInfoPtr pInfo);
59 static void
60 TuioReadInput(InputInfoPtr);
62 static int
63 TuioControl(DeviceIntPtr, int);
65 /* Internal Functions */
66 static int
67 _hal_create_devices(InputInfoPtr pInfo, int num);
69 static int
70 _init_buttons(DeviceIntPtr device);
72 static int
73 _init_axes(DeviceIntPtr device);
75 static int
76 _tuio_lo_2dcur_handle(const char *path,
77 const char *types,
78 lo_arg **argv,
79 int argc,
80 void *data,
81 void *user_data);
83 static void
84 _free_tuiodev(TuioDevicePtr pTuio);
86 static void
87 _lo_error(int num,
88 const char *msg,
89 const char *path);
91 /* Object and Subdev list manipulation functions */
92 static ObjectPtr
93 _object_get(ObjectPtr head, int id);
95 static ObjectPtr
96 _object_new(int id);
98 static void
99 _object_add(ObjectPtr *obj_list, ObjectPtr obj);
101 static ObjectPtr
102 _object_remove(ObjectPtr *obj_list, int id);
104 static void
105 _subdev_add(InputInfoPtr pInfo, SubDevicePtr subdev);
107 static void
108 _subdev_remove(InputInfoPtr pInfo, InputInfoPtr sub_pInfo);
110 static SubDevicePtr
111 _subdev_get(InputInfoPtr pInfo, SubDevicePtr *subdev_list);
113 static int
114 _hal_remove_device(InputInfoPtr pInfo);
116 /* Driver information */
117 static XF86ModuleVersionInfo TuioVersionRec =
119 "tuio",
120 MODULEVENDORSTRING,
121 MODINFOSTRING1,
122 MODINFOSTRING2,
123 XORG_VERSION_CURRENT,
124 PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
125 ABI_CLASS_XINPUT,
126 ABI_XINPUT_VERSION,
127 MOD_CLASS_XINPUT,
128 {0, 0, 0, 0}
131 _X_EXPORT InputDriverRec TUIO =
134 "tuio",
135 NULL,
136 TuioPreInit,
137 TuioUnInit,
138 NULL,
142 _X_EXPORT XF86ModuleData tuioModuleData =
144 &TuioVersionRec,
145 TuioPlug,
146 TuioUnplug
149 static pointer
150 TuioPlug(pointer module,
151 pointer options,
152 int *errmaj,
153 int *errmin)
155 xf86AddInputDriver(&TUIO, module, 0);
156 return module;
160 * Unplug
162 static void
163 TuioUnplug(pointer p)
168 * Pre-initialization of new device
169 * This can be entered by either a "core" tuio device
170 * or an extension "Object" device that is used for routing individual object
171 * events through.
173 static InputInfoPtr
174 TuioPreInit(InputDriverPtr drv,
175 IDevPtr dev,
176 int flags)
178 InputInfoPtr pInfo;
179 TuioDevicePtr pTuio = NULL;
180 ObjectPtr obj;
181 char *type;
182 int num_subdev, tuio_port;
184 if (!(pInfo = xf86AllocateInput(drv, 0)))
185 return NULL;
187 /* If Type == Object, this is a device for an object to use */
188 type = xf86CheckStrOption(dev->commonOptions, "Type", NULL);
190 if (type != NULL && strcmp(type, "Object") == 0) {
191 xf86Msg(X_INFO, "%s: TUIO subdevice found\n", dev->identifier);
193 } else {
195 if (!(pTuio = xcalloc(1, sizeof(TuioDeviceRec)))) {
196 xf86DeleteInput(pInfo, 0);
197 return NULL;
199 g_pInfo = pInfo;
201 pInfo->private = pTuio;
203 pTuio->num_subdev = 0;
205 /* Get the number of subdevices we need to create */
206 num_subdev = xf86CheckIntOption(dev->commonOptions, "SubDevices",
207 DEFAULT_SUBDEVICES);
208 if (num_subdev > MAX_SUBDEVICES) {
209 num_subdev = MAX_SUBDEVICES;
210 } else if (num_subdev < MIN_SUBDEVICES) {
211 num_subdev = MIN_SUBDEVICES;
213 pTuio->init_num_subdev = num_subdev;
215 /* Get the TUIO port number to use */
216 tuio_port = xf86CheckIntOption(dev->commonOptions, "Port", DEFAULT_PORT);
217 if (tuio_port < 0 || tuio_port > 65535) {
218 xf86Msg(X_INFO, "%s: Invalid port number (%i), defaulting to %i\n",
219 dev->identifier, tuio_port, DEFAULT_PORT);
220 tuio_port = DEFAULT_PORT;
222 xf86Msg(X_INFO, "%s: TUIO UDP Port set to %i\n",
223 dev->identifier, tuio_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 < 0) {
230 pTuio->fseq_threshold = 0;
232 xf86Msg(X_INFO, "%s: FseqThreshold set to %i\n",
233 dev->identifier, pTuio->fseq_threshold);
235 /* Get setting for whether to send button events or not with
236 * object add & remove */
237 pTuio->post_button_events = xf86CheckBoolOption(dev->commonOptions,
238 "PostButtonEvents", True);
241 /* Set up InputInfoPtr */
242 pInfo->name = xstrdup(dev->identifier);
243 pInfo->flags = 0;
244 pInfo->type_name = XI_TOUCHSCREEN; /* FIXME: Correct type? */
245 pInfo->conf_idev = dev;
246 pInfo->read_input = pTuio ? TuioReadInput : TuioObjReadInput; /* Set callback */
247 pInfo->device_control = TuioControl; /* Set callback */
248 pInfo->switch_mode = NULL;
250 /* Process common device options */
251 xf86CollectInputOptions(pInfo, NULL, NULL);
252 xf86ProcessCommonOptions(pInfo, pInfo->options);
254 pInfo->flags |= XI86_OPEN_ON_INIT;
255 pInfo->flags |= XI86_CONFIGURED;
257 return pInfo;
261 * Clean up
263 static void
264 TuioUnInit(InputDriverPtr drv,
265 InputInfoPtr pInfo,
266 int flags)
268 xf86DeleteInput(pInfo, 0);
272 * Empty callback for object device.
274 static void
275 TuioObjReadInput(InputInfoPtr pInfo) {
276 return;
280 * Handle new TUIO data on the socket
282 static void
283 TuioReadInput(InputInfoPtr pInfo)
285 TuioDevicePtr pTuio = pInfo->private;
286 ObjectPtr *obj_list = &pTuio->obj_list;
287 ObjectPtr obj = pTuio->obj_list;
288 SubDevicePtr *subdev_list = &pTuio->subdev_list;
289 ObjectPtr objtmp;
290 int valuators[2];
292 while (xf86WaitForInput(pInfo->fd, 0) > 0)
294 /* The liblo handler will set this flag if anything was processed */
295 pTuio->processed = 0;
297 /* liblo will receive a message and call the appropriate
298 * handlers (i.e. _tuio_lo_cur2d_hande()) */
299 lo_server_recv_noblock(pTuio->server, 0);
301 /* During the processing of the previous message/bundle,
302 * any "active" messages will be handled by flagging
303 * the listed object ids. Now that processing is done,
304 * remove any dead object ids and set any pending changes.
305 * Also check to make sure the processed data was newer than
306 * the last processed data */
307 if (pTuio->processed &&
308 (pTuio->fseq_new > pTuio->fseq_old ||
309 pTuio->fseq_old - pTuio->fseq_new > pTuio->fseq_threshold)) {
311 while (obj != NULL) {
312 if (!obj->alive) {
313 if (obj->subdev && pTuio->post_button_events) {
314 /* Post button "up" event */
315 xf86PostButtonEvent(obj->subdev->pInfo->dev, TRUE, 1, FALSE, 0, 0);
317 objtmp = obj->next;
318 obj = _object_remove(obj_list, obj->id);
319 _subdev_add(pInfo, obj->subdev);
320 xfree(obj);
321 obj = objtmp;
323 } else {
324 /* Object is alive. Check to see if an update has been set.
325 * If it has been updated and it has a subdevice to send
326 * events on, send the event) */
327 if (obj->pending.set && obj->subdev) {
328 obj->x = obj->pending.x;
329 obj->y = obj->pending.y;
330 obj->pending.set = False;
332 /* OKAY FOR NOW, maybe update with a better range? */
333 /* TODO: Add more valuators with additional information */
334 valuators[0] = obj->x * 0x7FFFFFFF;
335 valuators[1] = obj->y * 0x7FFFFFFF;
337 xf86PostMotionEventP(obj->subdev->pInfo->dev,
338 TRUE, /* is_absolute */
339 0, /* first_valuator */
340 2, /* num_valuators */
341 valuators);
343 if (obj->pending.button) {
344 xf86PostButtonEvent(obj->subdev->pInfo->dev, TRUE, 1, TRUE, 0, 0);
345 obj->pending.button = False;
348 obj->alive = 0; /* Reset for next message */
349 obj = obj->next;
352 pTuio->fseq_old = pTuio->fseq_new;
358 * Handle device state changes
360 static int
361 TuioControl(DeviceIntPtr device,
362 int what)
364 InputInfoPtr pInfo = device->public.devicePrivate;
365 TuioDevicePtr pTuio = pInfo->private;
366 SubDevicePtr subdev;
367 char *tuio_port;
368 int res;
370 switch (what)
372 case DEVICE_INIT:
373 xf86Msg(X_INFO, "%s: Init\n", pInfo->name);
374 _init_buttons(device);
375 _init_axes(device);
377 /* If this is a "core" device, create object devices */
378 if (pTuio) {
379 _hal_create_devices(pInfo, pTuio->init_num_subdev);
381 break;
383 case DEVICE_ON: /* Open socket and start listening! */
384 xf86Msg(X_INFO, "%s: On.\n", pInfo->name);
385 if (device->public.on)
386 break;
388 /* If this is an object device, use a dummy pipe,
389 * and add device to subdev list */
390 if (!pTuio) {
391 if (pipefd[0] == -1) {
392 SYSCALL(res = pipe(pipefd));
393 if (res == -1) {
394 xf86Msg(X_ERROR, "%s: failed to open pipe\n",
395 pInfo->name);
396 return BadAlloc;
400 pInfo->fd = pipefd[0];
402 goto finish;
405 /* Setup server */
406 asprintf(&tuio_port, "%i", pTuio->tuio_port);
407 pTuio->server = lo_server_new_with_proto(tuio_port, LO_UDP, _lo_error);
408 if (pTuio->server == NULL) {
409 xf86Msg(X_ERROR, "%s: Error allocating new lo_server\n",
410 pInfo->name);
411 return BadAlloc;
414 /* Register to receive all /tuio/2Dcur messages */
415 lo_server_add_method(pTuio->server, "/tuio/2Dcur", NULL,
416 _tuio_lo_2dcur_handle, pInfo);
418 pInfo->fd = lo_server_get_socket_fd(pTuio->server);
420 xf86FlushInput(pInfo->fd);
422 finish: xf86AddEnabledDevice(pInfo);
423 device->public.on = TRUE;
425 /* Allocate device storage and add to device list */
426 subdev = xcalloc(1, sizeof(SubDeviceRec));
427 subdev->pInfo = pInfo;
428 _subdev_add(g_pInfo, subdev);
429 break;
431 case DEVICE_OFF:
432 xf86Msg(X_INFO, "%s: Off\n", pInfo->name);
433 if (!device->public.on)
434 break;
436 xf86RemoveEnabledDevice(pInfo);
438 if (pTuio) {
439 lo_server_free(pTuio->server);
440 pInfo->fd = -1;
442 /* Remove subdev from list - This applies for both subdevices
443 * and the "core" device */
444 _subdev_remove(g_pInfo, pInfo);
446 device->public.on = FALSE;
447 break;
449 case DEVICE_CLOSE:
450 xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
451 _hal_remove_device(pInfo);
452 break;
455 return Success;
459 * Initialize the device properties
460 * TODO
462 TuioPropertyInit() {
466 * Free a TuioDeviceRec
468 static void
469 _free_tuiodev(TuioDevicePtr pTuio) {
470 ObjectPtr obj = pTuio->obj_list;
471 ObjectPtr tmp;
473 while (obj != NULL) {
474 tmp = obj->next;
475 xfree(obj);
476 obj = tmp;
479 xfree(pTuio);
483 * Handles OSC messages in the /tuio/2Dcur address space
485 static int
486 _tuio_lo_2dcur_handle(const char *path,
487 const char *types,
488 lo_arg **argv,
489 int argc,
490 void *data,
491 void *user_data) {
492 InputInfoPtr pInfo = user_data;
493 TuioDevicePtr pTuio = pInfo->private;
494 ObjectPtr *obj_list = &pTuio->obj_list;
495 ObjectPtr obj, objtemp;
496 char *act;
497 int i;
499 if (argc == 0) {
500 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d (argc == 0)\n",
501 pInfo->name);
502 return 0;
503 } else if(*types != 's') {
504 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d (types[0] != 's')\n",
505 pInfo->name);
506 return 0;
509 /* Flag as being processed, used in TuioReadInput() */
510 pTuio->processed = 1;
512 /* Parse message type */
513 /* Set message type: */
514 if (strcmp((char *)argv[0], "set") == 0) {
516 /* Simple type check */
517 if (strcmp(types, "sifffff")) {
518 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d set msg (types == %s)\n",
519 pInfo->name, types);
520 return 0;
523 obj = _object_get(*obj_list, argv[1]->i);
525 /* If not found, create a new object */
526 if (obj == NULL) {
527 obj = _object_new(argv[1]->i);
528 _object_add(obj_list, obj);
529 obj->subdev = _subdev_get(pInfo, &pTuio->subdev_list);
530 if (obj->subdev && pTuio->post_button_events)
531 obj->pending.button = True;
534 obj->pending.x = argv[2]->f;
535 obj->pending.y = argv[3]->f;
536 obj->pending.set = True;
538 } else if (strcmp((char *)argv[0], "alive") == 0) {
539 /* Mark all objects that are still alive */
540 obj = *obj_list;
541 while (obj != NULL) {
542 for (i=1; i<argc; i++) {
543 if (argv[i]->i == obj->id) {
544 obj->alive = True;
545 break;
548 obj = obj->next;
551 } else if (strcmp((char *)argv[0], "fseq") == 0) {
552 /* Simple type check */
553 if (strcmp(types, "si")) {
554 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d fseq msg (types == %s)\n",
555 pInfo->name, types);
556 return 0;
558 pTuio->fseq_new = argv[1]->i;
561 return 0;
565 * liblo error handler
567 static void
568 _lo_error(int num,
569 const char *msg,
570 const char *path)
572 xf86Msg(X_ERROR, "liblo: %s\n", msg);
576 * Retrieves an object from a list based on its id.
578 * @return NULL if not found.
580 static ObjectPtr
581 _object_get(ObjectPtr head, int id) {
582 ObjectPtr obj = head;
584 while (obj != NULL && obj->id != id) {
585 obj = obj->next;
588 return obj;
592 * Allocates and inserts a new object at the beginning of a list.
593 * Pointer to the new object is returned.
594 * Doesn't check for duplicate ids, so call _object_get() beforehand
595 * to make sure it doesn't exist already!!
597 * @return ptr to newly inserted object
599 static ObjectPtr
600 _object_new(int id) {
601 ObjectPtr new_obj = xcalloc(1, sizeof(ObjectRec));
603 new_obj->id = id;
604 new_obj->alive = True;
606 return new_obj;
610 * Adds a SubDevice to the beginning of the subdev_list list
612 static void
613 _object_add(ObjectPtr *obj_list, ObjectPtr obj) {
615 if (obj_list == NULL || obj == NULL)
616 return;
618 if (*obj_list != NULL) {
619 obj->next = *obj_list;
621 *obj_list = obj;
626 * Removes an Object with a specific id from a list.
628 static ObjectPtr
629 _object_remove(ObjectPtr *obj_list, int id) {
630 ObjectPtr obj = *obj_list;
631 ObjectPtr objtmp;
633 if (obj == NULL) return; /* Empty list */
635 if (obj->id == id) { /* Remove from head */
636 *obj_list = obj->next;
637 } else {
638 while (obj->next != NULL) {
639 if (obj->next->id == id) {
640 objtmp = obj->next;
641 obj->next = objtmp->next;
642 obj = objtmp;
643 obj->next = NULL;
644 return obj;
646 obj = obj->next;
648 obj = NULL;
651 return obj;
655 * Adds a SubDevice to the beginning of the subdev_list list
657 static void
658 _subdev_add(InputInfoPtr pInfo, SubDevicePtr subdev) {
659 TuioDevicePtr pTuio = pInfo->private;
660 SubDevicePtr *subdev_list = &pTuio->subdev_list;
661 ObjectPtr obj = pTuio->obj_list;
663 if (subdev_list == NULL || subdev == NULL)
664 return;
666 /* First check to see if there are any objects that don't have a
667 * subdevice that we can assign this subdevice to */
668 while (obj != NULL) {
669 if (obj->subdev == NULL) {
670 obj->subdev = subdev;
671 if (pTuio->post_button_events)
672 obj->pending.button = True;
673 obj->pending.set = True;
674 return;
676 obj = obj->next;
679 /* No subdevice-less objects, add to front of subdev list */
680 if (*subdev_list != NULL) {
681 subdev->next = *subdev_list;
683 *subdev_list = subdev;
687 * Gets any available subdevice
689 static SubDevicePtr
690 _subdev_get(InputInfoPtr pInfo, SubDevicePtr *subdev_list) {
691 SubDevicePtr subdev;
693 if (subdev_list == NULL || *subdev_list == NULL) {
694 _hal_create_devices(pInfo, 1); /* Create one new subdevice */
695 return NULL;
698 subdev = *subdev_list;
699 *subdev_list = subdev->next;
700 subdev->next = NULL;
702 return subdev;
705 static void
706 _subdev_remove(InputInfoPtr pInfo, InputInfoPtr sub_pInfo)
708 TuioDevicePtr pTuio = pInfo->private;
709 SubDevicePtr *subdev_list = &pTuio->subdev_list;
710 SubDevicePtr subdev = *subdev_list, last;
711 ObjectPtr obj = pTuio->obj_list;
712 Bool found = False;
714 /* First try to find it in the list of subdevices */
715 if (subdev != NULL && subdev->pInfo == sub_pInfo) {
716 found = True;
717 *subdev_list = subdev->next;
718 xfree(subdev);
719 } else if (subdev != NULL) {
720 last = subdev;
721 subdev = subdev->next;
722 while (subdev != NULL) {
723 if (subdev->pInfo == sub_pInfo) {
724 last->next = subdev->next;
725 found = True;
726 xfree(subdev);
727 break;
729 last = subdev;
730 subdev = subdev->next;
734 /* If it still hasn't been found, find the object that is holding
735 * it */
736 if (!found) {
737 while (obj != NULL) {
738 if (obj->subdev != NULL && obj->subdev->pInfo == sub_pInfo) {
739 xfree(obj->subdev);
740 obj->subdev = NULL;
741 found = True;
742 break;
744 obj = obj->next;
750 * Init the button map device. We only use one button.
752 static int
753 _init_buttons(DeviceIntPtr device)
755 InputInfoPtr pInfo = device->public.devicePrivate;
756 CARD8 *map;
757 Atom *labels;
758 int numbuttons = 4;
759 int ret = Success;
760 int i;
762 map = xcalloc(numbuttons, sizeof(CARD8));
763 labels = xcalloc(numbuttons, sizeof(Atom));
764 for (i=0; i<numbuttons; i++)
765 map[i] = i;
767 if (!InitButtonClassDeviceStruct(device, numbuttons /* 1 button */,
768 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
769 labels,
770 #endif
771 map)) {
772 xf86Msg(X_ERROR, "%s: Failed to register buttons.\n", pInfo->name);
773 ret = BadAlloc;
776 xfree(labels);
777 return ret;
781 * Init valuators for device, use x/y coordinates.
783 static int
784 _init_axes(DeviceIntPtr device)
786 InputInfoPtr pInfo = device->public.devicePrivate;
787 int i;
788 const int num_axes = 2;
789 Atom *atoms;
791 atoms = xcalloc(num_axes, sizeof(Atom));
793 if (!InitValuatorClassDeviceStruct(device,
794 num_axes,
795 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
796 atoms,
797 #endif
798 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
799 GetMotionHistory,
800 #endif
801 GetMotionHistorySize(),
803 return BadAlloc;
805 for (i = 0; i < num_axes; i++)
807 xf86InitValuatorAxisStruct(device, i,
808 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
809 atoms[i],
810 #endif
811 0, 0x7FFFFFFF, 1, 1, 1);
812 xf86InitValuatorDefaults(device, i);
815 /* Use absolute mode. Currently, TUIO coords are mapped to the
816 * full screen area */
817 pInfo->dev->valuator->mode = Absolute;
818 if (!InitAbsoluteClassDeviceStruct(device))
819 return BadAlloc;
821 return Success;
825 * New device creation through hal
826 * I referenced the wacom hal-setup patch while writing this:
827 * http://cvs.fedoraproject.org/viewvc/rpms/linuxwacom/devel/linuxwacom-0.8.2.2-hal-setup.patch?revision=1.1&view=markup
829 * @return 0 if successful, 1 if failure
831 static int
832 _hal_create_devices(InputInfoPtr pInfo, int num) {
833 TuioDevicePtr pTuio = pInfo->private;
834 DBusError error;
835 DBusConnection *conn;
836 LibHalContext *ctx;
837 char *newdev;
838 char *name;
839 int i;
841 /* We need a new device to send motion/button events through.
842 * There isn't a great way to do this right now without native
843 * blob events, so just hack it out for now. Woot. */
845 /* Open connection to dbus and create contex */
846 dbus_error_init(&error);
847 if ((conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) {
848 xf86Msg(X_ERROR, "%s: Failed to open dbus connection: %s\n",
849 pInfo->name, error.message);
850 return 1;
853 if ((ctx = libhal_ctx_new()) == NULL) {
854 xf86Msg(X_ERROR, "%s: Failed to obtain hal context\n",
855 pInfo->name);
856 return 1;
859 dbus_error_init(&error);
860 libhal_ctx_set_dbus_connection(ctx, conn);
861 if (!libhal_ctx_init(ctx, &error)) {
862 xf86Msg(X_ERROR, "%s: Failed to initialize hal context: %s\n",
863 pInfo->name, error.message);
864 return 1;
867 /* Create new devices through hal */
868 for (i=0; i<num; i++) {
870 dbus_error_init(&error);
871 newdev = libhal_new_device(ctx, &error);
872 if (dbus_error_is_set(&error) == TRUE) {
873 xf86Msg(X_ERROR, "%s: Failed to create input device: %s\n",
874 pInfo->name, error.message);
875 return 1;
878 dbus_error_init(&error);
879 libhal_device_set_property_string(ctx, newdev, "input.device",
880 "tuio_subdevice", &error);
881 if (dbus_error_is_set(&error) == TRUE) {
882 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
883 pInfo->name, error.message);
884 return 1;
887 dbus_error_init(&error);
888 libhal_device_set_property_bool(ctx, newdev, "RequireEnable",
889 False, &error);
890 if (dbus_error_is_set(&error) == TRUE) {
891 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
892 pInfo->name, error.message);
893 return 1;
896 dbus_error_init(&error);
897 libhal_device_set_property_string(ctx, newdev,
898 "input.x11_driver", "tuio",
899 &error);
900 if (dbus_error_is_set(&error) == TRUE) {
901 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
902 pInfo->name, error.message);
903 return 1;
906 /* Set "Type" property. This will be used in TuioPreInit to determine
907 * whether the new device is a subdev or not */
908 dbus_error_init(&error);
909 libhal_device_set_property_string(ctx, newdev,
910 "input.x11_options.Type",
911 "Object", &error);
912 if (dbus_error_is_set(&error) == TRUE) {
913 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
914 pInfo->name, error.message);
915 return 1;
918 asprintf(&name, "%s subdev %i", pInfo->name, pTuio->num_subdev);
920 /* Set name */
921 dbus_error_init(&error);
922 libhal_device_set_property_string(ctx, newdev,
923 "info.product", name,
924 &error);
925 if (dbus_error_is_set(&error) == TRUE) {
926 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
927 pInfo->name, error.message);
928 return 1;
931 /* Finalize creation of new device */
932 dbus_error_init(&error);
933 libhal_device_commit_to_gdl(ctx, newdev, "/org/freedesktop/Hal/devices/tuio_subdev", &error);
934 if (dbus_error_is_set (&error) == TRUE) {
935 xf86Msg(X_ERROR, "%s: Failed to add input device: %s\n",
936 pInfo->name, error.message);
937 return 1;
940 xfree(name);
941 pTuio->num_subdev++;
944 if (!libhal_ctx_shutdown(ctx, &error)) {
945 xf86Msg(X_ERROR, "%s: Unable to shutdown hal context: %s\n",
946 pInfo->name, error.message);
947 return 1;
949 libhal_ctx_free(ctx);
951 return 0;
954 static int
955 _hal_remove_device(InputInfoPtr pInfo) {
956 DBusError error;
957 DBusConnection *conn;
958 LibHalContext *ctx;
959 char** devices;
960 int i, num_devices;
962 xf86Msg(X_INFO, "%s: Removing subdevice\n",
963 pInfo->name);
965 /* Open connection to dbus and create contex */
966 dbus_error_init(&error);
967 if ((conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) {
968 xf86Msg(X_ERROR, "%s: Failed to open dbus connection: %s\n",
969 pInfo->name, error.message);
970 return 1;
973 if ((ctx = libhal_ctx_new()) == NULL) {
974 xf86Msg(X_ERROR, "%s: Failed to obtain hal context\n",
975 pInfo->name);
976 return 1;
979 dbus_error_init(&error);
980 libhal_ctx_set_dbus_connection(ctx, conn);
981 if (!libhal_ctx_init(ctx, &error)) {
982 xf86Msg(X_ERROR, "%s: Failed to initialize hal context: %s\n",
983 pInfo->name, error.message);
984 return 1;
987 devices = libhal_manager_find_device_string_match(ctx, "info.product",
988 pInfo->name,
989 &num_devices,
990 &error);
991 if (dbus_error_is_set(&error) == TRUE) {
992 xf86Msg(X_ERROR, "%s: Failed when trying to find device: %s\n",
993 pInfo->name, error.message);
994 return 1;
997 if (num_devices == 0) {
998 xf86Msg(X_ERROR, "%s: Unable to find subdevice in HAL GDL\n",
999 pInfo->name);
1000 } else {
1001 for (i=0; i<num_devices; i++) {
1002 xf86Msg(X_INFO, "%s: Removing subdevice with udi '%s'\n",
1003 pInfo->name, devices[i]);
1004 if (!libhal_remove_device(ctx, devices[i], &error)) {
1005 xf86Msg(X_ERROR, "%s: Unable to remove subdevice: %s\n",
1006 pInfo->name, error.message);
1011 if (!libhal_ctx_shutdown(ctx, &error)) {
1012 xf86Msg(X_ERROR, "%s: Unable to shutdown hal context: %s\n",
1013 pInfo->name, error.message);
1014 return 1;
1016 libhal_ctx_free(ctx);
1018 return 0;