1706f2543Smrg/*
2706f2543Smrg * Copyright 2007-2008 Peter Hutterer
3706f2543Smrg * Copyright 2009 Red Hat, Inc.
4706f2543Smrg *
5706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6706f2543Smrg * copy of this software and associated documentation files (the "Software"),
7706f2543Smrg * to deal in the Software without restriction, including without limitation
8706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
10706f2543Smrg * Software is furnished to do so, subject to the following conditions:
11706f2543Smrg *
12706f2543Smrg * The above copyright notice and this permission notice (including the next
13706f2543Smrg * paragraph) shall be included in all copies or substantial portions of the
14706f2543Smrg * Software.
15706f2543Smrg *
16706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19706f2543Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20706f2543Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21706f2543Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22706f2543Smrg * DEALINGS IN THE SOFTWARE.
23706f2543Smrg *
24706f2543Smrg * Author: Peter Hutterer, University of South Australia, NICTA
25706f2543Smrg */
26706f2543Smrg
27706f2543Smrg/***********************************************************************
28706f2543Smrg *
29706f2543Smrg * Request change in the device hierarchy.
30706f2543Smrg *
31706f2543Smrg */
32706f2543Smrg
33706f2543Smrg
34706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
35706f2543Smrg#include <dix-config.h>
36706f2543Smrg#endif
37706f2543Smrg
38706f2543Smrg#include <X11/X.h>	/* for inputstr.h    */
39706f2543Smrg#include <X11/Xproto.h>	/* Request macro     */
40706f2543Smrg#include "inputstr.h"	/* DeviceIntPtr      */
41706f2543Smrg#include "windowstr.h"	/* window structure  */
42706f2543Smrg#include "scrnintstr.h"	/* screen structure  */
43706f2543Smrg#include <X11/extensions/XI.h>
44706f2543Smrg#include <X11/extensions/XI2proto.h>
45706f2543Smrg#include <X11/extensions/geproto.h>
46706f2543Smrg#include "extnsionst.h"
47706f2543Smrg#include "exevents.h"
48706f2543Smrg#include "exglobals.h"
49706f2543Smrg#include "geext.h"
50706f2543Smrg#include "xace.h"
51706f2543Smrg#include "xiquerydevice.h" /* for GetDeviceUse */
52706f2543Smrg
53706f2543Smrg#include "xkbsrv.h"
54706f2543Smrg
55706f2543Smrg#include "xichangehierarchy.h"
56706f2543Smrg
57706f2543Smrg/**
58706f2543Smrg * Send the current state of the device hierarchy to all clients.
59706f2543Smrg */
60706f2543Smrgvoid XISendDeviceHierarchyEvent(int flags[MAXDEVICES])
61706f2543Smrg{
62706f2543Smrg    xXIHierarchyEvent *ev;
63706f2543Smrg    xXIHierarchyInfo *info;
64706f2543Smrg    DeviceIntRec dummyDev;
65706f2543Smrg    DeviceIntPtr dev;
66706f2543Smrg    int i;
67706f2543Smrg
68706f2543Smrg    if (!flags)
69706f2543Smrg        return;
70706f2543Smrg
71706f2543Smrg    ev = calloc(1, sizeof(xXIHierarchyEvent) +
72706f2543Smrg                 MAXDEVICES * sizeof(xXIHierarchyInfo));
73706f2543Smrg    if (!ev)
74706f2543Smrg        return;
75706f2543Smrg    ev->type = GenericEvent;
76706f2543Smrg    ev->extension = IReqCode;
77706f2543Smrg    ev->evtype = XI_HierarchyChanged;
78706f2543Smrg    ev->time = GetTimeInMillis();
79706f2543Smrg    ev->flags = 0;
80706f2543Smrg    ev->num_info = inputInfo.numDevices;
81706f2543Smrg
82706f2543Smrg    info = (xXIHierarchyInfo*)&ev[1];
83706f2543Smrg    for (dev = inputInfo.devices; dev; dev = dev->next)
84706f2543Smrg    {
85706f2543Smrg        info->deviceid = dev->id;
86706f2543Smrg        info->enabled = dev->enabled;
87706f2543Smrg        info->use = GetDeviceUse(dev, &info->attachment);
88706f2543Smrg        info->flags = flags[dev->id];
89706f2543Smrg        ev->flags |= info->flags;
90706f2543Smrg        info++;
91706f2543Smrg    }
92706f2543Smrg    for (dev = inputInfo.off_devices; dev; dev = dev->next)
93706f2543Smrg    {
94706f2543Smrg        info->deviceid = dev->id;
95706f2543Smrg        info->enabled = dev->enabled;
96706f2543Smrg        info->use = GetDeviceUse(dev, &info->attachment);
97706f2543Smrg        info->flags = flags[dev->id];
98706f2543Smrg        ev->flags |= info->flags;
99706f2543Smrg        info++;
100706f2543Smrg    }
101706f2543Smrg
102706f2543Smrg
103706f2543Smrg    for (i = 0; i < MAXDEVICES; i++)
104706f2543Smrg    {
105706f2543Smrg        if (flags[i] & (XIMasterRemoved | XISlaveRemoved))
106706f2543Smrg        {
107706f2543Smrg            info->deviceid = i;
108706f2543Smrg            info->enabled = FALSE;
109706f2543Smrg            info->flags = flags[i];
110706f2543Smrg            info->use = 0;
111706f2543Smrg            ev->flags |= info->flags;
112706f2543Smrg            ev->num_info++;
113706f2543Smrg            info++;
114706f2543Smrg        }
115706f2543Smrg    }
116706f2543Smrg
117706f2543Smrg    ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo));
118706f2543Smrg
119706f2543Smrg    dummyDev.id = XIAllDevices;
120706f2543Smrg    SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8), (xEvent*)ev, 1);
121706f2543Smrg    free(ev);
122706f2543Smrg}
123706f2543Smrg
124706f2543Smrg
125706f2543Smrg/***********************************************************************
126706f2543Smrg *
127706f2543Smrg * This procedure allows a client to change the device hierarchy through
128706f2543Smrg * adding new master devices, removing them, etc.
129706f2543Smrg *
130706f2543Smrg */
131706f2543Smrg
132706f2543Smrgint SProcXIChangeHierarchy(ClientPtr client)
133706f2543Smrg{
134706f2543Smrg    char n;
135706f2543Smrg
136706f2543Smrg    REQUEST(xXIChangeHierarchyReq);
137706f2543Smrg    swaps(&stuff->length, n);
138706f2543Smrg    return (ProcXIChangeHierarchy(client));
139706f2543Smrg}
140706f2543Smrg
141706f2543Smrgstatic int
142706f2543Smrgadd_master(ClientPtr client, xXIAddMasterInfo *c, int flags[MAXDEVICES])
143706f2543Smrg{
144706f2543Smrg    DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
145706f2543Smrg    char* name;
146706f2543Smrg    int rc;
147706f2543Smrg
148706f2543Smrg    name = calloc(c->name_len + 1, sizeof(char));
149706f2543Smrg    strncpy(name, (char*)&c[1], c->name_len);
150706f2543Smrg
151706f2543Smrg    rc = AllocDevicePair(client, name, &ptr, &keybd,
152706f2543Smrg                         CorePointerProc, CoreKeyboardProc, TRUE);
153706f2543Smrg    if (rc != Success)
154706f2543Smrg        goto unwind;
155706f2543Smrg
156706f2543Smrg    if (!c->send_core)
157706f2543Smrg        ptr->coreEvents = keybd->coreEvents =  FALSE;
158706f2543Smrg
159706f2543Smrg    /* Allocate virtual slave devices for xtest events */
160706f2543Smrg    rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, ptr, keybd);
161706f2543Smrg    if (rc != Success)
162706f2543Smrg    {
163706f2543Smrg        DeleteInputDeviceRequest(ptr);
164706f2543Smrg        DeleteInputDeviceRequest(keybd);
165706f2543Smrg        goto unwind;
166706f2543Smrg    }
167706f2543Smrg
168706f2543Smrg    ActivateDevice(ptr, FALSE);
169706f2543Smrg    ActivateDevice(keybd, FALSE);
170706f2543Smrg    flags[ptr->id] |= XIMasterAdded;
171706f2543Smrg    flags[keybd->id] |= XIMasterAdded;
172706f2543Smrg
173706f2543Smrg    ActivateDevice(XTestptr, FALSE);
174706f2543Smrg    ActivateDevice(XTestkeybd, FALSE);
175706f2543Smrg    flags[XTestptr->id] |= XISlaveAdded;
176706f2543Smrg    flags[XTestkeybd->id] |= XISlaveAdded;
177706f2543Smrg
178706f2543Smrg    if (c->enable)
179706f2543Smrg    {
180706f2543Smrg        EnableDevice(ptr, FALSE);
181706f2543Smrg        EnableDevice(keybd, FALSE);
182706f2543Smrg        flags[ptr->id] |= XIDeviceEnabled;
183706f2543Smrg        flags[keybd->id] |= XIDeviceEnabled;
184706f2543Smrg
185706f2543Smrg        EnableDevice(XTestptr, FALSE);
186706f2543Smrg        EnableDevice(XTestkeybd, FALSE);
187706f2543Smrg        flags[XTestptr->id] |= XIDeviceEnabled;
188706f2543Smrg        flags[XTestkeybd->id] |= XIDeviceEnabled;
189706f2543Smrg    }
190706f2543Smrg
191706f2543Smrg    /* Attach the XTest virtual devices to the newly
192706f2543Smrg       created master device */
193706f2543Smrg    AttachDevice(NULL, XTestptr, ptr);
194706f2543Smrg    AttachDevice(NULL, XTestkeybd, keybd);
195706f2543Smrg    flags[XTestptr->id] |= XISlaveAttached;
196706f2543Smrg    flags[XTestkeybd->id] |= XISlaveAttached;
197706f2543Smrg
198706f2543Smrgunwind:
199706f2543Smrg    free(name);
200706f2543Smrg    return rc;
201706f2543Smrg}
202706f2543Smrg
203706f2543Smrgstatic void
204706f2543Smrgdisable_clientpointer(DeviceIntPtr dev)
205706f2543Smrg{
206706f2543Smrg    int i;
207706f2543Smrg
208706f2543Smrg    for (i = 0; i < currentMaxClients; i++)
209706f2543Smrg    {
210706f2543Smrg        ClientPtr client = clients[i];
211706f2543Smrg        if (client && client->clientPtr == dev)
212706f2543Smrg            client->clientPtr = NULL;
213706f2543Smrg    }
214706f2543Smrg}
215706f2543Smrg
216706f2543Smrgstatic int
217706f2543Smrgremove_master(ClientPtr client, xXIRemoveMasterInfo *r,
218706f2543Smrg              int flags[MAXDEVICES])
219706f2543Smrg{
220706f2543Smrg    DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
221706f2543Smrg    int rc = Success;
222706f2543Smrg
223706f2543Smrg    if (r->return_mode != XIAttachToMaster &&
224706f2543Smrg        r->return_mode != XIFloating)
225706f2543Smrg        return BadValue;
226706f2543Smrg
227706f2543Smrg    rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess);
228706f2543Smrg    if (rc != Success)
229706f2543Smrg        goto unwind;
230706f2543Smrg
231706f2543Smrg    if (!IsMaster(ptr))
232706f2543Smrg    {
233706f2543Smrg        client->errorValue = r->deviceid;
234706f2543Smrg        rc = BadDevice;
235706f2543Smrg        goto unwind;
236706f2543Smrg    }
237706f2543Smrg
238706f2543Smrg    /* XXX: For now, don't allow removal of VCP, VCK */
239706f2543Smrg    if (ptr == inputInfo.pointer || ptr == inputInfo.keyboard)
240706f2543Smrg    {
241706f2543Smrg        rc = BadDevice;
242706f2543Smrg        goto unwind;
243706f2543Smrg    }
244706f2543Smrg
245706f2543Smrg
246706f2543Smrg    ptr = GetMaster(ptr, MASTER_POINTER);
247706f2543Smrg    rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess);
248706f2543Smrg    if (rc != Success)
249706f2543Smrg        goto unwind;
250706f2543Smrg    keybd = GetMaster(ptr, MASTER_KEYBOARD);
251706f2543Smrg    rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess);
252706f2543Smrg    if (rc != Success)
253706f2543Smrg        goto unwind;
254706f2543Smrg
255706f2543Smrg    XTestptr = GetXTestDevice(ptr);
256706f2543Smrg    rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess);
257706f2543Smrg    if (rc != Success)
258706f2543Smrg        goto unwind;
259706f2543Smrg
260706f2543Smrg    XTestkeybd = GetXTestDevice(keybd);
261706f2543Smrg    rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client,
262706f2543Smrg                         DixDestroyAccess);
263706f2543Smrg    if (rc != Success)
264706f2543Smrg        goto unwind;
265706f2543Smrg
266706f2543Smrg    disable_clientpointer(ptr);
267706f2543Smrg
268706f2543Smrg    /* Disabling sends the devices floating, reattach them if
269706f2543Smrg     * desired. */
270706f2543Smrg    if (r->return_mode == XIAttachToMaster)
271706f2543Smrg    {
272706f2543Smrg        DeviceIntPtr attached,
273706f2543Smrg                     newptr,
274706f2543Smrg                     newkeybd;
275706f2543Smrg
276706f2543Smrg        rc = dixLookupDevice(&newptr, r->return_pointer, client, DixAddAccess);
277706f2543Smrg        if (rc != Success)
278706f2543Smrg            goto unwind;
279706f2543Smrg
280706f2543Smrg        if (!IsMaster(newptr))
281706f2543Smrg        {
282706f2543Smrg            client->errorValue = r->return_pointer;
283706f2543Smrg            rc = BadDevice;
284706f2543Smrg            goto unwind;
285706f2543Smrg        }
286706f2543Smrg
287706f2543Smrg        rc = dixLookupDevice(&newkeybd, r->return_keyboard,
288706f2543Smrg                             client, DixAddAccess);
289706f2543Smrg        if (rc != Success)
290706f2543Smrg            goto unwind;
291706f2543Smrg
292706f2543Smrg        if (!IsMaster(newkeybd))
293706f2543Smrg        {
294706f2543Smrg            client->errorValue = r->return_keyboard;
295706f2543Smrg            rc = BadDevice;
296706f2543Smrg            goto unwind;
297706f2543Smrg        }
298706f2543Smrg
299706f2543Smrg        for (attached = inputInfo.devices; attached; attached = attached->next)
300706f2543Smrg        {
301706f2543Smrg            if (!IsMaster(attached)) {
302706f2543Smrg                if (attached->u.master == ptr)
303706f2543Smrg                {
304706f2543Smrg                    AttachDevice(client, attached, newptr);
305706f2543Smrg                    flags[attached->id] |= XISlaveAttached;
306706f2543Smrg                }
307706f2543Smrg                if (attached->u.master == keybd)
308706f2543Smrg                {
309706f2543Smrg                    AttachDevice(client, attached, newkeybd);
310706f2543Smrg                    flags[attached->id] |= XISlaveAttached;
311706f2543Smrg                }
312706f2543Smrg            }
313706f2543Smrg        }
314706f2543Smrg    }
315706f2543Smrg
316706f2543Smrg    /* can't disable until we removed pairing */
317706f2543Smrg    keybd->spriteInfo->paired = NULL;
318706f2543Smrg    ptr->spriteInfo->paired = NULL;
319706f2543Smrg    XTestptr->spriteInfo->paired = NULL;
320706f2543Smrg    XTestkeybd->spriteInfo->paired = NULL;
321706f2543Smrg
322706f2543Smrg    /* disable the remove the devices, XTest devices must be done first
323706f2543Smrg       else the sprites they rely on will be destroyed  */
324706f2543Smrg    DisableDevice(XTestptr, FALSE);
325706f2543Smrg    DisableDevice(XTestkeybd, FALSE);
326706f2543Smrg    DisableDevice(keybd, FALSE);
327706f2543Smrg    DisableDevice(ptr, FALSE);
328706f2543Smrg    flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached;
329706f2543Smrg    flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached;
330706f2543Smrg    flags[keybd->id] |= XIDeviceDisabled;
331706f2543Smrg    flags[ptr->id] |= XIDeviceDisabled;
332706f2543Smrg
333706f2543Smrg    RemoveDevice(XTestptr, FALSE);
334706f2543Smrg    RemoveDevice(XTestkeybd, FALSE);
335706f2543Smrg    RemoveDevice(keybd, FALSE);
336706f2543Smrg    RemoveDevice(ptr, FALSE);
337706f2543Smrg    flags[XTestptr->id] |= XISlaveRemoved;
338706f2543Smrg    flags[XTestkeybd->id] |= XISlaveRemoved;
339706f2543Smrg    flags[keybd->id] |= XIMasterRemoved;
340706f2543Smrg    flags[ptr->id] |= XIMasterRemoved;
341706f2543Smrg
342706f2543Smrgunwind:
343706f2543Smrg    return rc;
344706f2543Smrg}
345706f2543Smrg
346706f2543Smrgstatic int
347706f2543Smrgdetach_slave(ClientPtr client, xXIDetachSlaveInfo *c, int flags[MAXDEVICES])
348706f2543Smrg{
349706f2543Smrg    DeviceIntPtr dev;
350706f2543Smrg    int rc;
351706f2543Smrg
352706f2543Smrg    rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
353706f2543Smrg    if (rc != Success)
354706f2543Smrg        goto unwind;
355706f2543Smrg
356706f2543Smrg    if (IsMaster(dev))
357706f2543Smrg    {
358706f2543Smrg        client->errorValue = c->deviceid;
359706f2543Smrg        rc = BadDevice;
360706f2543Smrg        goto unwind;
361706f2543Smrg    }
362706f2543Smrg
363706f2543Smrg    /* Don't allow changes to XTest Devices, these are fixed */
364706f2543Smrg    if (IsXTestDevice(dev, NULL))
365706f2543Smrg    {
366706f2543Smrg        client->errorValue = c->deviceid;
367706f2543Smrg        rc = BadDevice;
368706f2543Smrg        goto unwind;
369706f2543Smrg    }
370706f2543Smrg
371706f2543Smrg    ReleaseButtonsAndKeys(dev);
372706f2543Smrg    AttachDevice(client, dev, NULL);
373706f2543Smrg    flags[dev->id] |= XISlaveDetached;
374706f2543Smrg
375706f2543Smrgunwind:
376706f2543Smrg    return rc;
377706f2543Smrg}
378706f2543Smrg
379706f2543Smrgstatic int
380706f2543Smrgattach_slave(ClientPtr client, xXIAttachSlaveInfo *c,
381706f2543Smrg             int flags[MAXDEVICES])
382706f2543Smrg{
383706f2543Smrg    DeviceIntPtr dev;
384706f2543Smrg    DeviceIntPtr newmaster;
385706f2543Smrg    int rc;
386706f2543Smrg
387706f2543Smrg    rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
388706f2543Smrg    if (rc != Success)
389706f2543Smrg        goto unwind;
390706f2543Smrg
391706f2543Smrg    if (IsMaster(dev))
392706f2543Smrg    {
393706f2543Smrg        client->errorValue = c->deviceid;
394706f2543Smrg        rc = BadDevice;
395706f2543Smrg        goto unwind;
396706f2543Smrg    }
397706f2543Smrg
398706f2543Smrg    /* Don't allow changes to XTest Devices, these are fixed */
399706f2543Smrg    if (IsXTestDevice(dev, NULL))
400706f2543Smrg    {
401706f2543Smrg        client->errorValue = c->deviceid;
402706f2543Smrg        rc = BadDevice;
403706f2543Smrg        goto unwind;
404706f2543Smrg    }
405706f2543Smrg
406706f2543Smrg    rc = dixLookupDevice(&newmaster, c->new_master, client, DixAddAccess);
407706f2543Smrg    if (rc != Success)
408706f2543Smrg        goto unwind;
409706f2543Smrg    if (!IsMaster(newmaster))
410706f2543Smrg    {
411706f2543Smrg        client->errorValue = c->new_master;
412706f2543Smrg        rc = BadDevice;
413706f2543Smrg        goto unwind;
414706f2543Smrg    }
415706f2543Smrg
416706f2543Smrg    if (!((IsPointerDevice(newmaster) && IsPointerDevice(dev)) ||
417706f2543Smrg        (IsKeyboardDevice(newmaster) && IsKeyboardDevice(dev))))
418706f2543Smrg    {
419706f2543Smrg        rc = BadDevice;
420706f2543Smrg        goto unwind;
421706f2543Smrg    }
422706f2543Smrg
423706f2543Smrg    ReleaseButtonsAndKeys(dev);
424706f2543Smrg    AttachDevice(client, dev, newmaster);
425706f2543Smrg    flags[dev->id] |= XISlaveAttached;
426706f2543Smrg
427706f2543Smrgunwind:
428706f2543Smrg    return rc;
429706f2543Smrg}
430706f2543Smrg
431706f2543Smrg
432706f2543Smrg
433706f2543Smrg#define SWAPIF(cmd) if (client->swapped) { cmd; }
434706f2543Smrg
435706f2543Smrgint
436706f2543SmrgProcXIChangeHierarchy(ClientPtr client)
437706f2543Smrg{
438706f2543Smrg    xXIAnyHierarchyChangeInfo *any;
439706f2543Smrg    size_t len;			/* length of data remaining in request */
440706f2543Smrg    char n;
441706f2543Smrg    int rc = Success;
442706f2543Smrg    int flags[MAXDEVICES] = {0};
4437b5ab33aSmrg    enum {
4447b5ab33aSmrg        NO_CHANGE,
4457b5ab33aSmrg        FLUSH,
4467b5ab33aSmrg        CHANGED,
4477b5ab33aSmrg    } changes = NO_CHANGE;
448706f2543Smrg
449706f2543Smrg    REQUEST(xXIChangeHierarchyReq);
450706f2543Smrg    REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq);
451706f2543Smrg
452706f2543Smrg    if (!stuff->num_changes)
453706f2543Smrg        return rc;
454706f2543Smrg
455706f2543Smrg    if (stuff->length > (INT_MAX >> 2))
456706f2543Smrg        return BadAlloc;
45748a68b89Smrg    len = (stuff->length << 2) - sizeof(xXIChangeHierarchyReq);
458706f2543Smrg
459706f2543Smrg    any = (xXIAnyHierarchyChangeInfo*)&stuff[1];
460706f2543Smrg    while(stuff->num_changes--)
461706f2543Smrg    {
462706f2543Smrg        if (len < sizeof(xXIAnyHierarchyChangeInfo)) {
463706f2543Smrg            rc = BadLength;
464706f2543Smrg            goto unwind;
465706f2543Smrg        }
466706f2543Smrg
467706f2543Smrg        SWAPIF(swapl(&any->type, n));
468706f2543Smrg        SWAPIF(swaps(&any->length, n));
469706f2543Smrg
470706f2543Smrg        if ((any->length > (INT_MAX >> 2)) || (len < (any->length << 2)))
471706f2543Smrg            return BadLength;
472706f2543Smrg
473706f2543Smrg#define CHANGE_SIZE_MATCH(type) \
474706f2543Smrg    do { \
475706f2543Smrg        if ((len < sizeof(type)) || (any->length != (sizeof(type) >> 2))) { \
476706f2543Smrg            rc = BadLength; \
477706f2543Smrg            goto unwind; \
478706f2543Smrg        } \
479706f2543Smrg    } while(0)
480706f2543Smrg
481706f2543Smrg        switch(any->type)
482706f2543Smrg        {
483706f2543Smrg            case XIAddMaster:
484706f2543Smrg                {
485706f2543Smrg                    xXIAddMasterInfo* c = (xXIAddMasterInfo*)any;
486706f2543Smrg	            /* Variable length, due to appended name string */
487706f2543Smrg	            if (len < sizeof(xXIAddMasterInfo)) {
488706f2543Smrg	                rc = BadLength;
489706f2543Smrg	                goto unwind;
490706f2543Smrg	            }
491706f2543Smrg                    SWAPIF(swaps(&c->name_len, n));
492706f2543Smrg	            if (c->name_len > (len - sizeof(xXIAddMasterInfo))) {
493706f2543Smrg	                rc = BadLength;
494706f2543Smrg	                goto unwind;
495706f2543Smrg	            }
496706f2543Smrg
497706f2543Smrg                    rc = add_master(client, c, flags);
498706f2543Smrg                    if (rc != Success)
499706f2543Smrg                        goto unwind;
5007b5ab33aSmrg	            changes = FLUSH;
5017b5ab33aSmrg                    break;
502706f2543Smrg                }
503706f2543Smrg            case XIRemoveMaster:
504706f2543Smrg                {
505706f2543Smrg                    xXIRemoveMasterInfo* r = (xXIRemoveMasterInfo*)any;
506706f2543Smrg
507706f2543Smrg	            CHANGE_SIZE_MATCH(xXIRemoveMasterInfo);
508706f2543Smrg                    rc = remove_master(client, r, flags);
509706f2543Smrg                    if (rc != Success)
510706f2543Smrg                        goto unwind;
5117b5ab33aSmrg                    changes = FLUSH;
5127b5ab33aSmrg                    break;
513706f2543Smrg                }
514706f2543Smrg            case XIDetachSlave:
515706f2543Smrg                {
516706f2543Smrg                    xXIDetachSlaveInfo* c = (xXIDetachSlaveInfo*)any;
517706f2543Smrg
518706f2543Smrg	            CHANGE_SIZE_MATCH(xXIDetachSlaveInfo);
519706f2543Smrg                    rc = detach_slave(client, c, flags);
520706f2543Smrg                    if (rc != Success)
521706f2543Smrg                       goto unwind;
5227b5ab33aSmrg                    changes = CHANGED;
5237b5ab33aSmrg                    break;
524706f2543Smrg                }
525706f2543Smrg            case XIAttachSlave:
526706f2543Smrg                {
527706f2543Smrg                    xXIAttachSlaveInfo* c = (xXIAttachSlaveInfo*)any;
528706f2543Smrg
529706f2543Smrg	            CHANGE_SIZE_MATCH(xXIAttachSlaveInfo);
530706f2543Smrg                    rc = attach_slave(client, c, flags);
531706f2543Smrg                    if (rc != Success)
532706f2543Smrg                       goto unwind;
5337b5ab33aSmrg                    changes = CHANGED;
5347b5ab33aSmrg                    break;
535706f2543Smrg                }
5367b5ab33aSmrg            default:
537706f2543Smrg                break;
538706f2543Smrg        }
539706f2543Smrg
5407b5ab33aSmrg        if (changes == FLUSH) {
5417b5ab33aSmrg            XISendDeviceHierarchyEvent(flags);
5427b5ab33aSmrg            memset(flags, 0, sizeof(flags));
5437b5ab33aSmrg            changes = NO_CHANGE;
5447b5ab33aSmrg        }
5457b5ab33aSmrg
546706f2543Smrg        len -= any->length * 4;
547706f2543Smrg        any = (xXIAnyHierarchyChangeInfo*)((char*)any + any->length * 4);
548706f2543Smrg    }
549706f2543Smrg
550706f2543Smrgunwind:
551706f2543Smrg
5527b5ab33aSmrg    if (changes != NO_CHANGE)
5537b5ab33aSmrg        XISendDeviceHierarchyEvent(flags);
554706f2543Smrg    return rc;
555706f2543Smrg}
556706f2543Smrg
557