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 #include <dix-config.h>
35 #include <X11/X.h> /* for inputstr.h */
36 #include <X11/Xproto.h> /* Request macro */
37 #include <X11/extensions/XI.h>
38 #include <X11/extensions/XI2proto.h>
39 #include <X11/extensions/geproto.h>
41 #include "dix/dix_priv.h"
42 #include "dix/exevents_priv.h"
43 #include "dix/input_priv.h"
45 #include "inputstr.h" /* DeviceIntPtr */
46 #include "windowstr.h" /* window structure */
47 #include "scrnintstr.h" /* screen structure */
48 #include "extnsionst.h"
49 #include "exglobals.h"
53 #include "xiquerydevice.h" /* for GetDeviceUse */
55 #include "xichangehierarchy.h"
56 #include "xibarriers.h"
59 * Send the current state of the device hierarchy to all clients.
62 XISendDeviceHierarchyEvent(int flags
[MAXDEVICES
])
64 xXIHierarchyEvent
*ev
;
65 xXIHierarchyInfo
*info
;
66 DeviceIntRec dummyDev
;
73 ev
= calloc(1, sizeof(xXIHierarchyEvent
) +
74 MAXDEVICES
* sizeof(xXIHierarchyInfo
));
77 ev
->type
= GenericEvent
;
78 ev
->extension
= IReqCode
;
79 ev
->evtype
= XI_HierarchyChanged
;
80 ev
->time
= GetTimeInMillis();
82 ev
->num_info
= inputInfo
.numDevices
;
84 info
= (xXIHierarchyInfo
*) &ev
[1];
85 for (dev
= inputInfo
.devices
; dev
; dev
= dev
->next
) {
86 info
->deviceid
= dev
->id
;
87 info
->enabled
= dev
->enabled
;
88 info
->use
= GetDeviceUse(dev
, &info
->attachment
);
89 info
->flags
= flags
[dev
->id
];
90 ev
->flags
|= info
->flags
;
93 for (dev
= inputInfo
.off_devices
; dev
; dev
= dev
->next
) {
94 info
->deviceid
= dev
->id
;
95 info
->enabled
= dev
->enabled
;
96 info
->use
= GetDeviceUse(dev
, &info
->attachment
);
97 info
->flags
= flags
[dev
->id
];
98 ev
->flags
|= info
->flags
;
102 for (i
= 0; i
< MAXDEVICES
; i
++) {
103 if (flags
[i
] & (XIMasterRemoved
| XISlaveRemoved
)) {
105 info
->enabled
= FALSE
;
106 info
->flags
= flags
[i
];
108 ev
->flags
|= info
->flags
;
114 ev
->length
= bytes_to_int32(ev
->num_info
* sizeof(xXIHierarchyInfo
));
116 memset(&dummyDev
, 0, sizeof(dummyDev
));
117 dummyDev
.id
= XIAllDevices
;
118 dummyDev
.type
= SLAVE
;
119 SendEventToAllWindows(&dummyDev
, (XI_HierarchyChangedMask
>> 8),
124 /***********************************************************************
126 * This procedure allows a client to change the device hierarchy through
127 * adding new master devices, removing them, etc.
132 SProcXIChangeHierarchy(ClientPtr client
)
134 REQUEST(xXIChangeHierarchyReq
);
135 swaps(&stuff
->length
);
136 return (ProcXIChangeHierarchy(client
));
140 add_master(ClientPtr client
, xXIAddMasterInfo
* c
, int flags
[MAXDEVICES
])
142 DeviceIntPtr ptr
, keybd
, XTestptr
, XTestkeybd
;
146 name
= calloc(c
->name_len
+ 1, sizeof(char));
151 strncpy(name
, (char *) &c
[1], c
->name_len
);
153 rc
= AllocDevicePair(client
, name
, &ptr
, &keybd
,
154 CorePointerProc
, CoreKeyboardProc
, TRUE
);
159 ptr
->coreEvents
= keybd
->coreEvents
= FALSE
;
161 /* Allocate virtual slave devices for xtest events */
162 rc
= AllocXTestDevice(client
, name
, &XTestptr
, &XTestkeybd
, ptr
, keybd
);
164 DeleteInputDeviceRequest(ptr
);
165 DeleteInputDeviceRequest(keybd
);
169 ActivateDevice(ptr
, FALSE
);
170 ActivateDevice(keybd
, FALSE
);
171 flags
[ptr
->id
] |= XIMasterAdded
;
172 flags
[keybd
->id
] |= XIMasterAdded
;
174 ActivateDevice(XTestptr
, FALSE
);
175 ActivateDevice(XTestkeybd
, FALSE
);
176 flags
[XTestptr
->id
] |= XISlaveAdded
;
177 flags
[XTestkeybd
->id
] |= XISlaveAdded
;
180 EnableDevice(ptr
, FALSE
);
181 EnableDevice(keybd
, FALSE
);
182 flags
[ptr
->id
] |= XIDeviceEnabled
;
183 flags
[keybd
->id
] |= XIDeviceEnabled
;
185 EnableDevice(XTestptr
, FALSE
);
186 EnableDevice(XTestkeybd
, FALSE
);
187 flags
[XTestptr
->id
] |= XIDeviceEnabled
;
188 flags
[XTestkeybd
->id
] |= XIDeviceEnabled
;
191 /* Attach the XTest virtual devices to the newly
192 created master device */
193 AttachDevice(NULL
, XTestptr
, ptr
);
194 AttachDevice(NULL
, XTestkeybd
, keybd
);
195 flags
[XTestptr
->id
] |= XISlaveAttached
;
196 flags
[XTestkeybd
->id
] |= XISlaveAttached
;
198 for (int i
= 0; i
< currentMaxClients
; i
++)
199 XIBarrierNewMasterDevice(clients
[i
], ptr
->id
);
207 disable_clientpointer(DeviceIntPtr dev
)
211 for (i
= 0; i
< currentMaxClients
; i
++) {
212 ClientPtr client
= clients
[i
];
214 if (client
&& client
->clientPtr
== dev
)
215 client
->clientPtr
= NULL
;
220 find_disabled_master(int type
)
224 /* Once a master device is disabled it loses the pairing, so returning the first
225 * match is good enough */
226 for (dev
= inputInfo
.off_devices
; dev
; dev
= dev
->next
) {
227 if (dev
->type
== type
)
235 remove_master(ClientPtr client
, xXIRemoveMasterInfo
* r
, int flags
[MAXDEVICES
])
237 DeviceIntPtr dev
, ptr
, keybd
, XTestptr
, XTestkeybd
;
240 if (r
->return_mode
!= XIAttachToMaster
&& r
->return_mode
!= XIFloating
)
243 rc
= dixLookupDevice(&dev
, r
->deviceid
, client
, DixDestroyAccess
);
247 if (!IsMaster(dev
)) {
248 client
->errorValue
= r
->deviceid
;
253 /* XXX: For now, don't allow removal of VCP, VCK */
254 if (dev
== inputInfo
.pointer
|| dev
== inputInfo
.keyboard
) {
259 if ((ptr
= GetMaster(dev
, MASTER_POINTER
)) == NULL
)
260 ptr
= find_disabled_master(MASTER_POINTER
);
261 BUG_RETURN_VAL(ptr
== NULL
, BadDevice
);
262 rc
= dixLookupDevice(&ptr
, ptr
->id
, client
, DixDestroyAccess
);
266 if ((keybd
= GetMaster(dev
, MASTER_KEYBOARD
)) == NULL
)
267 keybd
= find_disabled_master(MASTER_KEYBOARD
);
268 BUG_RETURN_VAL(keybd
== NULL
, BadDevice
);
269 rc
= dixLookupDevice(&keybd
, keybd
->id
, client
, DixDestroyAccess
);
273 XTestptr
= GetXTestDevice(ptr
);
274 BUG_RETURN_VAL(XTestptr
== NULL
, BadDevice
);
275 rc
= dixLookupDevice(&XTestptr
, XTestptr
->id
, client
, DixDestroyAccess
);
279 XTestkeybd
= GetXTestDevice(keybd
);
280 BUG_RETURN_VAL(XTestkeybd
== NULL
, BadDevice
);
281 rc
= dixLookupDevice(&XTestkeybd
, XTestkeybd
->id
, client
, DixDestroyAccess
);
285 disable_clientpointer(ptr
);
287 /* Disabling sends the devices floating, reattach them if
289 if (r
->return_mode
== XIAttachToMaster
) {
290 DeviceIntPtr attached
, newptr
, newkeybd
;
292 rc
= dixLookupDevice(&newptr
, r
->return_pointer
, client
, DixAddAccess
);
296 if (!IsMaster(newptr
) || !IsPointerDevice(newptr
)) {
297 client
->errorValue
= r
->return_pointer
;
302 rc
= dixLookupDevice(&newkeybd
, r
->return_keyboard
,
303 client
, DixAddAccess
);
307 if (!IsMaster(newkeybd
) || !IsKeyboardDevice(newkeybd
)) {
308 client
->errorValue
= r
->return_keyboard
;
313 for (attached
= inputInfo
.devices
; attached
; attached
= attached
->next
) {
314 if (!IsMaster(attached
)) {
315 if (GetMaster(attached
, MASTER_ATTACHED
) == ptr
) {
316 AttachDevice(client
, attached
, newptr
);
317 flags
[attached
->id
] |= XISlaveAttached
;
319 if (GetMaster(attached
, MASTER_ATTACHED
) == keybd
) {
320 AttachDevice(client
, attached
, newkeybd
);
321 flags
[attached
->id
] |= XISlaveAttached
;
327 for (int i
= 0; i
< currentMaxClients
; i
++)
328 XIBarrierRemoveMasterDevice(clients
[i
], ptr
->id
);
330 /* disable the remove the devices, XTest devices must be done first
331 else the sprites they rely on will be destroyed */
332 DisableDevice(XTestptr
, FALSE
);
333 DisableDevice(XTestkeybd
, FALSE
);
334 DisableDevice(keybd
, FALSE
);
335 DisableDevice(ptr
, FALSE
);
336 flags
[XTestptr
->id
] |= XIDeviceDisabled
| XISlaveDetached
;
337 flags
[XTestkeybd
->id
] |= XIDeviceDisabled
| XISlaveDetached
;
338 flags
[keybd
->id
] |= XIDeviceDisabled
;
339 flags
[ptr
->id
] |= XIDeviceDisabled
;
341 flags
[XTestptr
->id
] |= XISlaveRemoved
;
342 flags
[XTestkeybd
->id
] |= XISlaveRemoved
;
343 flags
[keybd
->id
] |= XIMasterRemoved
;
344 flags
[ptr
->id
] |= XIMasterRemoved
;
346 RemoveDevice(XTestptr
, FALSE
);
347 RemoveDevice(XTestkeybd
, FALSE
);
348 RemoveDevice(keybd
, FALSE
);
349 RemoveDevice(ptr
, FALSE
);
356 detach_slave(ClientPtr client
, xXIDetachSlaveInfo
* c
, int flags
[MAXDEVICES
])
361 rc
= dixLookupDevice(&dev
, c
->deviceid
, client
, DixManageAccess
);
366 client
->errorValue
= c
->deviceid
;
371 /* Don't allow changes to XTest Devices, these are fixed */
372 if (IsXTestDevice(dev
, NULL
)) {
373 client
->errorValue
= c
->deviceid
;
378 ReleaseButtonsAndKeys(dev
);
379 AttachDevice(client
, dev
, NULL
);
380 flags
[dev
->id
] |= XISlaveDetached
;
387 attach_slave(ClientPtr client
, xXIAttachSlaveInfo
* c
, int flags
[MAXDEVICES
])
390 DeviceIntPtr newmaster
;
393 rc
= dixLookupDevice(&dev
, c
->deviceid
, client
, DixManageAccess
);
398 client
->errorValue
= c
->deviceid
;
403 /* Don't allow changes to XTest Devices, these are fixed */
404 if (IsXTestDevice(dev
, NULL
)) {
405 client
->errorValue
= c
->deviceid
;
410 rc
= dixLookupDevice(&newmaster
, c
->new_master
, client
, DixAddAccess
);
413 if (!IsMaster(newmaster
)) {
414 client
->errorValue
= c
->new_master
;
419 if (!((IsPointerDevice(newmaster
) && IsPointerDevice(dev
)) ||
420 (IsKeyboardDevice(newmaster
) && IsKeyboardDevice(dev
)))) {
425 ReleaseButtonsAndKeys(dev
);
426 AttachDevice(client
, dev
, newmaster
);
427 flags
[dev
->id
] |= XISlaveAttached
;
433 #define SWAPIF(cmd) if (client->swapped) { cmd; }
436 ProcXIChangeHierarchy(ClientPtr client
)
438 xXIAnyHierarchyChangeInfo
*any
;
439 size_t len
; /* length of data remaining in request */
441 int flags
[MAXDEVICES
] = { 0 };
446 } changes
= NO_CHANGE
;
448 REQUEST(xXIChangeHierarchyReq
);
449 REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq
);
451 if (!stuff
->num_changes
)
454 len
= ((size_t)client
->req_len
<< 2) - sizeof(xXIChangeHierarchyReq
);
456 any
= (xXIAnyHierarchyChangeInfo
*) &stuff
[1];
457 while (stuff
->num_changes
--) {
458 if (len
< sizeof(xXIAnyHierarchyChangeInfo
)) {
463 SWAPIF(swaps(&any
->type
));
464 SWAPIF(swaps(&any
->length
));
466 if (len
< ((size_t)any
->length
<< 2))
469 #define CHANGE_SIZE_MATCH(type) \
471 if ((len < sizeof(type)) || (any->length != (sizeof(type) >> 2))) { \
480 xXIAddMasterInfo
*c
= (xXIAddMasterInfo
*) any
;
482 /* Variable length, due to appended name string */
483 if (len
< sizeof(xXIAddMasterInfo
)) {
487 SWAPIF(swaps(&c
->name_len
));
488 if (c
->name_len
> (len
- sizeof(xXIAddMasterInfo
))) {
493 rc
= add_master(client
, c
, flags
);
501 xXIRemoveMasterInfo
*r
= (xXIRemoveMasterInfo
*) any
;
503 CHANGE_SIZE_MATCH(xXIRemoveMasterInfo
);
504 rc
= remove_master(client
, r
, flags
);
512 xXIDetachSlaveInfo
*c
= (xXIDetachSlaveInfo
*) any
;
514 CHANGE_SIZE_MATCH(xXIDetachSlaveInfo
);
515 rc
= detach_slave(client
, c
, flags
);
523 xXIAttachSlaveInfo
*c
= (xXIAttachSlaveInfo
*) any
;
525 CHANGE_SIZE_MATCH(xXIAttachSlaveInfo
);
526 rc
= attach_slave(client
, c
, flags
);
536 if (changes
== FLUSH
) {
537 XISendDeviceHierarchyEvent(flags
);
538 memset(flags
, 0, sizeof(flags
));
542 len
-= any
->length
* 4;
543 any
= (xXIAnyHierarchyChangeInfo
*) ((char *) any
+ any
->length
* 4);
547 if (changes
!= NO_CHANGE
)
548 XISendDeviceHierarchyEvent(flags
);