Added 2 new valuators: x velocity and y velocity
[xf86-input-tuio.git] / src / tuio.c
blobcb44e9e2124e9a952a23ba17f9e7bcf6603bf2fd
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 <xf86_OSlib.h>
30 #include <xserver-properties.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[NUM_VALUATORS];
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->xpos = obj->pending.xpos;
329 obj->ypos = obj->pending.ypos;
330 obj->xvel = obj->pending.xvel;
331 obj->yvel = obj->pending.yvel;
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->xpos * 0x7FFFFFFF;
337 valuators[1] = obj->ypos * 0x7FFFFFFF;
338 valuators[2] = obj->xvel * 0x7FFFFFFF;
339 valuators[3] = obj->yvel * 0x7FFFFFFF;
341 xf86PostMotionEventP(obj->subdev->pInfo->dev,
342 TRUE, /* is_absolute */
343 0, /* first_valuator */
344 NUM_VALUATORS, /* num_valuators */
345 valuators);
347 if (obj->pending.button) {
348 xf86PostButtonEvent(obj->subdev->pInfo->dev, TRUE, 1, TRUE, 0, 0);
349 obj->pending.button = False;
352 obj->alive = 0; /* Reset for next message */
353 obj = obj->next;
356 pTuio->fseq_old = pTuio->fseq_new;
362 * Handle device state changes
364 static int
365 TuioControl(DeviceIntPtr device,
366 int what)
368 InputInfoPtr pInfo = device->public.devicePrivate;
369 TuioDevicePtr pTuio = pInfo->private;
370 SubDevicePtr subdev;
371 char *tuio_port;
372 int res;
374 switch (what)
376 case DEVICE_INIT:
377 xf86Msg(X_INFO, "%s: Init\n", pInfo->name);
378 _init_buttons(device);
379 _init_axes(device);
381 /* If this is a "core" device, create object devices */
382 if (pTuio) {
383 _hal_create_devices(pInfo, pTuio->init_num_subdev);
385 break;
387 case DEVICE_ON: /* Open socket and start listening! */
388 xf86Msg(X_INFO, "%s: On.\n", pInfo->name);
389 if (device->public.on)
390 break;
392 /* If this is an object device, use a dummy pipe,
393 * and add device to subdev list */
394 if (!pTuio) {
395 if (pipefd[0] == -1) {
396 SYSCALL(res = pipe(pipefd));
397 if (res == -1) {
398 xf86Msg(X_ERROR, "%s: failed to open pipe\n",
399 pInfo->name);
400 return BadAlloc;
404 pInfo->fd = pipefd[0];
406 goto finish;
409 /* Setup server */
410 asprintf(&tuio_port, "%i", pTuio->tuio_port);
411 pTuio->server = lo_server_new_with_proto(tuio_port, LO_UDP, _lo_error);
412 if (pTuio->server == NULL) {
413 xf86Msg(X_ERROR, "%s: Error allocating new lo_server\n",
414 pInfo->name);
415 return BadAlloc;
418 /* Register to receive all /tuio/2Dcur messages */
419 lo_server_add_method(pTuio->server, "/tuio/2Dcur", NULL,
420 _tuio_lo_2dcur_handle, pInfo);
422 pInfo->fd = lo_server_get_socket_fd(pTuio->server);
424 xf86FlushInput(pInfo->fd);
426 finish: xf86AddEnabledDevice(pInfo);
427 device->public.on = TRUE;
429 /* Allocate device storage and add to device list */
430 subdev = xcalloc(1, sizeof(SubDeviceRec));
431 subdev->pInfo = pInfo;
432 _subdev_add(g_pInfo, subdev);
433 break;
435 case DEVICE_OFF:
436 xf86Msg(X_INFO, "%s: Off\n", pInfo->name);
437 if (!device->public.on)
438 break;
440 xf86RemoveEnabledDevice(pInfo);
442 if (pTuio) {
443 lo_server_free(pTuio->server);
444 pInfo->fd = -1;
446 /* Remove subdev from list - This applies for both subdevices
447 * and the "core" device */
448 _subdev_remove(g_pInfo, pInfo);
450 device->public.on = FALSE;
451 break;
453 case DEVICE_CLOSE:
454 xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
455 _hal_remove_device(pInfo);
456 break;
459 return Success;
463 * Initialize the device properties
464 * TODO
466 TuioPropertyInit() {
470 * Free a TuioDeviceRec
472 static void
473 _free_tuiodev(TuioDevicePtr pTuio) {
474 ObjectPtr obj = pTuio->obj_list;
475 ObjectPtr tmp;
477 while (obj != NULL) {
478 tmp = obj->next;
479 xfree(obj);
480 obj = tmp;
483 xfree(pTuio);
487 * Handles OSC messages in the /tuio/2Dcur address space
489 static int
490 _tuio_lo_2dcur_handle(const char *path,
491 const char *types,
492 lo_arg **argv,
493 int argc,
494 void *data,
495 void *user_data) {
496 InputInfoPtr pInfo = user_data;
497 TuioDevicePtr pTuio = pInfo->private;
498 ObjectPtr *obj_list = &pTuio->obj_list;
499 ObjectPtr obj, objtemp;
500 char *act;
501 int i;
503 if (argc == 0) {
504 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d (argc == 0)\n",
505 pInfo->name);
506 return 0;
507 } else if(*types != 's') {
508 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d (types[0] != 's')\n",
509 pInfo->name);
510 return 0;
513 /* Flag as being processed, used in TuioReadInput() */
514 pTuio->processed = 1;
516 /* Parse message type */
517 /* Set message type: */
518 if (strcmp((char *)argv[0], "set") == 0) {
520 /* Simple type check */
521 if (strcmp(types, "sifffff")) {
522 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d set msg (types == %s)\n",
523 pInfo->name, types);
524 return 0;
527 obj = _object_get(*obj_list, argv[1]->i);
529 /* If not found, create a new object */
530 if (obj == NULL) {
531 obj = _object_new(argv[1]->i);
532 _object_add(obj_list, obj);
533 obj->subdev = _subdev_get(pInfo, &pTuio->subdev_list);
534 if (obj->subdev && pTuio->post_button_events)
535 obj->pending.button = True;
538 obj->pending.xpos = argv[2]->f;
539 obj->pending.ypos = argv[3]->f;
540 obj->pending.xvel = argv[4]->f;
541 obj->pending.yvel = argv[5]->f;
542 obj->pending.set = True;
544 } else if (strcmp((char *)argv[0], "alive") == 0) {
545 /* Mark all objects that are still alive */
546 obj = *obj_list;
547 while (obj != NULL) {
548 for (i=1; i<argc; i++) {
549 if (argv[i]->i == obj->id) {
550 obj->alive = True;
551 break;
554 obj = obj->next;
557 } else if (strcmp((char *)argv[0], "fseq") == 0) {
558 /* Simple type check */
559 if (strcmp(types, "si")) {
560 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d fseq msg (types == %s)\n",
561 pInfo->name, types);
562 return 0;
564 pTuio->fseq_new = argv[1]->i;
567 return 0;
571 * liblo error handler
573 static void
574 _lo_error(int num,
575 const char *msg,
576 const char *path)
578 xf86Msg(X_ERROR, "liblo: %s\n", msg);
582 * Retrieves an object from a list based on its id.
584 * @return NULL if not found.
586 static ObjectPtr
587 _object_get(ObjectPtr head, int id) {
588 ObjectPtr obj = head;
590 while (obj != NULL && obj->id != id) {
591 obj = obj->next;
594 return obj;
598 * Allocates and inserts a new object at the beginning of a list.
599 * Pointer to the new object is returned.
600 * Doesn't check for duplicate ids, so call _object_get() beforehand
601 * to make sure it doesn't exist already!!
603 * @return ptr to newly inserted object
605 static ObjectPtr
606 _object_new(int id) {
607 ObjectPtr new_obj = xcalloc(1, sizeof(ObjectRec));
609 new_obj->id = id;
610 new_obj->alive = True;
612 return new_obj;
616 * Adds a SubDevice to the beginning of the subdev_list list
618 static void
619 _object_add(ObjectPtr *obj_list, ObjectPtr obj) {
621 if (obj_list == NULL || obj == NULL)
622 return;
624 if (*obj_list != NULL) {
625 obj->next = *obj_list;
627 *obj_list = obj;
632 * Removes an Object with a specific id from a list.
634 static ObjectPtr
635 _object_remove(ObjectPtr *obj_list, int id) {
636 ObjectPtr obj = *obj_list;
637 ObjectPtr objtmp;
639 if (obj == NULL) return; /* Empty list */
641 if (obj->id == id) { /* Remove from head */
642 *obj_list = obj->next;
643 } else {
644 while (obj->next != NULL) {
645 if (obj->next->id == id) {
646 objtmp = obj->next;
647 obj->next = objtmp->next;
648 obj = objtmp;
649 obj->next = NULL;
650 return obj;
652 obj = obj->next;
654 obj = NULL;
657 return obj;
661 * Adds a SubDevice to the beginning of the subdev_list list
663 static void
664 _subdev_add(InputInfoPtr pInfo, SubDevicePtr subdev) {
665 TuioDevicePtr pTuio = pInfo->private;
666 SubDevicePtr *subdev_list = &pTuio->subdev_list;
667 ObjectPtr obj = pTuio->obj_list;
669 if (subdev_list == NULL || subdev == NULL)
670 return;
672 /* First check to see if there are any objects that don't have a
673 * subdevice that we can assign this subdevice to */
674 while (obj != NULL) {
675 if (obj->subdev == NULL) {
676 obj->subdev = subdev;
677 if (pTuio->post_button_events)
678 obj->pending.button = True;
679 obj->pending.set = True;
680 return;
682 obj = obj->next;
685 /* No subdevice-less objects, add to front of subdev list */
686 if (*subdev_list != NULL) {
687 subdev->next = *subdev_list;
689 *subdev_list = subdev;
693 * Gets any available subdevice
695 static SubDevicePtr
696 _subdev_get(InputInfoPtr pInfo, SubDevicePtr *subdev_list) {
697 SubDevicePtr subdev;
699 if (subdev_list == NULL || *subdev_list == NULL) {
700 _hal_create_devices(pInfo, 1); /* Create one new subdevice */
701 return NULL;
704 subdev = *subdev_list;
705 *subdev_list = subdev->next;
706 subdev->next = NULL;
708 return subdev;
711 static void
712 _subdev_remove(InputInfoPtr pInfo, InputInfoPtr sub_pInfo)
714 TuioDevicePtr pTuio = pInfo->private;
715 SubDevicePtr *subdev_list = &pTuio->subdev_list;
716 SubDevicePtr subdev = *subdev_list, last;
717 ObjectPtr obj = pTuio->obj_list;
718 Bool found = False;
720 /* First try to find it in the list of subdevices */
721 if (subdev != NULL && subdev->pInfo == sub_pInfo) {
722 found = True;
723 *subdev_list = subdev->next;
724 xfree(subdev);
725 } else if (subdev != NULL) {
726 last = subdev;
727 subdev = subdev->next;
728 while (subdev != NULL) {
729 if (subdev->pInfo == sub_pInfo) {
730 last->next = subdev->next;
731 found = True;
732 xfree(subdev);
733 break;
735 last = subdev;
736 subdev = subdev->next;
740 /* If it still hasn't been found, find the object that is holding
741 * it */
742 if (!found) {
743 while (obj != NULL) {
744 if (obj->subdev != NULL && obj->subdev->pInfo == sub_pInfo) {
745 xfree(obj->subdev);
746 obj->subdev = NULL;
747 found = True;
748 break;
750 obj = obj->next;
756 * Init the button map device. We only use one button.
758 static int
759 _init_buttons(DeviceIntPtr device)
761 InputInfoPtr pInfo = device->public.devicePrivate;
762 CARD8 *map;
763 Atom *labels;
764 int numbuttons = 2;
765 int ret = Success;
766 int i;
768 map = xcalloc(numbuttons, sizeof(CARD8));
769 labels = xcalloc(numbuttons, sizeof(Atom));
770 for (i=0; i<numbuttons; i++)
771 map[i] = i;
773 //map = xcalloc(1, sizeof(CARD8));
774 //*map = 3;
775 //label = XIGetKnownProperty("Button Left");
777 if (!InitButtonClassDeviceStruct(device, numbuttons/* 1 button */,
778 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
779 labels,
780 #endif
781 map)) {
782 xf86Msg(X_ERROR, "%s: Failed to register buttons.\n", pInfo->name);
783 ret = BadAlloc;
786 xfree(labels);
787 return ret;
791 * Init valuators for device, use x/y coordinates.
793 static int
794 _init_axes(DeviceIntPtr device)
796 InputInfoPtr pInfo = device->public.devicePrivate;
797 int i;
798 const int num_axes = 5;
799 Atom *atoms;
801 atoms = xcalloc(num_axes, sizeof(Atom));
802 //atom[0] = XI
804 if (!InitValuatorClassDeviceStruct(device,
805 num_axes,
806 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
807 atoms,
808 #endif
809 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
810 GetMotionHistory,
811 #endif
812 GetMotionHistorySize(),
814 return BadAlloc;
816 for (i = 0; i < 2; i++)
818 xf86InitValuatorAxisStruct(device, i,
819 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
820 atoms[i],
821 #endif
822 0, 0x7FFFFFFF, 1, 1, 1);
823 xf86InitValuatorDefaults(device, i);
826 for (i = 2; i < 6; i++)
828 xf86InitValuatorAxisStruct(device, i,
829 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
830 atoms[i],
831 #endif
832 0x80000000, 0x7FFFFFFF, 1, 1, 1);
833 xf86InitValuatorDefaults(device, i);
836 /* Use absolute mode. Currently, TUIO coords are mapped to the
837 * full screen area */
838 pInfo->dev->valuator->mode = Absolute;
839 if (!InitAbsoluteClassDeviceStruct(device))
840 return BadAlloc;
842 return Success;
846 * New device creation through hal
847 * I referenced the wacom hal-setup patch while writing this:
848 * http://cvs.fedoraproject.org/viewvc/rpms/linuxwacom/devel/linuxwacom-0.8.2.2-hal-setup.patch?revision=1.1&view=markup
850 * @return 0 if successful, 1 if failure
852 static int
853 _hal_create_devices(InputInfoPtr pInfo, int num) {
854 TuioDevicePtr pTuio = pInfo->private;
855 DBusError error;
856 DBusConnection *conn;
857 LibHalContext *ctx;
858 char *newdev;
859 char *name;
860 int i;
862 /* We need a new device to send motion/button events through.
863 * There isn't a great way to do this right now without native
864 * blob events, so just hack it out for now. Woot. */
866 /* Open connection to dbus and create contex */
867 dbus_error_init(&error);
868 if ((conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) {
869 xf86Msg(X_ERROR, "%s: Failed to open dbus connection: %s\n",
870 pInfo->name, error.message);
871 return 1;
874 if ((ctx = libhal_ctx_new()) == NULL) {
875 xf86Msg(X_ERROR, "%s: Failed to obtain hal context\n",
876 pInfo->name);
877 return 1;
880 dbus_error_init(&error);
881 libhal_ctx_set_dbus_connection(ctx, conn);
882 if (!libhal_ctx_init(ctx, &error)) {
883 xf86Msg(X_ERROR, "%s: Failed to initialize hal context: %s\n",
884 pInfo->name, error.message);
885 return 1;
888 /* Create new devices through hal */
889 for (i=0; i<num; i++) {
891 dbus_error_init(&error);
892 newdev = libhal_new_device(ctx, &error);
893 if (dbus_error_is_set(&error) == TRUE) {
894 xf86Msg(X_ERROR, "%s: Failed to create input device: %s\n",
895 pInfo->name, error.message);
896 return 1;
899 dbus_error_init(&error);
900 libhal_device_set_property_string(ctx, newdev, "input.device",
901 "tuio_subdevice", &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 dbus_error_init(&error);
909 libhal_device_set_property_bool(ctx, newdev, "RequireEnable",
910 False, &error);
911 if (dbus_error_is_set(&error) == TRUE) {
912 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
913 pInfo->name, error.message);
914 return 1;
917 dbus_error_init(&error);
918 libhal_device_set_property_string(ctx, newdev,
919 "input.x11_driver", "tuio",
920 &error);
921 if (dbus_error_is_set(&error) == TRUE) {
922 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
923 pInfo->name, error.message);
924 return 1;
927 /* Set "Type" property. This will be used in TuioPreInit to determine
928 * whether the new device is a subdev or not */
929 dbus_error_init(&error);
930 libhal_device_set_property_string(ctx, newdev,
931 "input.x11_options.Type",
932 "Object", &error);
933 if (dbus_error_is_set(&error) == TRUE) {
934 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
935 pInfo->name, error.message);
936 return 1;
939 asprintf(&name, "%s subdev %i", pInfo->name, pTuio->num_subdev);
941 /* Set name */
942 dbus_error_init(&error);
943 libhal_device_set_property_string(ctx, newdev,
944 "info.product", name,
945 &error);
946 if (dbus_error_is_set(&error) == TRUE) {
947 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
948 pInfo->name, error.message);
949 return 1;
952 /* Finalize creation of new device */
953 dbus_error_init(&error);
954 libhal_device_commit_to_gdl(ctx, newdev, "/org/freedesktop/Hal/devices/tuio_subdev", &error);
955 if (dbus_error_is_set (&error) == TRUE) {
956 xf86Msg(X_ERROR, "%s: Failed to add input device: %s\n",
957 pInfo->name, error.message);
958 return 1;
961 xfree(name);
962 pTuio->num_subdev++;
965 if (!libhal_ctx_shutdown(ctx, &error)) {
966 xf86Msg(X_ERROR, "%s: Unable to shutdown hal context: %s\n",
967 pInfo->name, error.message);
968 return 1;
970 libhal_ctx_free(ctx);
972 return 0;
975 static int
976 _hal_remove_device(InputInfoPtr pInfo) {
977 DBusError error;
978 DBusConnection *conn;
979 LibHalContext *ctx;
980 char** devices;
981 int i, num_devices;
983 xf86Msg(X_INFO, "%s: Removing subdevice\n",
984 pInfo->name);
986 /* Open connection to dbus and create contex */
987 dbus_error_init(&error);
988 if ((conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) {
989 xf86Msg(X_ERROR, "%s: Failed to open dbus connection: %s\n",
990 pInfo->name, error.message);
991 return 1;
994 if ((ctx = libhal_ctx_new()) == NULL) {
995 xf86Msg(X_ERROR, "%s: Failed to obtain hal context\n",
996 pInfo->name);
997 return 1;
1000 dbus_error_init(&error);
1001 libhal_ctx_set_dbus_connection(ctx, conn);
1002 if (!libhal_ctx_init(ctx, &error)) {
1003 xf86Msg(X_ERROR, "%s: Failed to initialize hal context: %s\n",
1004 pInfo->name, error.message);
1005 return 1;
1008 devices = libhal_manager_find_device_string_match(ctx, "info.product",
1009 pInfo->name,
1010 &num_devices,
1011 &error);
1012 if (dbus_error_is_set(&error) == TRUE) {
1013 xf86Msg(X_ERROR, "%s: Failed when trying to find device: %s\n",
1014 pInfo->name, error.message);
1015 return 1;
1018 if (num_devices == 0) {
1019 xf86Msg(X_ERROR, "%s: Unable to find subdevice in HAL GDL\n",
1020 pInfo->name);
1021 } else {
1022 for (i=0; i<num_devices; i++) {
1023 xf86Msg(X_INFO, "%s: Removing subdevice with udi '%s'\n",
1024 pInfo->name, devices[i]);
1025 if (!libhal_remove_device(ctx, devices[i], &error)) {
1026 xf86Msg(X_ERROR, "%s: Unable to remove subdevice: %s\n",
1027 pInfo->name, error.message);
1032 if (!libhal_ctx_shutdown(ctx, &error)) {
1033 xf86Msg(X_ERROR, "%s: Unable to shutdown hal context: %s\n",
1034 pInfo->name, error.message);
1035 return 1;
1037 libhal_ctx_free(ctx);
1039 return 0;