1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright 2007-2008 Peter Hutterer
3*4882a593Smuzhiyun * Copyright 2009 Red Hat, Inc.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person obtaining a
6*4882a593Smuzhiyun * copy of this software and associated documentation files (the "Software"),
7*4882a593Smuzhiyun * to deal in the Software without restriction, including without limitation
8*4882a593Smuzhiyun * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*4882a593Smuzhiyun * and/or sell copies of the Software, and to permit persons to whom the
10*4882a593Smuzhiyun * Software is furnished to do so, subject to the following conditions:
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * The above copyright notice and this permission notice (including the next
13*4882a593Smuzhiyun * paragraph) shall be included in all copies or substantial portions of the
14*4882a593Smuzhiyun * Software.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*4882a593Smuzhiyun * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19*4882a593Smuzhiyun * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*4882a593Smuzhiyun * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21*4882a593Smuzhiyun * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22*4882a593Smuzhiyun * DEALINGS IN THE SOFTWARE.
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * Author: Peter Hutterer, University of South Australia, NICTA
25*4882a593Smuzhiyun */
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /***********************************************************************
28*4882a593Smuzhiyun *
29*4882a593Smuzhiyun * Request change in the device hierarchy.
30*4882a593Smuzhiyun *
31*4882a593Smuzhiyun */
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
34*4882a593Smuzhiyun #include <dix-config.h>
35*4882a593Smuzhiyun #endif
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #include <X11/X.h> /* for inputstr.h */
38*4882a593Smuzhiyun #include <X11/Xproto.h> /* Request macro */
39*4882a593Smuzhiyun #include "inputstr.h" /* DeviceIntPtr */
40*4882a593Smuzhiyun #include "windowstr.h" /* window structure */
41*4882a593Smuzhiyun #include "scrnintstr.h" /* screen structure */
42*4882a593Smuzhiyun #include <X11/extensions/XI.h>
43*4882a593Smuzhiyun #include <X11/extensions/XI2proto.h>
44*4882a593Smuzhiyun #include <X11/extensions/geproto.h>
45*4882a593Smuzhiyun #include "extnsionst.h"
46*4882a593Smuzhiyun #include "exevents.h"
47*4882a593Smuzhiyun #include "exglobals.h"
48*4882a593Smuzhiyun #include "geext.h"
49*4882a593Smuzhiyun #include "xace.h"
50*4882a593Smuzhiyun #include "xiquerydevice.h" /* for GetDeviceUse */
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #include "xkbsrv.h"
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun #include "xichangehierarchy.h"
55*4882a593Smuzhiyun #include "xibarriers.h"
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /**
58*4882a593Smuzhiyun * Send the current state of the device hierarchy to all clients.
59*4882a593Smuzhiyun */
60*4882a593Smuzhiyun void
XISendDeviceHierarchyEvent(int flags[MAXDEVICES])61*4882a593Smuzhiyun XISendDeviceHierarchyEvent(int flags[MAXDEVICES])
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun xXIHierarchyEvent *ev;
64*4882a593Smuzhiyun xXIHierarchyInfo *info;
65*4882a593Smuzhiyun DeviceIntRec dummyDev;
66*4882a593Smuzhiyun DeviceIntPtr dev;
67*4882a593Smuzhiyun int i;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun if (!flags)
70*4882a593Smuzhiyun return;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun ev = calloc(1, sizeof(xXIHierarchyEvent) +
73*4882a593Smuzhiyun MAXDEVICES * sizeof(xXIHierarchyInfo));
74*4882a593Smuzhiyun if (!ev)
75*4882a593Smuzhiyun return;
76*4882a593Smuzhiyun ev->type = GenericEvent;
77*4882a593Smuzhiyun ev->extension = IReqCode;
78*4882a593Smuzhiyun ev->evtype = XI_HierarchyChanged;
79*4882a593Smuzhiyun ev->time = GetTimeInMillis();
80*4882a593Smuzhiyun ev->flags = 0;
81*4882a593Smuzhiyun ev->num_info = inputInfo.numDevices;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun info = (xXIHierarchyInfo *) &ev[1];
84*4882a593Smuzhiyun for (dev = inputInfo.devices; dev; dev = dev->next) {
85*4882a593Smuzhiyun info->deviceid = dev->id;
86*4882a593Smuzhiyun info->enabled = dev->enabled;
87*4882a593Smuzhiyun info->use = GetDeviceUse(dev, &info->attachment);
88*4882a593Smuzhiyun info->flags = flags[dev->id];
89*4882a593Smuzhiyun ev->flags |= info->flags;
90*4882a593Smuzhiyun info++;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun for (dev = inputInfo.off_devices; dev; dev = dev->next) {
93*4882a593Smuzhiyun info->deviceid = dev->id;
94*4882a593Smuzhiyun info->enabled = dev->enabled;
95*4882a593Smuzhiyun info->use = GetDeviceUse(dev, &info->attachment);
96*4882a593Smuzhiyun info->flags = flags[dev->id];
97*4882a593Smuzhiyun ev->flags |= info->flags;
98*4882a593Smuzhiyun info++;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun for (i = 0; i < MAXDEVICES; i++) {
102*4882a593Smuzhiyun if (flags[i] & (XIMasterRemoved | XISlaveRemoved)) {
103*4882a593Smuzhiyun info->deviceid = i;
104*4882a593Smuzhiyun info->enabled = FALSE;
105*4882a593Smuzhiyun info->flags = flags[i];
106*4882a593Smuzhiyun info->use = 0;
107*4882a593Smuzhiyun ev->flags |= info->flags;
108*4882a593Smuzhiyun ev->num_info++;
109*4882a593Smuzhiyun info++;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo));
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun memset(&dummyDev, 0, sizeof(dummyDev));
116*4882a593Smuzhiyun dummyDev.id = XIAllDevices;
117*4882a593Smuzhiyun dummyDev.type = SLAVE;
118*4882a593Smuzhiyun SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8),
119*4882a593Smuzhiyun (xEvent *) ev, 1);
120*4882a593Smuzhiyun free(ev);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun /***********************************************************************
124*4882a593Smuzhiyun *
125*4882a593Smuzhiyun * This procedure allows a client to change the device hierarchy through
126*4882a593Smuzhiyun * adding new master devices, removing them, etc.
127*4882a593Smuzhiyun *
128*4882a593Smuzhiyun */
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun int _X_COLD
SProcXIChangeHierarchy(ClientPtr client)131*4882a593Smuzhiyun SProcXIChangeHierarchy(ClientPtr client)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun REQUEST(xXIChangeHierarchyReq);
134*4882a593Smuzhiyun swaps(&stuff->length);
135*4882a593Smuzhiyun return (ProcXIChangeHierarchy(client));
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun static int
add_master(ClientPtr client,xXIAddMasterInfo * c,int flags[MAXDEVICES])139*4882a593Smuzhiyun add_master(ClientPtr client, xXIAddMasterInfo * c, int flags[MAXDEVICES])
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
142*4882a593Smuzhiyun char *name;
143*4882a593Smuzhiyun int rc;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun name = calloc(c->name_len + 1, sizeof(char));
146*4882a593Smuzhiyun if (name == NULL) {
147*4882a593Smuzhiyun rc = BadAlloc;
148*4882a593Smuzhiyun goto unwind;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun strncpy(name, (char *) &c[1], c->name_len);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun rc = AllocDevicePair(client, name, &ptr, &keybd,
153*4882a593Smuzhiyun CorePointerProc, CoreKeyboardProc, TRUE);
154*4882a593Smuzhiyun if (rc != Success)
155*4882a593Smuzhiyun goto unwind;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun if (!c->send_core)
158*4882a593Smuzhiyun ptr->coreEvents = keybd->coreEvents = FALSE;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* Allocate virtual slave devices for xtest events */
161*4882a593Smuzhiyun rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, ptr, keybd);
162*4882a593Smuzhiyun if (rc != Success) {
163*4882a593Smuzhiyun DeleteInputDeviceRequest(ptr);
164*4882a593Smuzhiyun DeleteInputDeviceRequest(keybd);
165*4882a593Smuzhiyun goto unwind;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun ActivateDevice(ptr, FALSE);
169*4882a593Smuzhiyun ActivateDevice(keybd, FALSE);
170*4882a593Smuzhiyun flags[ptr->id] |= XIMasterAdded;
171*4882a593Smuzhiyun flags[keybd->id] |= XIMasterAdded;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun ActivateDevice(XTestptr, FALSE);
174*4882a593Smuzhiyun ActivateDevice(XTestkeybd, FALSE);
175*4882a593Smuzhiyun flags[XTestptr->id] |= XISlaveAdded;
176*4882a593Smuzhiyun flags[XTestkeybd->id] |= XISlaveAdded;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun if (c->enable) {
179*4882a593Smuzhiyun EnableDevice(ptr, FALSE);
180*4882a593Smuzhiyun EnableDevice(keybd, FALSE);
181*4882a593Smuzhiyun flags[ptr->id] |= XIDeviceEnabled;
182*4882a593Smuzhiyun flags[keybd->id] |= XIDeviceEnabled;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun EnableDevice(XTestptr, FALSE);
185*4882a593Smuzhiyun EnableDevice(XTestkeybd, FALSE);
186*4882a593Smuzhiyun flags[XTestptr->id] |= XIDeviceEnabled;
187*4882a593Smuzhiyun flags[XTestkeybd->id] |= XIDeviceEnabled;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /* Attach the XTest virtual devices to the newly
191*4882a593Smuzhiyun created master device */
192*4882a593Smuzhiyun AttachDevice(NULL, XTestptr, ptr);
193*4882a593Smuzhiyun AttachDevice(NULL, XTestkeybd, keybd);
194*4882a593Smuzhiyun flags[XTestptr->id] |= XISlaveAttached;
195*4882a593Smuzhiyun flags[XTestkeybd->id] |= XISlaveAttached;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun for (int i = 0; i < currentMaxClients; i++)
198*4882a593Smuzhiyun XIBarrierNewMasterDevice(clients[i], ptr->id);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun unwind:
201*4882a593Smuzhiyun free(name);
202*4882a593Smuzhiyun return rc;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun static void
disable_clientpointer(DeviceIntPtr dev)206*4882a593Smuzhiyun disable_clientpointer(DeviceIntPtr dev)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun int i;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun for (i = 0; i < currentMaxClients; i++) {
211*4882a593Smuzhiyun ClientPtr client = clients[i];
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (client && client->clientPtr == dev)
214*4882a593Smuzhiyun client->clientPtr = NULL;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun static int
remove_master(ClientPtr client,xXIRemoveMasterInfo * r,int flags[MAXDEVICES])219*4882a593Smuzhiyun remove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES])
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
222*4882a593Smuzhiyun int rc = Success;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (r->return_mode != XIAttachToMaster && r->return_mode != XIFloating)
225*4882a593Smuzhiyun return BadValue;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess);
228*4882a593Smuzhiyun if (rc != Success)
229*4882a593Smuzhiyun goto unwind;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun if (!IsMaster(ptr)) {
232*4882a593Smuzhiyun client->errorValue = r->deviceid;
233*4882a593Smuzhiyun rc = BadDevice;
234*4882a593Smuzhiyun goto unwind;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun /* XXX: For now, don't allow removal of VCP, VCK */
238*4882a593Smuzhiyun if (ptr == inputInfo.pointer ||ptr == inputInfo.keyboard) {
239*4882a593Smuzhiyun rc = BadDevice;
240*4882a593Smuzhiyun goto unwind;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun ptr = GetMaster(ptr, MASTER_POINTER);
244*4882a593Smuzhiyun rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess);
245*4882a593Smuzhiyun if (rc != Success)
246*4882a593Smuzhiyun goto unwind;
247*4882a593Smuzhiyun keybd = GetMaster(ptr, MASTER_KEYBOARD);
248*4882a593Smuzhiyun rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess);
249*4882a593Smuzhiyun if (rc != Success)
250*4882a593Smuzhiyun goto unwind;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun XTestptr = GetXTestDevice(ptr);
253*4882a593Smuzhiyun rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess);
254*4882a593Smuzhiyun if (rc != Success)
255*4882a593Smuzhiyun goto unwind;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun XTestkeybd = GetXTestDevice(keybd);
258*4882a593Smuzhiyun rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, DixDestroyAccess);
259*4882a593Smuzhiyun if (rc != Success)
260*4882a593Smuzhiyun goto unwind;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun disable_clientpointer(ptr);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun /* Disabling sends the devices floating, reattach them if
265*4882a593Smuzhiyun * desired. */
266*4882a593Smuzhiyun if (r->return_mode == XIAttachToMaster) {
267*4882a593Smuzhiyun DeviceIntPtr attached, newptr, newkeybd;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun rc = dixLookupDevice(&newptr, r->return_pointer, client, DixAddAccess);
270*4882a593Smuzhiyun if (rc != Success)
271*4882a593Smuzhiyun goto unwind;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun if (!IsMaster(newptr)) {
274*4882a593Smuzhiyun client->errorValue = r->return_pointer;
275*4882a593Smuzhiyun rc = BadDevice;
276*4882a593Smuzhiyun goto unwind;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun rc = dixLookupDevice(&newkeybd, r->return_keyboard,
280*4882a593Smuzhiyun client, DixAddAccess);
281*4882a593Smuzhiyun if (rc != Success)
282*4882a593Smuzhiyun goto unwind;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun if (!IsMaster(newkeybd)) {
285*4882a593Smuzhiyun client->errorValue = r->return_keyboard;
286*4882a593Smuzhiyun rc = BadDevice;
287*4882a593Smuzhiyun goto unwind;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun for (attached = inputInfo.devices; attached; attached = attached->next) {
291*4882a593Smuzhiyun if (!IsMaster(attached)) {
292*4882a593Smuzhiyun if (GetMaster(attached, MASTER_ATTACHED) == ptr) {
293*4882a593Smuzhiyun AttachDevice(client, attached, newptr);
294*4882a593Smuzhiyun flags[attached->id] |= XISlaveAttached;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun if (GetMaster(attached, MASTER_ATTACHED) == keybd) {
297*4882a593Smuzhiyun AttachDevice(client, attached, newkeybd);
298*4882a593Smuzhiyun flags[attached->id] |= XISlaveAttached;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun for (int i = 0; i < currentMaxClients; i++)
305*4882a593Smuzhiyun XIBarrierRemoveMasterDevice(clients[i], ptr->id);
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun /* disable the remove the devices, XTest devices must be done first
308*4882a593Smuzhiyun else the sprites they rely on will be destroyed */
309*4882a593Smuzhiyun DisableDevice(XTestptr, FALSE);
310*4882a593Smuzhiyun DisableDevice(XTestkeybd, FALSE);
311*4882a593Smuzhiyun DisableDevice(keybd, FALSE);
312*4882a593Smuzhiyun DisableDevice(ptr, FALSE);
313*4882a593Smuzhiyun flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached;
314*4882a593Smuzhiyun flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached;
315*4882a593Smuzhiyun flags[keybd->id] |= XIDeviceDisabled;
316*4882a593Smuzhiyun flags[ptr->id] |= XIDeviceDisabled;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun flags[XTestptr->id] |= XISlaveRemoved;
319*4882a593Smuzhiyun flags[XTestkeybd->id] |= XISlaveRemoved;
320*4882a593Smuzhiyun flags[keybd->id] |= XIMasterRemoved;
321*4882a593Smuzhiyun flags[ptr->id] |= XIMasterRemoved;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun RemoveDevice(XTestptr, FALSE);
324*4882a593Smuzhiyun RemoveDevice(XTestkeybd, FALSE);
325*4882a593Smuzhiyun RemoveDevice(keybd, FALSE);
326*4882a593Smuzhiyun RemoveDevice(ptr, FALSE);
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun unwind:
329*4882a593Smuzhiyun return rc;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun static int
detach_slave(ClientPtr client,xXIDetachSlaveInfo * c,int flags[MAXDEVICES])333*4882a593Smuzhiyun detach_slave(ClientPtr client, xXIDetachSlaveInfo * c, int flags[MAXDEVICES])
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun DeviceIntPtr dev;
336*4882a593Smuzhiyun int rc;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
339*4882a593Smuzhiyun if (rc != Success)
340*4882a593Smuzhiyun goto unwind;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (IsMaster(dev)) {
343*4882a593Smuzhiyun client->errorValue = c->deviceid;
344*4882a593Smuzhiyun rc = BadDevice;
345*4882a593Smuzhiyun goto unwind;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun /* Don't allow changes to XTest Devices, these are fixed */
349*4882a593Smuzhiyun if (IsXTestDevice(dev, NULL)) {
350*4882a593Smuzhiyun client->errorValue = c->deviceid;
351*4882a593Smuzhiyun rc = BadDevice;
352*4882a593Smuzhiyun goto unwind;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun ReleaseButtonsAndKeys(dev);
356*4882a593Smuzhiyun AttachDevice(client, dev, NULL);
357*4882a593Smuzhiyun flags[dev->id] |= XISlaveDetached;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun unwind:
360*4882a593Smuzhiyun return rc;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun static int
attach_slave(ClientPtr client,xXIAttachSlaveInfo * c,int flags[MAXDEVICES])364*4882a593Smuzhiyun attach_slave(ClientPtr client, xXIAttachSlaveInfo * c, int flags[MAXDEVICES])
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun DeviceIntPtr dev;
367*4882a593Smuzhiyun DeviceIntPtr newmaster;
368*4882a593Smuzhiyun int rc;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
371*4882a593Smuzhiyun if (rc != Success)
372*4882a593Smuzhiyun goto unwind;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (IsMaster(dev)) {
375*4882a593Smuzhiyun client->errorValue = c->deviceid;
376*4882a593Smuzhiyun rc = BadDevice;
377*4882a593Smuzhiyun goto unwind;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /* Don't allow changes to XTest Devices, these are fixed */
381*4882a593Smuzhiyun if (IsXTestDevice(dev, NULL)) {
382*4882a593Smuzhiyun client->errorValue = c->deviceid;
383*4882a593Smuzhiyun rc = BadDevice;
384*4882a593Smuzhiyun goto unwind;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun rc = dixLookupDevice(&newmaster, c->new_master, client, DixAddAccess);
388*4882a593Smuzhiyun if (rc != Success)
389*4882a593Smuzhiyun goto unwind;
390*4882a593Smuzhiyun if (!IsMaster(newmaster)) {
391*4882a593Smuzhiyun client->errorValue = c->new_master;
392*4882a593Smuzhiyun rc = BadDevice;
393*4882a593Smuzhiyun goto unwind;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun if (!((IsPointerDevice(newmaster) && IsPointerDevice(dev)) ||
397*4882a593Smuzhiyun (IsKeyboardDevice(newmaster) && IsKeyboardDevice(dev)))) {
398*4882a593Smuzhiyun rc = BadDevice;
399*4882a593Smuzhiyun goto unwind;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun ReleaseButtonsAndKeys(dev);
403*4882a593Smuzhiyun AttachDevice(client, dev, newmaster);
404*4882a593Smuzhiyun flags[dev->id] |= XISlaveAttached;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun unwind:
407*4882a593Smuzhiyun return rc;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun #define SWAPIF(cmd) if (client->swapped) { cmd; }
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun int
ProcXIChangeHierarchy(ClientPtr client)413*4882a593Smuzhiyun ProcXIChangeHierarchy(ClientPtr client)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun xXIAnyHierarchyChangeInfo *any;
416*4882a593Smuzhiyun size_t len; /* length of data remaining in request */
417*4882a593Smuzhiyun int rc = Success;
418*4882a593Smuzhiyun int flags[MAXDEVICES] = { 0 };
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun REQUEST(xXIChangeHierarchyReq);
421*4882a593Smuzhiyun REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq);
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun if (!stuff->num_changes)
424*4882a593Smuzhiyun return rc;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun len = ((size_t)client->req_len << 2) - sizeof(xXIChangeHierarchyReq);
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun any = (xXIAnyHierarchyChangeInfo *) &stuff[1];
429*4882a593Smuzhiyun while (stuff->num_changes--) {
430*4882a593Smuzhiyun if (len < sizeof(xXIAnyHierarchyChangeInfo)) {
431*4882a593Smuzhiyun rc = BadLength;
432*4882a593Smuzhiyun goto unwind;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun SWAPIF(swaps(&any->type));
436*4882a593Smuzhiyun SWAPIF(swaps(&any->length));
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if (len < ((size_t)any->length << 2))
439*4882a593Smuzhiyun return BadLength;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun #define CHANGE_SIZE_MATCH(type) \
442*4882a593Smuzhiyun do { \
443*4882a593Smuzhiyun if ((len < sizeof(type)) || (any->length != (sizeof(type) >> 2))) { \
444*4882a593Smuzhiyun rc = BadLength; \
445*4882a593Smuzhiyun goto unwind; \
446*4882a593Smuzhiyun } \
447*4882a593Smuzhiyun } while(0)
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun switch (any->type) {
450*4882a593Smuzhiyun case XIAddMaster:
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun xXIAddMasterInfo *c = (xXIAddMasterInfo *) any;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /* Variable length, due to appended name string */
455*4882a593Smuzhiyun if (len < sizeof(xXIAddMasterInfo)) {
456*4882a593Smuzhiyun rc = BadLength;
457*4882a593Smuzhiyun goto unwind;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun SWAPIF(swaps(&c->name_len));
460*4882a593Smuzhiyun if (c->name_len > (len - sizeof(xXIAddMasterInfo))) {
461*4882a593Smuzhiyun rc = BadLength;
462*4882a593Smuzhiyun goto unwind;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun rc = add_master(client, c, flags);
466*4882a593Smuzhiyun if (rc != Success)
467*4882a593Smuzhiyun goto unwind;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun break;
470*4882a593Smuzhiyun case XIRemoveMaster:
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun xXIRemoveMasterInfo *r = (xXIRemoveMasterInfo *) any;
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun CHANGE_SIZE_MATCH(xXIRemoveMasterInfo);
475*4882a593Smuzhiyun rc = remove_master(client, r, flags);
476*4882a593Smuzhiyun if (rc != Success)
477*4882a593Smuzhiyun goto unwind;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun break;
480*4882a593Smuzhiyun case XIDetachSlave:
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun xXIDetachSlaveInfo *c = (xXIDetachSlaveInfo *) any;
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun CHANGE_SIZE_MATCH(xXIDetachSlaveInfo);
485*4882a593Smuzhiyun rc = detach_slave(client, c, flags);
486*4882a593Smuzhiyun if (rc != Success)
487*4882a593Smuzhiyun goto unwind;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun break;
490*4882a593Smuzhiyun case XIAttachSlave:
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun xXIAttachSlaveInfo *c = (xXIAttachSlaveInfo *) any;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun CHANGE_SIZE_MATCH(xXIAttachSlaveInfo);
495*4882a593Smuzhiyun rc = attach_slave(client, c, flags);
496*4882a593Smuzhiyun if (rc != Success)
497*4882a593Smuzhiyun goto unwind;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun break;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun len -= any->length * 4;
503*4882a593Smuzhiyun any = (xXIAnyHierarchyChangeInfo *) ((char *) any + any->length * 4);
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun unwind:
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun XISendDeviceHierarchyEvent(flags);
509*4882a593Smuzhiyun return rc;
510*4882a593Smuzhiyun }
511