Added option for hiding device pointers
[xf86-input-tuio.git] / src / tuio.c
blob8d6558a60d96d43d3f12ea198f153f41e08c5c32
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", DEFAULT_FSEQ_THRESHOLD);
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);
240 /* Get setting for whether to hide devices when idle */
241 pTuio->hide_devices = xf86CheckBoolOption(dev->commonOptions,
242 "PseudoHide", True);
245 /* Set up InputInfoPtr */
246 pInfo->name = xstrdup(dev->identifier);
247 pInfo->flags = 0;
248 pInfo->type_name = XI_TOUCHSCREEN; /* FIXME: Correct type? */
249 pInfo->conf_idev = dev;
250 pInfo->read_input = pTuio ? TuioReadInput : TuioObjReadInput; /* Set callback */
251 pInfo->device_control = TuioControl; /* Set callback */
252 pInfo->switch_mode = NULL;
254 /* Process common device options */
255 xf86CollectInputOptions(pInfo, NULL, NULL);
256 xf86ProcessCommonOptions(pInfo, pInfo->options);
258 pInfo->flags |= XI86_OPEN_ON_INIT;
259 pInfo->flags |= XI86_CONFIGURED;
261 return pInfo;
265 * Clean up
267 static void
268 TuioUnInit(InputDriverPtr drv,
269 InputInfoPtr pInfo,
270 int flags)
272 xf86DeleteInput(pInfo, 0);
276 * Empty callback for object device.
278 static void
279 TuioObjReadInput(InputInfoPtr pInfo) {
280 return;
284 * Handle new TUIO data on the socket
286 static void
287 TuioReadInput(InputInfoPtr pInfo)
289 TuioDevicePtr pTuio = pInfo->private;
290 ObjectPtr *obj_list = &pTuio->obj_list;
291 ObjectPtr obj = pTuio->obj_list;
292 SubDevicePtr *subdev_list = &pTuio->subdev_list;
293 ObjectPtr objtmp;
294 int valuators[NUM_VALUATORS];
296 while (xf86WaitForInput(pInfo->fd, 0) > 0)
298 /* The liblo handler will set this flag if anything was processed */
299 pTuio->processed = 0;
301 /* liblo will receive a message and call the appropriate
302 * handlers (i.e. _tuio_lo_cur2d_hande()) */
303 lo_server_recv_noblock(pTuio->server, 0);
305 /* During the processing of the previous message/bundle,
306 * any "active" messages will be handled by flagging
307 * the listed object ids. Now that processing is done,
308 * remove any dead object ids and set any pending changes.
309 * Also check to make sure the processed data was newer than
310 * the last processed data */
311 if (pTuio->processed &&
312 (pTuio->fseq_new > pTuio->fseq_old ||
313 pTuio->fseq_old - pTuio->fseq_new > pTuio->fseq_threshold)) {
315 while (obj != NULL) {
316 if (!obj->alive) {
317 if (obj->subdev && pTuio->post_button_events) {
318 /* Post button "up" event */
319 xf86PostButtonEvent(obj->subdev->pInfo->dev, TRUE, 1, FALSE, 0, 0);
321 valuators[0] = 0x7FFFFFFF;
322 valuators[1] = 0x7FFFFFFF;
323 valuators[2] = 0;
324 valuators[3] = 0;
326 xf86PostMotionEventP(obj->subdev->pInfo->dev,
327 TRUE, /* is_absolute */
328 0, /* first_valuator */
329 NUM_VALUATORS, /* num_valuators */
330 valuators);
332 objtmp = obj->next;
333 obj = _object_remove(obj_list, obj->id);
334 _subdev_add(pInfo, obj->subdev);
335 xfree(obj);
336 obj = objtmp;
339 } else {
340 /* Object is alive. Check to see if an update has been set.
341 * If it has been updated and it has a subdevice to send
342 * events on, send the event) */
343 if (obj->pending.set && obj->subdev) {
344 obj->xpos = obj->pending.xpos;
345 obj->ypos = obj->pending.ypos;
346 obj->xvel = obj->pending.xvel;
347 obj->yvel = obj->pending.yvel;
348 obj->pending.set = False;
350 /* OKAY FOR NOW, maybe update with a better range? */
351 /* TODO: Add more valuators with additional information */
352 valuators[0] = obj->xpos * 0x7FFFFFFF;
353 valuators[1] = obj->ypos * 0x7FFFFFFF;
354 valuators[2] = obj->xvel * 0x7FFFFFFF;
355 valuators[3] = obj->yvel * 0x7FFFFFFF;
357 xf86PostMotionEventP(obj->subdev->pInfo->dev,
358 TRUE, /* is_absolute */
359 0, /* first_valuator */
360 NUM_VALUATORS, /* num_valuators */
361 valuators);
363 if (obj->pending.button) {
364 xf86PostButtonEvent(obj->subdev->pInfo->dev, TRUE, 1, TRUE, 0, 0);
365 obj->pending.button = False;
368 obj->alive = 0; /* Reset for next message */
369 obj = obj->next;
372 pTuio->fseq_old = pTuio->fseq_new;
378 * Handle device state changes
380 static int
381 TuioControl(DeviceIntPtr device,
382 int what)
384 InputInfoPtr pInfo = device->public.devicePrivate;
385 TuioDevicePtr pTuio = pInfo->private;
386 SubDevicePtr subdev;
387 char *tuio_port;
388 int res;
390 switch (what)
392 case DEVICE_INIT:
393 xf86Msg(X_INFO, "%s: Init\n", pInfo->name);
394 _init_buttons(device);
395 _init_axes(device);
397 /* If this is a "core" device, create object devices */
398 if (pTuio) {
399 _hal_create_devices(pInfo, pTuio->init_num_subdev);
401 break;
403 case DEVICE_ON: /* Open socket and start listening! */
404 xf86Msg(X_INFO, "%s: On.\n", pInfo->name);
405 if (device->public.on)
406 break;
408 /* If this is an object device, use a dummy pipe,
409 * and add device to subdev list */
410 if (!pTuio) {
411 if (pipefd[0] == -1) {
412 SYSCALL(res = pipe(pipefd));
413 if (res == -1) {
414 xf86Msg(X_ERROR, "%s: failed to open pipe\n",
415 pInfo->name);
416 return BadAlloc;
420 pInfo->fd = pipefd[0];
422 goto finish;
425 /* Setup server */
426 asprintf(&tuio_port, "%i", pTuio->tuio_port);
427 pTuio->server = lo_server_new_with_proto(tuio_port, LO_UDP, _lo_error);
428 if (pTuio->server == NULL) {
429 xf86Msg(X_ERROR, "%s: Error allocating new lo_server\n",
430 pInfo->name);
431 return BadAlloc;
434 /* Register to receive all /tuio/2Dcur messages */
435 lo_server_add_method(pTuio->server, "/tuio/2Dcur", NULL,
436 _tuio_lo_2dcur_handle, pInfo);
438 pInfo->fd = lo_server_get_socket_fd(pTuio->server);
440 xf86FlushInput(pInfo->fd);
442 finish: xf86AddEnabledDevice(pInfo);
443 device->public.on = TRUE;
445 /* Allocate device storage and add to device list */
446 subdev = xcalloc(1, sizeof(SubDeviceRec));
447 subdev->pInfo = pInfo;
448 _subdev_add(g_pInfo, subdev);
449 break;
451 case DEVICE_OFF:
452 xf86Msg(X_INFO, "%s: Off\n", pInfo->name);
453 if (!device->public.on)
454 break;
456 xf86RemoveEnabledDevice(pInfo);
458 if (pTuio) {
459 lo_server_free(pTuio->server);
460 pInfo->fd = -1;
462 /* Remove subdev from list - This applies for both subdevices
463 * and the "core" device */
464 _subdev_remove(g_pInfo, pInfo);
466 device->public.on = FALSE;
467 break;
469 case DEVICE_CLOSE:
470 xf86Msg(X_INFO, "%s: Close\n", pInfo->name);
471 _hal_remove_device(pInfo);
472 break;
475 return Success;
479 * Initialize the device properties
480 * TODO
482 TuioPropertyInit() {
486 * Free a TuioDeviceRec
488 static void
489 _free_tuiodev(TuioDevicePtr pTuio) {
490 ObjectPtr obj = pTuio->obj_list;
491 ObjectPtr tmp;
493 while (obj != NULL) {
494 tmp = obj->next;
495 xfree(obj);
496 obj = tmp;
499 xfree(pTuio);
503 * Handles OSC messages in the /tuio/2Dcur address space
505 static int
506 _tuio_lo_2dcur_handle(const char *path,
507 const char *types,
508 lo_arg **argv,
509 int argc,
510 void *data,
511 void *user_data) {
512 InputInfoPtr pInfo = user_data;
513 TuioDevicePtr pTuio = pInfo->private;
514 ObjectPtr *obj_list = &pTuio->obj_list;
515 ObjectPtr obj, objtemp;
516 char *act;
517 int i;
519 if (argc == 0) {
520 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d (argc == 0)\n",
521 pInfo->name);
522 return 0;
523 } else if(*types != 's') {
524 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d (types[0] != 's')\n",
525 pInfo->name);
526 return 0;
529 /* Flag as being processed, used in TuioReadInput() */
530 pTuio->processed = 1;
532 /* Parse message type */
533 /* Set message type: */
534 if (strcmp((char *)argv[0], "set") == 0) {
536 /* Simple type check */
537 if (strcmp(types, "sifffff")) {
538 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d set msg (types == %s)\n",
539 pInfo->name, types);
540 return 0;
543 obj = _object_get(*obj_list, argv[1]->i);
545 /* If not found, create a new object */
546 if (obj == NULL) {
547 obj = _object_new(argv[1]->i);
548 _object_add(obj_list, obj);
549 obj->subdev = _subdev_get(pInfo, &pTuio->subdev_list);
550 if (obj->subdev && pTuio->post_button_events)
551 obj->pending.button = True;
554 obj->pending.xpos = argv[2]->f;
555 obj->pending.ypos = argv[3]->f;
556 obj->pending.xvel = argv[4]->f;
557 obj->pending.yvel = argv[5]->f;
558 obj->pending.set = True;
560 } else if (strcmp((char *)argv[0], "alive") == 0) {
561 /* Mark all objects that are still alive */
562 obj = *obj_list;
563 while (obj != NULL) {
564 for (i=1; i<argc; i++) {
565 if (argv[i]->i == obj->id) {
566 obj->alive = True;
567 break;
570 obj = obj->next;
573 } else if (strcmp((char *)argv[0], "fseq") == 0) {
574 /* Simple type check */
575 if (strcmp(types, "si")) {
576 xf86Msg(X_ERROR, "%s: Error in /tuio/cur2d fseq msg (types == %s)\n",
577 pInfo->name, types);
578 return 0;
580 pTuio->fseq_new = argv[1]->i;
583 return 0;
587 * liblo error handler
589 static void
590 _lo_error(int num,
591 const char *msg,
592 const char *path)
594 xf86Msg(X_ERROR, "liblo: %s\n", msg);
598 * Retrieves an object from a list based on its id.
600 * @return NULL if not found.
602 static ObjectPtr
603 _object_get(ObjectPtr head, int id) {
604 ObjectPtr obj = head;
606 while (obj != NULL && obj->id != id) {
607 obj = obj->next;
610 return obj;
614 * Allocates and inserts a new object at the beginning of a list.
615 * Pointer to the new object is returned.
616 * Doesn't check for duplicate ids, so call _object_get() beforehand
617 * to make sure it doesn't exist already!!
619 * @return ptr to newly inserted object
621 static ObjectPtr
622 _object_new(int id) {
623 ObjectPtr new_obj = xcalloc(1, sizeof(ObjectRec));
625 new_obj->id = id;
626 new_obj->alive = True;
628 return new_obj;
632 * Adds a SubDevice to the beginning of the subdev_list list
634 static void
635 _object_add(ObjectPtr *obj_list, ObjectPtr obj) {
637 if (obj_list == NULL || obj == NULL)
638 return;
640 if (*obj_list != NULL) {
641 obj->next = *obj_list;
643 *obj_list = obj;
648 * Removes an Object with a specific id from a list.
650 static ObjectPtr
651 _object_remove(ObjectPtr *obj_list, int id) {
652 ObjectPtr obj = *obj_list;
653 ObjectPtr objtmp;
655 if (obj == NULL) return; /* Empty list */
657 if (obj->id == id) { /* Remove from head */
658 *obj_list = obj->next;
659 } else {
660 while (obj->next != NULL) {
661 if (obj->next->id == id) {
662 objtmp = obj->next;
663 obj->next = objtmp->next;
664 obj = objtmp;
665 obj->next = NULL;
666 return obj;
668 obj = obj->next;
670 obj = NULL;
673 return obj;
677 * Adds a SubDevice to the beginning of the subdev_list list
679 static void
680 _subdev_add(InputInfoPtr pInfo, SubDevicePtr subdev) {
681 TuioDevicePtr pTuio = pInfo->private;
682 SubDevicePtr *subdev_list = &pTuio->subdev_list;
683 ObjectPtr obj = pTuio->obj_list;
685 if (subdev_list == NULL || subdev == NULL)
686 return;
688 /* First check to see if there are any objects that don't have a
689 * subdevice that we can assign this subdevice to */
690 while (obj != NULL) {
691 if (obj->subdev == NULL) {
692 obj->subdev = subdev;
693 if (pTuio->post_button_events)
694 obj->pending.button = True;
695 obj->pending.set = True;
696 return;
698 obj = obj->next;
701 /* No subdevice-less objects, add to front of subdev list */
702 if (*subdev_list != NULL) {
703 subdev->next = *subdev_list;
705 *subdev_list = subdev;
709 * Gets any available subdevice
711 static SubDevicePtr
712 _subdev_get(InputInfoPtr pInfo, SubDevicePtr *subdev_list) {
713 SubDevicePtr subdev;
715 if (subdev_list == NULL || *subdev_list == NULL) {
716 _hal_create_devices(pInfo, 1); /* Create one new subdevice */
717 return NULL;
720 subdev = *subdev_list;
721 *subdev_list = subdev->next;
722 subdev->next = NULL;
724 return subdev;
727 static void
728 _subdev_remove(InputInfoPtr pInfo, InputInfoPtr sub_pInfo)
730 TuioDevicePtr pTuio = pInfo->private;
731 SubDevicePtr *subdev_list = &pTuio->subdev_list;
732 SubDevicePtr subdev = *subdev_list, last;
733 ObjectPtr obj = pTuio->obj_list;
734 Bool found = False;
736 /* First try to find it in the list of subdevices */
737 if (subdev != NULL && subdev->pInfo == sub_pInfo) {
738 found = True;
739 *subdev_list = subdev->next;
740 xfree(subdev);
741 } else if (subdev != NULL) {
742 last = subdev;
743 subdev = subdev->next;
744 while (subdev != NULL) {
745 if (subdev->pInfo == sub_pInfo) {
746 last->next = subdev->next;
747 found = True;
748 xfree(subdev);
749 break;
751 last = subdev;
752 subdev = subdev->next;
756 /* If it still hasn't been found, find the object that is holding
757 * it */
758 if (!found) {
759 while (obj != NULL) {
760 if (obj->subdev != NULL && obj->subdev->pInfo == sub_pInfo) {
761 xfree(obj->subdev);
762 obj->subdev = NULL;
763 found = True;
764 break;
766 obj = obj->next;
772 * Init the button map device. We only use one button.
774 static int
775 _init_buttons(DeviceIntPtr device)
777 InputInfoPtr pInfo = device->public.devicePrivate;
778 CARD8 *map;
779 Atom *labels;
780 int numbuttons = 2;
781 int ret = Success;
782 int i;
784 map = xcalloc(numbuttons, sizeof(CARD8));
785 labels = xcalloc(numbuttons, sizeof(Atom));
786 for (i=0; i<numbuttons; i++)
787 map[i] = i;
789 //map = xcalloc(1, sizeof(CARD8));
790 //*map = 3;
791 //label = XIGetKnownProperty("Button Left");
793 if (!InitButtonClassDeviceStruct(device, numbuttons/* 1 button */,
794 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
795 labels,
796 #endif
797 map)) {
798 xf86Msg(X_ERROR, "%s: Failed to register buttons.\n", pInfo->name);
799 ret = BadAlloc;
802 xfree(labels);
803 return ret;
807 * Init valuators for device, use x/y coordinates.
809 static int
810 _init_axes(DeviceIntPtr device)
812 InputInfoPtr pInfo = device->public.devicePrivate;
813 int i;
814 const int num_axes = 5;
815 Atom *atoms;
817 atoms = xcalloc(num_axes, sizeof(Atom));
818 //atom[0] = XI
820 if (!InitValuatorClassDeviceStruct(device,
821 num_axes,
822 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
823 atoms,
824 #endif
825 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
826 GetMotionHistory,
827 #endif
828 GetMotionHistorySize(),
830 return BadAlloc;
832 /* Setup x/y axes */
833 for (i = 0; i < 2; i++)
835 xf86InitValuatorAxisStruct(device, i,
836 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
837 atoms[i],
838 #endif
839 0, 0x7FFFFFFF, 1, 1, 1);
840 xf86InitValuatorDefaults(device, i);
843 /* Setup velocity and acceleration axes */
844 for (i = 2; i < 6; i++)
846 xf86InitValuatorAxisStruct(device, i,
847 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
848 atoms[i],
849 #endif
850 0x80000000, 0x7FFFFFFF, 1, 1, 1);
851 xf86InitValuatorDefaults(device, i);
854 /* Use absolute mode. Currently, TUIO coords are mapped to the
855 * full screen area */
856 pInfo->dev->valuator->mode = Absolute;
857 if (!InitAbsoluteClassDeviceStruct(device))
858 return BadAlloc;
860 return Success;
864 * New device creation through hal
865 * I referenced the wacom hal-setup patch while writing this:
866 * http://cvs.fedoraproject.org/viewvc/rpms/linuxwacom/devel/linuxwacom-0.8.2.2-hal-setup.patch?revision=1.1&view=markup
868 * @return 0 if successful, 1 if failure
870 static int
871 _hal_create_devices(InputInfoPtr pInfo, int num) {
872 TuioDevicePtr pTuio = pInfo->private;
873 DBusError error;
874 DBusConnection *conn;
875 LibHalContext *ctx;
876 char *newdev;
877 char *name;
878 int i;
880 /* We need a new device to send motion/button events through.
881 * There isn't a great way to do this right now without native
882 * blob events, so just hack it out for now. Woot. */
884 /* Open connection to dbus and create contex */
885 dbus_error_init(&error);
886 if ((conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) {
887 xf86Msg(X_ERROR, "%s: Failed to open dbus connection: %s\n",
888 pInfo->name, error.message);
889 return 1;
892 if ((ctx = libhal_ctx_new()) == NULL) {
893 xf86Msg(X_ERROR, "%s: Failed to obtain hal context\n",
894 pInfo->name);
895 return 1;
898 dbus_error_init(&error);
899 libhal_ctx_set_dbus_connection(ctx, conn);
900 if (!libhal_ctx_init(ctx, &error)) {
901 xf86Msg(X_ERROR, "%s: Failed to initialize hal context: %s\n",
902 pInfo->name, error.message);
903 return 1;
906 /* Create new devices through hal */
907 for (i=0; i<num; i++) {
909 dbus_error_init(&error);
910 newdev = libhal_new_device(ctx, &error);
911 if (dbus_error_is_set(&error) == TRUE) {
912 xf86Msg(X_ERROR, "%s: Failed to create input device: %s\n",
913 pInfo->name, error.message);
914 return 1;
917 dbus_error_init(&error);
918 libhal_device_set_property_string(ctx, newdev, "input.device",
919 "tuio_subdevice", &error);
920 if (dbus_error_is_set(&error) == TRUE) {
921 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
922 pInfo->name, error.message);
923 return 1;
926 dbus_error_init(&error);
927 libhal_device_set_property_bool(ctx, newdev, "RequireEnable",
928 False, &error);
929 if (dbus_error_is_set(&error) == TRUE) {
930 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
931 pInfo->name, error.message);
932 return 1;
935 dbus_error_init(&error);
936 libhal_device_set_property_string(ctx, newdev,
937 "input.x11_driver", "tuio",
938 &error);
939 if (dbus_error_is_set(&error) == TRUE) {
940 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
941 pInfo->name, error.message);
942 return 1;
945 /* Set "Type" property. This will be used in TuioPreInit to determine
946 * whether the new device is a subdev or not */
947 dbus_error_init(&error);
948 libhal_device_set_property_string(ctx, newdev,
949 "input.x11_options.Type",
950 "Object", &error);
951 if (dbus_error_is_set(&error) == TRUE) {
952 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
953 pInfo->name, error.message);
954 return 1;
957 asprintf(&name, "%s subdev %i", pInfo->name, pTuio->num_subdev);
959 /* Set name */
960 dbus_error_init(&error);
961 libhal_device_set_property_string(ctx, newdev,
962 "info.product", name,
963 &error);
964 if (dbus_error_is_set(&error) == TRUE) {
965 xf86Msg(X_ERROR, "%s: Failed to set hal property: %s\n",
966 pInfo->name, error.message);
967 return 1;
970 /* Finalize creation of new device */
971 dbus_error_init(&error);
972 libhal_device_commit_to_gdl(ctx, newdev, "/org/freedesktop/Hal/devices/tuio_subdev", &error);
973 if (dbus_error_is_set (&error) == TRUE) {
974 xf86Msg(X_ERROR, "%s: Failed to add input device: %s\n",
975 pInfo->name, error.message);
976 return 1;
979 xfree(name);
980 pTuio->num_subdev++;
983 if (!libhal_ctx_shutdown(ctx, &error)) {
984 xf86Msg(X_ERROR, "%s: Unable to shutdown hal context: %s\n",
985 pInfo->name, error.message);
986 return 1;
988 libhal_ctx_free(ctx);
990 return 0;
993 static int
994 _hal_remove_device(InputInfoPtr pInfo) {
995 DBusError error;
996 DBusConnection *conn;
997 LibHalContext *ctx;
998 char** devices;
999 int i, num_devices;
1001 xf86Msg(X_INFO, "%s: Removing subdevice\n",
1002 pInfo->name);
1004 /* Open connection to dbus and create contex */
1005 dbus_error_init(&error);
1006 if ((conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) {
1007 xf86Msg(X_ERROR, "%s: Failed to open dbus connection: %s\n",
1008 pInfo->name, error.message);
1009 return 1;
1012 if ((ctx = libhal_ctx_new()) == NULL) {
1013 xf86Msg(X_ERROR, "%s: Failed to obtain hal context\n",
1014 pInfo->name);
1015 return 1;
1018 dbus_error_init(&error);
1019 libhal_ctx_set_dbus_connection(ctx, conn);
1020 if (!libhal_ctx_init(ctx, &error)) {
1021 xf86Msg(X_ERROR, "%s: Failed to initialize hal context: %s\n",
1022 pInfo->name, error.message);
1023 return 1;
1026 devices = libhal_manager_find_device_string_match(ctx, "info.product",
1027 pInfo->name,
1028 &num_devices,
1029 &error);
1030 if (dbus_error_is_set(&error) == TRUE) {
1031 xf86Msg(X_ERROR, "%s: Failed when trying to find device: %s\n",
1032 pInfo->name, error.message);
1033 return 1;
1036 if (num_devices == 0) {
1037 xf86Msg(X_ERROR, "%s: Unable to find subdevice in HAL GDL\n",
1038 pInfo->name);
1039 } else {
1040 for (i=0; i<num_devices; i++) {
1041 xf86Msg(X_INFO, "%s: Removing subdevice with udi '%s'\n",
1042 pInfo->name, devices[i]);
1043 if (!libhal_remove_device(ctx, devices[i], &error)) {
1044 xf86Msg(X_ERROR, "%s: Unable to remove subdevice: %s\n",
1045 pInfo->name, error.message);
1050 if (!libhal_ctx_shutdown(ctx, &error)) {
1051 xf86Msg(X_ERROR, "%s: Unable to shutdown hal context: %s\n",
1052 pInfo->name, error.message);
1053 return 1;
1055 libhal_ctx_free(ctx);
1057 return 0;