2 * Copyright (c) 2009 Ryan Huffman
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
23 * Ryan Huffman (ryanhuffman@gmail.com)
28 #include <xf86Xinput.h>
29 #include <xf86_OSlib.h>
30 #include <xserver-properties.h>
38 /* InputInfoPtr for main tuio device */
39 static InputInfoPtr g_pInfo
;
40 static int pipefd
[2] = {-1, -1};
42 /* Module Functions */
44 TuioPlug(pointer
, pointer
, int *, int *);
49 /* Driver Functions */
51 TuioPreInit(InputDriverPtr
, IDevPtr
, int);
54 TuioUnInit(InputDriverPtr
, InputInfoPtr
, int);
57 TuioObjReadInput(InputInfoPtr pInfo
);
60 TuioReadInput(InputInfoPtr
);
63 TuioControl(DeviceIntPtr
, int);
65 /* Internal Functions */
67 _hal_create_devices(InputInfoPtr pInfo
, int num
);
70 _init_buttons(DeviceIntPtr device
);
73 _init_axes(DeviceIntPtr device
);
76 _tuio_lo_2dcur_handle(const char *path
,
84 _free_tuiodev(TuioDevicePtr pTuio
);
91 /* Object and Subdev list manipulation functions */
93 _object_get(ObjectPtr head
, int id
);
99 _object_add(ObjectPtr
*obj_list
, ObjectPtr obj
);
102 _object_remove(ObjectPtr
*obj_list
, int id
);
105 _subdev_add(InputInfoPtr pInfo
, SubDevicePtr subdev
);
108 _subdev_remove(InputInfoPtr pInfo
, InputInfoPtr sub_pInfo
);
111 _subdev_get(InputInfoPtr pInfo
, SubDevicePtr
*subdev_list
);
114 _hal_remove_device(InputInfoPtr pInfo
);
116 /* Driver information */
117 static XF86ModuleVersionInfo TuioVersionRec
=
123 XORG_VERSION_CURRENT
,
124 PACKAGE_VERSION_MAJOR
, PACKAGE_VERSION_MINOR
, PACKAGE_VERSION_PATCHLEVEL
,
131 _X_EXPORT InputDriverRec TUIO
=
142 _X_EXPORT XF86ModuleData tuioModuleData
=
150 TuioPlug(pointer module
,
155 xf86AddInputDriver(&TUIO
, module
, 0);
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
174 TuioPreInit(InputDriverPtr drv
,
179 TuioDevicePtr pTuio
= NULL
;
182 int num_subdev
, tuio_port
;
184 if (!(pInfo
= xf86AllocateInput(drv
, 0)))
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
);
195 if (!(pTuio
= xcalloc(1, sizeof(TuioDeviceRec
)))) {
196 xf86DeleteInput(pInfo
, 0);
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",
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
,
245 /* Set up InputInfoPtr */
246 pInfo
->name
= xstrdup(dev
->identifier
);
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
;
268 TuioUnInit(InputDriverPtr drv
,
272 xf86DeleteInput(pInfo
, 0);
276 * Empty callback for object device.
279 TuioObjReadInput(InputInfoPtr pInfo
) {
284 * Handle new TUIO data on the socket
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
;
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
) {
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;
326 xf86PostMotionEventP(obj
->subdev
->pInfo
->dev
,
327 TRUE
, /* is_absolute */
328 0, /* first_valuator */
329 NUM_VALUATORS
, /* num_valuators */
333 obj
= _object_remove(obj_list
, obj
->id
);
334 _subdev_add(pInfo
, obj
->subdev
);
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 */
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 */
372 pTuio
->fseq_old
= pTuio
->fseq_new
;
378 * Handle device state changes
381 TuioControl(DeviceIntPtr device
,
384 InputInfoPtr pInfo
= device
->public.devicePrivate
;
385 TuioDevicePtr pTuio
= pInfo
->private;
393 xf86Msg(X_INFO
, "%s: Init\n", pInfo
->name
);
394 _init_buttons(device
);
397 /* If this is a "core" device, create object devices */
399 _hal_create_devices(pInfo
, pTuio
->init_num_subdev
);
403 case DEVICE_ON
: /* Open socket and start listening! */
404 xf86Msg(X_INFO
, "%s: On.\n", pInfo
->name
);
405 if (device
->public.on
)
408 /* If this is an object device, use a dummy pipe,
409 * and add device to subdev list */
411 if (pipefd
[0] == -1) {
412 SYSCALL(res
= pipe(pipefd
));
414 xf86Msg(X_ERROR
, "%s: failed to open pipe\n",
420 pInfo
->fd
= pipefd
[0];
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",
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
);
452 xf86Msg(X_INFO
, "%s: Off\n", pInfo
->name
);
453 if (!device
->public.on
)
456 xf86RemoveEnabledDevice(pInfo
);
459 lo_server_free(pTuio
->server
);
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
;
470 xf86Msg(X_INFO
, "%s: Close\n", pInfo
->name
);
471 _hal_remove_device(pInfo
);
479 * Initialize the device properties
486 * Free a TuioDeviceRec
489 _free_tuiodev(TuioDevicePtr pTuio
) {
490 ObjectPtr obj
= pTuio
->obj_list
;
493 while (obj
!= NULL
) {
503 * Handles OSC messages in the /tuio/2Dcur address space
506 _tuio_lo_2dcur_handle(const char *path
,
512 InputInfoPtr pInfo
= user_data
;
513 TuioDevicePtr pTuio
= pInfo
->private;
514 ObjectPtr
*obj_list
= &pTuio
->obj_list
;
515 ObjectPtr obj
, objtemp
;
520 xf86Msg(X_ERROR
, "%s: Error in /tuio/cur2d (argc == 0)\n",
523 } else if(*types
!= 's') {
524 xf86Msg(X_ERROR
, "%s: Error in /tuio/cur2d (types[0] != 's')\n",
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",
543 obj
= _object_get(*obj_list
, argv
[1]->i
);
545 /* If not found, create a new object */
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 */
563 while (obj
!= NULL
) {
564 for (i
=1; i
<argc
; i
++) {
565 if (argv
[i
]->i
== obj
->id
) {
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",
580 pTuio
->fseq_new
= argv
[1]->i
;
587 * liblo error handler
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.
603 _object_get(ObjectPtr head
, int id
) {
604 ObjectPtr obj
= head
;
606 while (obj
!= NULL
&& obj
->id
!= id
) {
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
622 _object_new(int id
) {
623 ObjectPtr new_obj
= xcalloc(1, sizeof(ObjectRec
));
626 new_obj
->alive
= True
;
632 * Adds a SubDevice to the beginning of the subdev_list list
635 _object_add(ObjectPtr
*obj_list
, ObjectPtr obj
) {
637 if (obj_list
== NULL
|| obj
== NULL
)
640 if (*obj_list
!= NULL
) {
641 obj
->next
= *obj_list
;
648 * Removes an Object with a specific id from a list.
651 _object_remove(ObjectPtr
*obj_list
, int id
) {
652 ObjectPtr obj
= *obj_list
;
655 if (obj
== NULL
) return; /* Empty list */
657 if (obj
->id
== id
) { /* Remove from head */
658 *obj_list
= obj
->next
;
660 while (obj
->next
!= NULL
) {
661 if (obj
->next
->id
== id
) {
663 obj
->next
= objtmp
->next
;
677 * Adds a SubDevice to the beginning of the subdev_list list
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
)
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
;
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
712 _subdev_get(InputInfoPtr pInfo
, SubDevicePtr
*subdev_list
) {
715 if (subdev_list
== NULL
|| *subdev_list
== NULL
) {
716 _hal_create_devices(pInfo
, 1); /* Create one new subdevice */
720 subdev
= *subdev_list
;
721 *subdev_list
= subdev
->next
;
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
;
736 /* First try to find it in the list of subdevices */
737 if (subdev
!= NULL
&& subdev
->pInfo
== sub_pInfo
) {
739 *subdev_list
= subdev
->next
;
741 } else if (subdev
!= NULL
) {
743 subdev
= subdev
->next
;
744 while (subdev
!= NULL
) {
745 if (subdev
->pInfo
== sub_pInfo
) {
746 last
->next
= subdev
->next
;
752 subdev
= subdev
->next
;
756 /* If it still hasn't been found, find the object that is holding
759 while (obj
!= NULL
) {
760 if (obj
->subdev
!= NULL
&& obj
->subdev
->pInfo
== sub_pInfo
) {
772 * Init the button map device. We only use one button.
775 _init_buttons(DeviceIntPtr device
)
777 InputInfoPtr pInfo
= device
->public.devicePrivate
;
784 map
= xcalloc(numbuttons
, sizeof(CARD8
));
785 labels
= xcalloc(numbuttons
, sizeof(Atom
));
786 for (i
=0; i
<numbuttons
; i
++)
789 //map = xcalloc(1, sizeof(CARD8));
791 //label = XIGetKnownProperty("Button Left");
793 if (!InitButtonClassDeviceStruct(device
, numbuttons
/* 1 button */,
794 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
798 xf86Msg(X_ERROR
, "%s: Failed to register buttons.\n", pInfo
->name
);
807 * Init valuators for device, use x/y coordinates.
810 _init_axes(DeviceIntPtr device
)
812 InputInfoPtr pInfo
= device
->public.devicePrivate
;
814 const int num_axes
= 5;
817 atoms
= xcalloc(num_axes
, sizeof(Atom
));
820 if (!InitValuatorClassDeviceStruct(device
,
822 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
825 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) < 3
828 GetMotionHistorySize(),
833 for (i
= 0; i
< 2; i
++)
835 xf86InitValuatorAxisStruct(device
, i
,
836 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
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
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
))
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
871 _hal_create_devices(InputInfoPtr pInfo
, int num
) {
872 TuioDevicePtr pTuio
= pInfo
->private;
874 DBusConnection
*conn
;
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
);
892 if ((ctx
= libhal_ctx_new()) == NULL
) {
893 xf86Msg(X_ERROR
, "%s: Failed to obtain hal context\n",
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
);
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
);
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
);
926 dbus_error_init(&error
);
927 libhal_device_set_property_bool(ctx
, newdev
, "RequireEnable",
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
);
935 dbus_error_init(&error
);
936 libhal_device_set_property_string(ctx
, newdev
,
937 "input.x11_driver", "tuio",
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
);
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",
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
);
957 asprintf(&name
, "%s subdev %i", pInfo
->name
, pTuio
->num_subdev
);
960 dbus_error_init(&error
);
961 libhal_device_set_property_string(ctx
, newdev
,
962 "info.product", name
,
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
);
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
);
983 if (!libhal_ctx_shutdown(ctx
, &error
)) {
984 xf86Msg(X_ERROR
, "%s: Unable to shutdown hal context: %s\n",
985 pInfo
->name
, error
.message
);
988 libhal_ctx_free(ctx
);
994 _hal_remove_device(InputInfoPtr pInfo
) {
996 DBusConnection
*conn
;
1001 xf86Msg(X_INFO
, "%s: Removing subdevice\n",
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
);
1012 if ((ctx
= libhal_ctx_new()) == NULL
) {
1013 xf86Msg(X_ERROR
, "%s: Failed to obtain hal context\n",
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
);
1026 devices
= libhal_manager_find_device_string_match(ctx
, "info.product",
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
);
1036 if (num_devices
== 0) {
1037 xf86Msg(X_ERROR
, "%s: Unable to find subdevice in HAL GDL\n",
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
);
1055 libhal_ctx_free(ctx
);