7 #include <X11/extensions/XInput2.h>
10 #define MD_PREFIX "TUIO "
11 #define PDEBUG(msg, ...) if(debug) printf("TMD: "msg,##__VA_ARGS__);
13 typedef struct _attach_info
{
14 struct _attach_info
*next
;
19 } AttachInfo
, *AttachInfoPtr
;
21 /* Attach Info "root" node */
22 static AttachInfo ais
;
25 static int foreground
= 1;
28 * Removes a master device.
30 int remove_master(Display
* dpy
, int master_id
) {
33 c
.type
= XIRemoveMaster
;
34 c
.deviceid
= master_id
;
35 c
.return_mode
= XIFloating
;
37 return XIChangeHierarchy(dpy
, (XIAnyHierarchyChangeInfo
*)&c
, 1);
41 * Creates a new master device.
43 int create_master(Display
* dpy
, char* name
) {
51 return XIChangeHierarchy(dpy
, (XIAnyHierarchyChangeInfo
*)&c
, 1);
55 * Attaches a slave device to a master device.
57 int change_attachment(Display
* dpy
, int slaveid
, int masterid
) {
60 c
.type
= XIAttachSlave
;
62 c
.new_master
= masterid
;
64 return XIChangeHierarchy(dpy
, (XIAnyHierarchyChangeInfo
*)&c
, 1);
68 * Listens for the creation of slave and master devices. When a new slave
69 * device is found, a new master device will be created and attached to
70 * when the message for the new master device comes back around.
72 void listen(Display
*dpy
, int xi_opcode
) {
74 unsigned char hmask
[2] = { 0, 0 };
75 char *m_name
, *s_name
;
82 //m_cur = XCreateFontCursor(dpy, 88);
83 //if (m_cur == BadAlloc || m_cur == BadValue) {
84 //printf("Unable to create cursor\n");
87 evmask_h
.mask
= hmask
;
88 evmask_h
.mask_len
= sizeof(hmask
);
89 evmask_h
.deviceid
= XIAllDevices
;
90 XISetMask(hmask
, XI_HierarchyChanged
);
93 XISelectEvents(dpy
, DefaultRootWindow(dpy
), &evmask_h
, 1);
95 PDEBUG("Listening for events...\n");
97 /* Start listening for events... */
99 XGenericEventCookie
*cookie
;
100 cookie
= &ev
.xcookie
;
101 XNextEvent(dpy
, &ev
);
103 if (!XGetEventData(dpy
, &ev
))
106 PDEBUG("Event Received\n");
108 if (cookie
->type
!= GenericEvent
||
109 cookie
->extension
!= xi_opcode
)
112 if (cookie
->evtype
== XI_HierarchyChanged
) {
114 XIHierarchyEvent
*event
= cookie
->data
;
116 if (event
->flags
& XISlaveAdded
) {
117 PDEBUG(" Slave added\n");
119 for (i
=0; i
< event
->num_info
; i
++) {
120 if (event
->info
[i
].flags
& XISlaveAdded
) {
121 info
= XIQueryDevice(dpy
, event
->info
[i
].deviceid
, &num_devices
);
122 if (num_devices
!= 1) {
123 PDEBUG(" Couldn't find slave device (XIQueryDevice)\n");
124 XIFreeDeviceInfo(info
);
129 PDEBUG(" Found: %s\n", s_name
);
131 /* This is a hack. XTEST slave devices are created and
132 * attached to each new master device within X. If we
133 * were to actually create a new master device for this
134 * device we would end up with a recurring creation of
135 * master devices and slave devices. Also, tuio subdevices
136 * will have the word "subdev" in them. */
137 if (strstr(s_name
, "XTEST") ||
138 !strstr(s_name
, "subdev")) {
139 PDEBUG(" Device is NOT a tuio subdevice\n");
140 XIFreeDeviceInfo(info
);
143 PDEBUG(" Device is a tuio subdevice, "
144 "creating Master Device\n");
147 asprintf(&m_name
, MD_PREFIX
"%s", s_name
);
148 create_master(dpy
, m_name
);
151 ai
= malloc(sizeof(AttachInfo
));
155 /* The new pointer will have the suffix " pointer" */
156 asprintf(&ai
->m_name
, MD_PREFIX
"%s pointer", s_name
);
157 ai
->slaveid
= event
->info
[i
].deviceid
;
158 XIFreeDeviceInfo(info
);
163 if (event
->flags
& XIMasterAdded
) {
164 PDEBUG(" Master added\n");
166 for (i
=0; i
< event
->num_info
; i
++) {
167 if(event
->info
[i
].flags
& XIMasterAdded
) {
169 info
= XIQueryDevice(dpy
, event
->info
[i
].deviceid
, &num_devices
);
170 if (num_devices
!= 1) {
171 PDEBUG(" Couldn't find master device (XIQueryDevice)\n");
172 XIFreeDeviceInfo(info
);
177 PDEBUG(" Found: %s, reattaching\n", m_name
);
181 if (strcmp(ai
->m_name
, m_name
) == 0) {
182 PDEBUG(" New master found in internal list\n");
183 change_attachment(dpy
, ai
->slaveid
, event
->info
[i
].deviceid
);
184 ai
->masterid
= event
->info
[i
].deviceid
;
185 //XIDefineCursor(dpy, event->info[i].deviceid,
186 //DefaultRootWindow(dpy), m_cur);
190 XIFreeDeviceInfo(info
);
195 if (event
->flags
& XISlaveRemoved
) {
196 PDEBUG(" Slave removed\n");
197 for (i
=0; i
< event
->num_info
; i
++) {
198 if(event
->info
[i
].flags
& XISlaveRemoved
) {
205 if (ai
->slaveid
== event
->info
[i
].deviceid
) {
207 /* Remove corresponding master device */
209 PDEBUG(" Removing Master: %d\n", m_id
);
210 remove_master(dpy
, m_id
);
212 ai_last
->next
= ai
->next
;
224 XFreeEventData(dpy
, &ev
);
229 * Forks the process sets
236 printf("Failed to fork\n");
238 } else if (pid
> 0) {
244 if ((chdir("/")) < 0) {
248 freopen( "/dev/null", "r", stdin
);
249 freopen( "/dev/null", "w", stdout
);
250 freopen( "/dev/null", "w", stderr
);
254 * Prints help information.
256 void printHelp(char* bin_name
) {
257 printf("Usage: %s [OPTION...]\n\n", bin_name
);
258 printf(" -d\tenables debugging output\n");
259 printf(" -f\truns process in foreground\n");
260 printf(" -h\tprints this help message\n");
264 * Processes application arguments.
266 void processArgs(int argc
, char **argv
) {
269 for (i
=1; i
<argc
; i
++) {
270 if (strcmp(argv
[i
], "-d") == 0) {
272 PDEBUG("Debug on\n");
273 } else if (strcmp(argv
[i
], "-f") == 0) {
275 } else if (strcmp(argv
[i
], "-h") == 0) {
278 } else if (strcmp(argv
[i
], "-v") == 0) {
279 printf("Version "VERSION
"\n");
285 int main (int argc
, char **argv
) {
287 int xi_opcode
, event
, error
;
293 processArgs(argc
, argv
);
297 PDEBUG("Connecting to X\n");
299 dpy
= XOpenDisplay(NULL
);
301 printf("Failed to open display.\n");
305 /* Make sure the X Input extension is available */
306 if (!XQueryExtension(dpy
, "XInputExtension", &xi_opcode
, &event
, &error
)) {
307 printf("X Input extension not available.\nExiting\n");
311 /* Check XI version, need 2.0 */
314 ret
= XIQueryVersion(dpy
, &major
, &minor
);
315 if (ret
== BadRequest
) {
316 printf("XInput 2.0 not supported. Server supports %i.%i.\nExiting\n", major
, minor
);
320 listen(dpy
, xi_opcode
);