2 * Copyright 2007-2008 Peter Hutterer
3 * Copyright 2009 Red Hat, Inc.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
24 * Author: Peter Hutterer, University of South Australia, NICTA
27 /***********************************************************************
29 * Request change in the device hierarchy.
33 #ifdef HAVE_DIX_CONFIG_H
34 #include <dix-config.h>
37 #include <X11/X.h> /* for inputstr.h */
38 #include <X11/Xproto.h> /* Request macro */
39 #include "inputstr.h" /* DeviceIntPtr */
40 #include "windowstr.h" /* window structure */
41 #include "scrnintstr.h" /* screen structure */
42 #include <X11/extensions/XI.h>
43 #include <X11/extensions/XI2proto.h>
44 #include <X11/extensions/geproto.h>
45 #include "extnsionst.h"
47 #include "exglobals.h"
50 #include "xiquerydevice.h" /* for GetDeviceUse */
54 #include "xichangehierarchy.h"
55 #include "xibarriers.h"
58 * Send the current state of the device hierarchy to all clients.
61 XISendDeviceHierarchyEvent(int flags
[MAXDEVICES
])
63 xXIHierarchyEvent
*ev
;
64 xXIHierarchyInfo
*info
;
65 DeviceIntRec dummyDev
;
72 ev
= calloc(1, sizeof(xXIHierarchyEvent
) +
73 MAXDEVICES
* sizeof(xXIHierarchyInfo
));
76 ev
->type
= GenericEvent
;
77 ev
->extension
= IReqCode
;
78 ev
->evtype
= XI_HierarchyChanged
;
79 ev
->time
= GetTimeInMillis();
81 ev
->num_info
= inputInfo
.numDevices
;
83 info
= (xXIHierarchyInfo
*) &ev
[1];
84 for (dev
= inputInfo
.devices
; dev
; dev
= dev
->next
) {
85 info
->deviceid
= dev
->id
;
86 info
->enabled
= dev
->enabled
;
87 info
->use
= GetDeviceUse(dev
, &info
->attachment
);
88 info
->flags
= flags
[dev
->id
];
89 ev
->flags
|= info
->flags
;
92 for (dev
= inputInfo
.off_devices
; dev
; dev
= dev
->next
) {
93 info
->deviceid
= dev
->id
;
94 info
->enabled
= dev
->enabled
;
95 info
->use
= GetDeviceUse(dev
, &info
->attachment
);
96 info
->flags
= flags
[dev
->id
];
97 ev
->flags
|= info
->flags
;
101 for (i
= 0; i
< MAXDEVICES
; i
++) {
102 if (flags
[i
] & (XIMasterRemoved
| XISlaveRemoved
)) {
104 info
->enabled
= FALSE
;
105 info
->flags
= flags
[i
];
107 ev
->flags
|= info
->flags
;
113 ev
->length
= bytes_to_int32(ev
->num_info
* sizeof(xXIHierarchyInfo
));
115 memset(&dummyDev
, 0, sizeof(dummyDev
));
116 dummyDev
.id
= XIAllDevices
;
117 dummyDev
.type
= SLAVE
;
118 SendEventToAllWindows(&dummyDev
, (XI_HierarchyChangedMask
>> 8),
123 /***********************************************************************
125 * This procedure allows a client to change the device hierarchy through
126 * adding new master devices, removing them, etc.
131 SProcXIChangeHierarchy(ClientPtr client
)
133 REQUEST(xXIChangeHierarchyReq
);
134 swaps(&stuff
->length
);
135 return (ProcXIChangeHierarchy(client
));
139 add_master(ClientPtr client
, xXIAddMasterInfo
* c
, int flags
[MAXDEVICES
])
141 DeviceIntPtr ptr
, keybd
, XTestptr
, XTestkeybd
;
145 name
= calloc(c
->name_len
+ 1, sizeof(char));
150 strncpy(name
, (char *) &c
[1], c
->name_len
);
152 rc
= AllocDevicePair(client
, name
, &ptr
, &keybd
,
153 CorePointerProc
, CoreKeyboardProc
, TRUE
);
158 ptr
->coreEvents
= keybd
->coreEvents
= FALSE
;
160 /* Allocate virtual slave devices for xtest events */
161 rc
= AllocXTestDevice(client
, name
, &XTestptr
, &XTestkeybd
, ptr
, keybd
);
163 DeleteInputDeviceRequest(ptr
);
164 DeleteInputDeviceRequest(keybd
);
168 ActivateDevice(ptr
, FALSE
);
169 ActivateDevice(keybd
, FALSE
);
170 flags
[ptr
->id
] |= XIMasterAdded
;
171 flags
[keybd
->id
] |= XIMasterAdded
;
173 ActivateDevice(XTestptr
, FALSE
);
174 ActivateDevice(XTestkeybd
, FALSE
);
175 flags
[XTestptr
->id
] |= XISlaveAdded
;
176 flags
[XTestkeybd
->id
] |= XISlaveAdded
;
179 EnableDevice(ptr
, FALSE
);
180 EnableDevice(keybd
, FALSE
);
181 flags
[ptr
->id
] |= XIDeviceEnabled
;
182 flags
[keybd
->id
] |= XIDeviceEnabled
;
184 EnableDevice(XTestptr
, FALSE
);
185 EnableDevice(XTestkeybd
, FALSE
);
186 flags
[XTestptr
->id
] |= XIDeviceEnabled
;
187 flags
[XTestkeybd
->id
] |= XIDeviceEnabled
;
190 /* Attach the XTest virtual devices to the newly
191 created master device */
192 AttachDevice(NULL
, XTestptr
, ptr
);
193 AttachDevice(NULL
, XTestkeybd
, keybd
);
194 flags
[XTestptr
->id
] |= XISlaveAttached
;
195 flags
[XTestkeybd
->id
] |= XISlaveAttached
;
197 XIBarrierNewMasterDevice(client
, ptr
->id
);
205 disable_clientpointer(DeviceIntPtr dev
)
209 for (i
= 0; i
< currentMaxClients
; i
++) {
210 ClientPtr client
= clients
[i
];
212 if (client
&& client
->clientPtr
== dev
)
213 client
->clientPtr
= NULL
;
218 remove_master(ClientPtr client
, xXIRemoveMasterInfo
* r
, int flags
[MAXDEVICES
])
220 DeviceIntPtr ptr
, keybd
, XTestptr
, XTestkeybd
;
223 if (r
->return_mode
!= XIAttachToMaster
&& r
->return_mode
!= XIFloating
)
226 rc
= dixLookupDevice(&ptr
, r
->deviceid
, client
, DixDestroyAccess
);
230 if (!IsMaster(ptr
)) {
231 client
->errorValue
= r
->deviceid
;
236 /* XXX: For now, don't allow removal of VCP, VCK */
237 if (ptr
== inputInfo
.pointer
||ptr
== inputInfo
.keyboard
) {
242 ptr
= GetMaster(ptr
, MASTER_POINTER
);
243 rc
= dixLookupDevice(&ptr
, ptr
->id
, client
, DixDestroyAccess
);
246 keybd
= GetMaster(ptr
, MASTER_KEYBOARD
);
247 rc
= dixLookupDevice(&keybd
, keybd
->id
, client
, DixDestroyAccess
);
251 XTestptr
= GetXTestDevice(ptr
);
252 rc
= dixLookupDevice(&XTestptr
, XTestptr
->id
, client
, DixDestroyAccess
);
256 XTestkeybd
= GetXTestDevice(keybd
);
257 rc
= dixLookupDevice(&XTestkeybd
, XTestkeybd
->id
, client
, DixDestroyAccess
);
261 disable_clientpointer(ptr
);
263 /* Disabling sends the devices floating, reattach them if
265 if (r
->return_mode
== XIAttachToMaster
) {
266 DeviceIntPtr attached
, newptr
, newkeybd
;
268 rc
= dixLookupDevice(&newptr
, r
->return_pointer
, client
, DixAddAccess
);
272 if (!IsMaster(newptr
)) {
273 client
->errorValue
= r
->return_pointer
;
278 rc
= dixLookupDevice(&newkeybd
, r
->return_keyboard
,
279 client
, DixAddAccess
);
283 if (!IsMaster(newkeybd
)) {
284 client
->errorValue
= r
->return_keyboard
;
289 for (attached
= inputInfo
.devices
; attached
; attached
= attached
->next
) {
290 if (!IsMaster(attached
)) {
291 if (GetMaster(attached
, MASTER_ATTACHED
) == ptr
) {
292 AttachDevice(client
, attached
, newptr
);
293 flags
[attached
->id
] |= XISlaveAttached
;
295 if (GetMaster(attached
, MASTER_ATTACHED
) == keybd
) {
296 AttachDevice(client
, attached
, newkeybd
);
297 flags
[attached
->id
] |= XISlaveAttached
;
303 XIBarrierRemoveMasterDevice(client
, ptr
->id
);
305 /* disable the remove the devices, XTest devices must be done first
306 else the sprites they rely on will be destroyed */
307 DisableDevice(XTestptr
, FALSE
);
308 DisableDevice(XTestkeybd
, FALSE
);
309 DisableDevice(keybd
, FALSE
);
310 DisableDevice(ptr
, FALSE
);
311 flags
[XTestptr
->id
] |= XIDeviceDisabled
| XISlaveDetached
;
312 flags
[XTestkeybd
->id
] |= XIDeviceDisabled
| XISlaveDetached
;
313 flags
[keybd
->id
] |= XIDeviceDisabled
;
314 flags
[ptr
->id
] |= XIDeviceDisabled
;
316 flags
[XTestptr
->id
] |= XISlaveRemoved
;
317 flags
[XTestkeybd
->id
] |= XISlaveRemoved
;
318 flags
[keybd
->id
] |= XIMasterRemoved
;
319 flags
[ptr
->id
] |= XIMasterRemoved
;
321 RemoveDevice(XTestptr
, FALSE
);
322 RemoveDevice(XTestkeybd
, FALSE
);
323 RemoveDevice(keybd
, FALSE
);
324 RemoveDevice(ptr
, FALSE
);
331 detach_slave(ClientPtr client
, xXIDetachSlaveInfo
* c
, int flags
[MAXDEVICES
])
336 rc
= dixLookupDevice(&dev
, c
->deviceid
, client
, DixManageAccess
);
341 client
->errorValue
= c
->deviceid
;
346 /* Don't allow changes to XTest Devices, these are fixed */
347 if (IsXTestDevice(dev
, NULL
)) {
348 client
->errorValue
= c
->deviceid
;
353 ReleaseButtonsAndKeys(dev
);
354 AttachDevice(client
, dev
, NULL
);
355 flags
[dev
->id
] |= XISlaveDetached
;
362 attach_slave(ClientPtr client
, xXIAttachSlaveInfo
* c
, int flags
[MAXDEVICES
])
365 DeviceIntPtr newmaster
;
368 rc
= dixLookupDevice(&dev
, c
->deviceid
, client
, DixManageAccess
);
373 client
->errorValue
= c
->deviceid
;
378 /* Don't allow changes to XTest Devices, these are fixed */
379 if (IsXTestDevice(dev
, NULL
)) {
380 client
->errorValue
= c
->deviceid
;
385 rc
= dixLookupDevice(&newmaster
, c
->new_master
, client
, DixAddAccess
);
388 if (!IsMaster(newmaster
)) {
389 client
->errorValue
= c
->new_master
;
394 if (!((IsPointerDevice(newmaster
) && IsPointerDevice(dev
)) ||
395 (IsKeyboardDevice(newmaster
) && IsKeyboardDevice(dev
)))) {
400 ReleaseButtonsAndKeys(dev
);
401 AttachDevice(client
, dev
, newmaster
);
402 flags
[dev
->id
] |= XISlaveAttached
;
408 #define SWAPIF(cmd) if (client->swapped) { cmd; }
411 ProcXIChangeHierarchy(ClientPtr client
)
413 xXIAnyHierarchyChangeInfo
*any
;
414 int required_len
= sizeof(xXIChangeHierarchyReq
);
416 int flags
[MAXDEVICES
] = { 0 };
418 REQUEST(xXIChangeHierarchyReq
);
419 REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq
);
421 if (!stuff
->num_changes
)
424 any
= (xXIAnyHierarchyChangeInfo
*) &stuff
[1];
425 while (stuff
->num_changes
--) {
426 SWAPIF(swaps(&any
->type
));
427 SWAPIF(swaps(&any
->length
));
429 required_len
+= any
->length
;
430 if ((stuff
->length
* 4) < required_len
)
436 xXIAddMasterInfo
*c
= (xXIAddMasterInfo
*) any
;
438 SWAPIF(swaps(&c
->name_len
));
440 rc
= add_master(client
, c
, flags
);
447 xXIRemoveMasterInfo
*r
= (xXIRemoveMasterInfo
*) any
;
449 rc
= remove_master(client
, r
, flags
);
456 xXIDetachSlaveInfo
*c
= (xXIDetachSlaveInfo
*) any
;
458 rc
= detach_slave(client
, c
, flags
);
465 xXIAttachSlaveInfo
*c
= (xXIAttachSlaveInfo
*) any
;
467 rc
= attach_slave(client
, c
, flags
);
474 any
= (xXIAnyHierarchyChangeInfo
*) ((char *) any
+ any
->length
* 4);
479 XISendDeviceHierarchyEvent(flags
);