xichangehierarchy.c revision 0b0d8713
16747b715Smrg/*
26747b715Smrg * Copyright 2007-2008 Peter Hutterer
36747b715Smrg * Copyright 2009 Red Hat, Inc.
46747b715Smrg *
56747b715Smrg * Permission is hereby granted, free of charge, to any person obtaining a
66747b715Smrg * copy of this software and associated documentation files (the "Software"),
76747b715Smrg * to deal in the Software without restriction, including without limitation
86747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
96747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the
106747b715Smrg * Software is furnished to do so, subject to the following conditions:
116747b715Smrg *
126747b715Smrg * The above copyright notice and this permission notice (including the next
136747b715Smrg * paragraph) shall be included in all copies or substantial portions of the
146747b715Smrg * Software.
156747b715Smrg *
166747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
176747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
186747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
196747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
206747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
216747b715Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
226747b715Smrg * DEALINGS IN THE SOFTWARE.
236747b715Smrg *
246747b715Smrg * Author: Peter Hutterer, University of South Australia, NICTA
256747b715Smrg */
266747b715Smrg
276747b715Smrg/***********************************************************************
286747b715Smrg *
296747b715Smrg * Request change in the device hierarchy.
306747b715Smrg *
316747b715Smrg */
326747b715Smrg
336747b715Smrg
346747b715Smrg#ifdef HAVE_DIX_CONFIG_H
356747b715Smrg#include <dix-config.h>
366747b715Smrg#endif
376747b715Smrg
386747b715Smrg#include <X11/X.h>	/* for inputstr.h    */
396747b715Smrg#include <X11/Xproto.h>	/* Request macro     */
406747b715Smrg#include "inputstr.h"	/* DeviceIntPtr      */
416747b715Smrg#include "windowstr.h"	/* window structure  */
426747b715Smrg#include "scrnintstr.h"	/* screen structure  */
436747b715Smrg#include <X11/extensions/XI.h>
446747b715Smrg#include <X11/extensions/XI2proto.h>
456747b715Smrg#include <X11/extensions/geproto.h>
466747b715Smrg#include "extnsionst.h"
476747b715Smrg#include "exevents.h"
486747b715Smrg#include "exglobals.h"
496747b715Smrg#include "geext.h"
506747b715Smrg#include "xace.h"
516747b715Smrg#include "xiquerydevice.h" /* for GetDeviceUse */
526747b715Smrg
536747b715Smrg#include "xkbsrv.h"
546747b715Smrg
556747b715Smrg#include "xichangehierarchy.h"
566747b715Smrg
576747b715Smrg/**
586747b715Smrg * Send the current state of the device hierarchy to all clients.
596747b715Smrg */
606747b715Smrgvoid XISendDeviceHierarchyEvent(int flags[MAXDEVICES])
616747b715Smrg{
626747b715Smrg    xXIHierarchyEvent *ev;
636747b715Smrg    xXIHierarchyInfo *info;
646747b715Smrg    DeviceIntRec dummyDev;
656747b715Smrg    DeviceIntPtr dev;
666747b715Smrg    int i;
676747b715Smrg
686747b715Smrg    if (!flags)
696747b715Smrg        return;
706747b715Smrg
716747b715Smrg    ev = calloc(1, sizeof(xXIHierarchyEvent) +
726747b715Smrg                 MAXDEVICES * sizeof(xXIHierarchyInfo));
739ace9065Smrg    if (!ev)
749ace9065Smrg        return;
756747b715Smrg    ev->type = GenericEvent;
766747b715Smrg    ev->extension = IReqCode;
776747b715Smrg    ev->evtype = XI_HierarchyChanged;
786747b715Smrg    ev->time = GetTimeInMillis();
796747b715Smrg    ev->flags = 0;
806747b715Smrg    ev->num_info = inputInfo.numDevices;
816747b715Smrg
826747b715Smrg    info = (xXIHierarchyInfo*)&ev[1];
836747b715Smrg    for (dev = inputInfo.devices; dev; dev = dev->next)
846747b715Smrg    {
856747b715Smrg        info->deviceid = dev->id;
866747b715Smrg        info->enabled = dev->enabled;
876747b715Smrg        info->use = GetDeviceUse(dev, &info->attachment);
886747b715Smrg        info->flags = flags[dev->id];
896747b715Smrg        ev->flags |= info->flags;
906747b715Smrg        info++;
916747b715Smrg    }
926747b715Smrg    for (dev = inputInfo.off_devices; dev; dev = dev->next)
936747b715Smrg    {
946747b715Smrg        info->deviceid = dev->id;
956747b715Smrg        info->enabled = dev->enabled;
966747b715Smrg        info->use = GetDeviceUse(dev, &info->attachment);
976747b715Smrg        info->flags = flags[dev->id];
986747b715Smrg        ev->flags |= info->flags;
996747b715Smrg        info++;
1006747b715Smrg    }
1016747b715Smrg
1026747b715Smrg
1036747b715Smrg    for (i = 0; i < MAXDEVICES; i++)
1046747b715Smrg    {
1056747b715Smrg        if (flags[i] & (XIMasterRemoved | XISlaveRemoved))
1066747b715Smrg        {
1076747b715Smrg            info->deviceid = i;
1086747b715Smrg            info->enabled = FALSE;
1096747b715Smrg            info->flags = flags[i];
1106747b715Smrg            info->use = 0;
1116747b715Smrg            ev->flags |= info->flags;
1126747b715Smrg            ev->num_info++;
1136747b715Smrg            info++;
1146747b715Smrg        }
1156747b715Smrg    }
1166747b715Smrg
1176747b715Smrg    ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo));
1186747b715Smrg
1196747b715Smrg    dummyDev.id = XIAllDevices;
1206747b715Smrg    SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8), (xEvent*)ev, 1);
1216747b715Smrg    free(ev);
1226747b715Smrg}
1236747b715Smrg
1246747b715Smrg
1256747b715Smrg/***********************************************************************
1266747b715Smrg *
1276747b715Smrg * This procedure allows a client to change the device hierarchy through
1286747b715Smrg * adding new master devices, removing them, etc.
1296747b715Smrg *
1306747b715Smrg */
1316747b715Smrg
1326747b715Smrgint SProcXIChangeHierarchy(ClientPtr client)
1336747b715Smrg{
1346747b715Smrg    char n;
1356747b715Smrg
1366747b715Smrg    REQUEST(xXIChangeHierarchyReq);
1376747b715Smrg    swaps(&stuff->length, n);
1386747b715Smrg    return (ProcXIChangeHierarchy(client));
1396747b715Smrg}
1406747b715Smrg
1419ace9065Smrgstatic int
1429ace9065Smrgadd_master(ClientPtr client, xXIAddMasterInfo *c, int flags[MAXDEVICES])
1439ace9065Smrg{
1449ace9065Smrg    DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
1459ace9065Smrg    char* name;
1469ace9065Smrg    int rc;
1479ace9065Smrg
1489ace9065Smrg    name = calloc(c->name_len + 1, sizeof(char));
1499ace9065Smrg    strncpy(name, (char*)&c[1], c->name_len);
1509ace9065Smrg
1519ace9065Smrg    rc = AllocDevicePair(client, name, &ptr, &keybd,
1529ace9065Smrg                         CorePointerProc, CoreKeyboardProc, TRUE);
1539ace9065Smrg    if (rc != Success)
1549ace9065Smrg        goto unwind;
1559ace9065Smrg
1569ace9065Smrg    if (!c->send_core)
1579ace9065Smrg        ptr->coreEvents = keybd->coreEvents =  FALSE;
1589ace9065Smrg
1599ace9065Smrg    /* Allocate virtual slave devices for xtest events */
1609ace9065Smrg    rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, ptr, keybd);
1619ace9065Smrg    if (rc != Success)
1629ace9065Smrg    {
1639ace9065Smrg        DeleteInputDeviceRequest(ptr);
1649ace9065Smrg        DeleteInputDeviceRequest(keybd);
1659ace9065Smrg        goto unwind;
1669ace9065Smrg    }
1679ace9065Smrg
1689ace9065Smrg    ActivateDevice(ptr, FALSE);
1699ace9065Smrg    ActivateDevice(keybd, FALSE);
1709ace9065Smrg    flags[ptr->id] |= XIMasterAdded;
1719ace9065Smrg    flags[keybd->id] |= XIMasterAdded;
1729ace9065Smrg
1739ace9065Smrg    ActivateDevice(XTestptr, FALSE);
1749ace9065Smrg    ActivateDevice(XTestkeybd, FALSE);
1759ace9065Smrg    flags[XTestptr->id] |= XISlaveAdded;
1769ace9065Smrg    flags[XTestkeybd->id] |= XISlaveAdded;
1779ace9065Smrg
1789ace9065Smrg    if (c->enable)
1799ace9065Smrg    {
1809ace9065Smrg        EnableDevice(ptr, FALSE);
1819ace9065Smrg        EnableDevice(keybd, FALSE);
1829ace9065Smrg        flags[ptr->id] |= XIDeviceEnabled;
1839ace9065Smrg        flags[keybd->id] |= XIDeviceEnabled;
1849ace9065Smrg
1859ace9065Smrg        EnableDevice(XTestptr, FALSE);
1869ace9065Smrg        EnableDevice(XTestkeybd, FALSE);
1879ace9065Smrg        flags[XTestptr->id] |= XIDeviceEnabled;
1889ace9065Smrg        flags[XTestkeybd->id] |= XIDeviceEnabled;
1899ace9065Smrg    }
1909ace9065Smrg
1919ace9065Smrg    /* Attach the XTest virtual devices to the newly
1929ace9065Smrg       created master device */
1939ace9065Smrg    AttachDevice(NULL, XTestptr, ptr);
1949ace9065Smrg    AttachDevice(NULL, XTestkeybd, keybd);
1959ace9065Smrg    flags[XTestptr->id] |= XISlaveAttached;
1969ace9065Smrg    flags[XTestkeybd->id] |= XISlaveAttached;
1979ace9065Smrg
1989ace9065Smrgunwind:
1999ace9065Smrg    free(name);
2009ace9065Smrg    return rc;
2019ace9065Smrg}
2029ace9065Smrg
203475c125cSmrgstatic void
204475c125cSmrgdisable_clientpointer(DeviceIntPtr dev)
205475c125cSmrg{
206475c125cSmrg    int i;
207475c125cSmrg
208475c125cSmrg    for (i = 0; i < currentMaxClients; i++)
209475c125cSmrg    {
210475c125cSmrg        ClientPtr client = clients[i];
211475c125cSmrg        if (client && client->clientPtr == dev)
212475c125cSmrg            client->clientPtr = NULL;
213475c125cSmrg    }
214475c125cSmrg}
215475c125cSmrg
2169ace9065Smrgstatic int
2179ace9065Smrgremove_master(ClientPtr client, xXIRemoveMasterInfo *r,
2189ace9065Smrg              int flags[MAXDEVICES])
2199ace9065Smrg{
2209ace9065Smrg    DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
2219ace9065Smrg    int rc = Success;
2229ace9065Smrg
2239ace9065Smrg    if (r->return_mode != XIAttachToMaster &&
2249ace9065Smrg        r->return_mode != XIFloating)
2259ace9065Smrg        return BadValue;
2269ace9065Smrg
2279ace9065Smrg    rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess);
2289ace9065Smrg    if (rc != Success)
2299ace9065Smrg        goto unwind;
2309ace9065Smrg
2319ace9065Smrg    if (!IsMaster(ptr))
2329ace9065Smrg    {
2339ace9065Smrg        client->errorValue = r->deviceid;
2349ace9065Smrg        rc = BadDevice;
2359ace9065Smrg        goto unwind;
2369ace9065Smrg    }
2379ace9065Smrg
2389ace9065Smrg    /* XXX: For now, don't allow removal of VCP, VCK */
2399ace9065Smrg    if (ptr == inputInfo.pointer || ptr == inputInfo.keyboard)
2409ace9065Smrg    {
2419ace9065Smrg        rc = BadDevice;
2429ace9065Smrg        goto unwind;
2439ace9065Smrg    }
2449ace9065Smrg
2459ace9065Smrg
2469ace9065Smrg    ptr = GetMaster(ptr, MASTER_POINTER);
2479ace9065Smrg    rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess);
2489ace9065Smrg    if (rc != Success)
2499ace9065Smrg        goto unwind;
2509ace9065Smrg    keybd = GetMaster(ptr, MASTER_KEYBOARD);
2519ace9065Smrg    rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess);
2529ace9065Smrg    if (rc != Success)
2539ace9065Smrg        goto unwind;
2549ace9065Smrg
2559ace9065Smrg    XTestptr = GetXTestDevice(ptr);
2569ace9065Smrg    rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess);
2579ace9065Smrg    if (rc != Success)
2589ace9065Smrg        goto unwind;
2599ace9065Smrg
2609ace9065Smrg    XTestkeybd = GetXTestDevice(keybd);
2619ace9065Smrg    rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client,
2629ace9065Smrg                         DixDestroyAccess);
2639ace9065Smrg    if (rc != Success)
2649ace9065Smrg        goto unwind;
2659ace9065Smrg
266475c125cSmrg    disable_clientpointer(ptr);
267475c125cSmrg
2689ace9065Smrg    /* Disabling sends the devices floating, reattach them if
2699ace9065Smrg     * desired. */
2709ace9065Smrg    if (r->return_mode == XIAttachToMaster)
2719ace9065Smrg    {
2729ace9065Smrg        DeviceIntPtr attached,
2739ace9065Smrg                     newptr,
2749ace9065Smrg                     newkeybd;
2759ace9065Smrg
2769ace9065Smrg        rc = dixLookupDevice(&newptr, r->return_pointer, client, DixAddAccess);
2779ace9065Smrg        if (rc != Success)
2789ace9065Smrg            goto unwind;
2799ace9065Smrg
2809ace9065Smrg        if (!IsMaster(newptr))
2819ace9065Smrg        {
2829ace9065Smrg            client->errorValue = r->return_pointer;
2839ace9065Smrg            rc = BadDevice;
2849ace9065Smrg            goto unwind;
2859ace9065Smrg        }
2869ace9065Smrg
2879ace9065Smrg        rc = dixLookupDevice(&newkeybd, r->return_keyboard,
2889ace9065Smrg                             client, DixAddAccess);
2899ace9065Smrg        if (rc != Success)
2909ace9065Smrg            goto unwind;
2919ace9065Smrg
2929ace9065Smrg        if (!IsMaster(newkeybd))
2939ace9065Smrg        {
2949ace9065Smrg            client->errorValue = r->return_keyboard;
2959ace9065Smrg            rc = BadDevice;
2969ace9065Smrg            goto unwind;
2979ace9065Smrg        }
2989ace9065Smrg
2999ace9065Smrg        for (attached = inputInfo.devices; attached; attached = attached->next)
3009ace9065Smrg        {
3019ace9065Smrg            if (!IsMaster(attached)) {
3029ace9065Smrg                if (attached->u.master == ptr)
3039ace9065Smrg                {
3049ace9065Smrg                    AttachDevice(client, attached, newptr);
3059ace9065Smrg                    flags[attached->id] |= XISlaveAttached;
3069ace9065Smrg                }
3079ace9065Smrg                if (attached->u.master == keybd)
3089ace9065Smrg                {
3099ace9065Smrg                    AttachDevice(client, attached, newkeybd);
3109ace9065Smrg                    flags[attached->id] |= XISlaveAttached;
3119ace9065Smrg                }
3129ace9065Smrg            }
3139ace9065Smrg        }
3149ace9065Smrg    }
3159ace9065Smrg
3169ace9065Smrg    /* can't disable until we removed pairing */
3179ace9065Smrg    keybd->spriteInfo->paired = NULL;
3189ace9065Smrg    ptr->spriteInfo->paired = NULL;
3199ace9065Smrg    XTestptr->spriteInfo->paired = NULL;
3209ace9065Smrg    XTestkeybd->spriteInfo->paired = NULL;
3219ace9065Smrg
3229ace9065Smrg    /* disable the remove the devices, XTest devices must be done first
3239ace9065Smrg       else the sprites they rely on will be destroyed  */
3249ace9065Smrg    DisableDevice(XTestptr, FALSE);
3259ace9065Smrg    DisableDevice(XTestkeybd, FALSE);
3269ace9065Smrg    DisableDevice(keybd, FALSE);
3279ace9065Smrg    DisableDevice(ptr, FALSE);
3289ace9065Smrg    flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached;
3299ace9065Smrg    flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached;
3309ace9065Smrg    flags[keybd->id] |= XIDeviceDisabled;
3319ace9065Smrg    flags[ptr->id] |= XIDeviceDisabled;
3329ace9065Smrg
3339ace9065Smrg    RemoveDevice(XTestptr, FALSE);
3349ace9065Smrg    RemoveDevice(XTestkeybd, FALSE);
3359ace9065Smrg    RemoveDevice(keybd, FALSE);
3369ace9065Smrg    RemoveDevice(ptr, FALSE);
3379ace9065Smrg    flags[XTestptr->id] |= XISlaveRemoved;
3389ace9065Smrg    flags[XTestkeybd->id] |= XISlaveRemoved;
3399ace9065Smrg    flags[keybd->id] |= XIMasterRemoved;
3409ace9065Smrg    flags[ptr->id] |= XIMasterRemoved;
3419ace9065Smrg
3429ace9065Smrgunwind:
3439ace9065Smrg    return rc;
3449ace9065Smrg}
3459ace9065Smrg
3469ace9065Smrgstatic int
3479ace9065Smrgdetach_slave(ClientPtr client, xXIDetachSlaveInfo *c, int flags[MAXDEVICES])
3489ace9065Smrg{
3499ace9065Smrg    DeviceIntPtr dev;
3509ace9065Smrg    int rc;
3519ace9065Smrg
3529ace9065Smrg    rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
3539ace9065Smrg    if (rc != Success)
3549ace9065Smrg        goto unwind;
3559ace9065Smrg
3569ace9065Smrg    if (IsMaster(dev))
3579ace9065Smrg    {
3589ace9065Smrg        client->errorValue = c->deviceid;
3599ace9065Smrg        rc = BadDevice;
3609ace9065Smrg        goto unwind;
3619ace9065Smrg    }
3629ace9065Smrg
3639ace9065Smrg    /* Don't allow changes to XTest Devices, these are fixed */
3649ace9065Smrg    if (IsXTestDevice(dev, NULL))
3659ace9065Smrg    {
3669ace9065Smrg        client->errorValue = c->deviceid;
3679ace9065Smrg        rc = BadDevice;
3689ace9065Smrg        goto unwind;
3699ace9065Smrg    }
3709ace9065Smrg
3719ace9065Smrg    ReleaseButtonsAndKeys(dev);
3729ace9065Smrg    AttachDevice(client, dev, NULL);
3739ace9065Smrg    flags[dev->id] |= XISlaveDetached;
3749ace9065Smrg
3759ace9065Smrgunwind:
3769ace9065Smrg    return rc;
3779ace9065Smrg}
3789ace9065Smrg
3799ace9065Smrgstatic int
3809ace9065Smrgattach_slave(ClientPtr client, xXIAttachSlaveInfo *c,
3819ace9065Smrg             int flags[MAXDEVICES])
3829ace9065Smrg{
3839ace9065Smrg    DeviceIntPtr dev;
3849ace9065Smrg    DeviceIntPtr newmaster;
3859ace9065Smrg    int rc;
3869ace9065Smrg
3879ace9065Smrg    rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
3889ace9065Smrg    if (rc != Success)
3899ace9065Smrg        goto unwind;
3909ace9065Smrg
3919ace9065Smrg    if (IsMaster(dev))
3929ace9065Smrg    {
3939ace9065Smrg        client->errorValue = c->deviceid;
3949ace9065Smrg        rc = BadDevice;
3959ace9065Smrg        goto unwind;
3969ace9065Smrg    }
3979ace9065Smrg
3989ace9065Smrg    /* Don't allow changes to XTest Devices, these are fixed */
3999ace9065Smrg    if (IsXTestDevice(dev, NULL))
4009ace9065Smrg    {
4019ace9065Smrg        client->errorValue = c->deviceid;
4029ace9065Smrg        rc = BadDevice;
4039ace9065Smrg        goto unwind;
4049ace9065Smrg    }
4059ace9065Smrg
4069ace9065Smrg    rc = dixLookupDevice(&newmaster, c->new_master, client, DixAddAccess);
4079ace9065Smrg    if (rc != Success)
4089ace9065Smrg        goto unwind;
4099ace9065Smrg    if (!IsMaster(newmaster))
4109ace9065Smrg    {
4119ace9065Smrg        client->errorValue = c->new_master;
4129ace9065Smrg        rc = BadDevice;
4139ace9065Smrg        goto unwind;
4149ace9065Smrg    }
4159ace9065Smrg
4169ace9065Smrg    if (!((IsPointerDevice(newmaster) && IsPointerDevice(dev)) ||
4179ace9065Smrg        (IsKeyboardDevice(newmaster) && IsKeyboardDevice(dev))))
4189ace9065Smrg    {
4199ace9065Smrg        rc = BadDevice;
4209ace9065Smrg        goto unwind;
4219ace9065Smrg    }
4229ace9065Smrg
4239ace9065Smrg    ReleaseButtonsAndKeys(dev);
4249ace9065Smrg    AttachDevice(client, dev, newmaster);
4259ace9065Smrg    flags[dev->id] |= XISlaveAttached;
4269ace9065Smrg
4279ace9065Smrgunwind:
4289ace9065Smrg    return rc;
4299ace9065Smrg}
4309ace9065Smrg
4319ace9065Smrg
4329ace9065Smrg
4336747b715Smrg#define SWAPIF(cmd) if (client->swapped) { cmd; }
4346747b715Smrg
4356747b715Smrgint
4366747b715SmrgProcXIChangeHierarchy(ClientPtr client)
4376747b715Smrg{
4386747b715Smrg    xXIAnyHierarchyChangeInfo *any;
4390b0d8713Smrg    size_t len;			/* length of data remaining in request */
4406747b715Smrg    char n;
4416747b715Smrg    int rc = Success;
4426747b715Smrg    int flags[MAXDEVICES] = {0};
4436747b715Smrg
4446747b715Smrg    REQUEST(xXIChangeHierarchyReq);
4456747b715Smrg    REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq);
4466747b715Smrg
4476747b715Smrg    if (!stuff->num_changes)
4486747b715Smrg        return rc;
4496747b715Smrg
4500b0d8713Smrg    if (stuff->length > (INT_MAX >> 2))
4510b0d8713Smrg        return BadAlloc;
4520b0d8713Smrg    len = (stuff->length << 2) - sizeof(xXIAnyHierarchyChangeInfo);
4530b0d8713Smrg
4546747b715Smrg    any = (xXIAnyHierarchyChangeInfo*)&stuff[1];
4556747b715Smrg    while(stuff->num_changes--)
4566747b715Smrg    {
4570b0d8713Smrg        if (len < sizeof(xXIAnyHierarchyChangeInfo)) {
4580b0d8713Smrg            rc = BadLength;
4590b0d8713Smrg            goto unwind;
4600b0d8713Smrg        }
4610b0d8713Smrg
4626747b715Smrg        SWAPIF(swapl(&any->type, n));
4636747b715Smrg        SWAPIF(swaps(&any->length, n));
4646747b715Smrg
4650b0d8713Smrg        if ((any->length > (INT_MAX >> 2)) || (len < (any->length << 2)))
4666747b715Smrg            return BadLength;
4676747b715Smrg
4680b0d8713Smrg#define CHANGE_SIZE_MATCH(type) \
4690b0d8713Smrg    do { \
4700b0d8713Smrg        if ((len < sizeof(type)) || (any->length != (sizeof(type) >> 2))) { \
4710b0d8713Smrg            rc = BadLength; \
4720b0d8713Smrg            goto unwind; \
4730b0d8713Smrg        } \
4740b0d8713Smrg    } while(0)
4750b0d8713Smrg
4766747b715Smrg        switch(any->type)
4776747b715Smrg        {
4786747b715Smrg            case XIAddMaster:
4796747b715Smrg                {
4806747b715Smrg                    xXIAddMasterInfo* c = (xXIAddMasterInfo*)any;
4810b0d8713Smrg	            /* Variable length, due to appended name string */
4820b0d8713Smrg	            if (len < sizeof(xXIAddMasterInfo)) {
4830b0d8713Smrg	                rc = BadLength;
4840b0d8713Smrg	                goto unwind;
4850b0d8713Smrg	            }
4866747b715Smrg                    SWAPIF(swaps(&c->name_len, n));
4870b0d8713Smrg	            if (c->name_len > (len - sizeof(xXIAddMasterInfo))) {
4880b0d8713Smrg	                rc = BadLength;
4890b0d8713Smrg	                goto unwind;
4900b0d8713Smrg	            }
4916747b715Smrg
4929ace9065Smrg                    rc = add_master(client, c, flags);
4936747b715Smrg                    if (rc != Success)
4946747b715Smrg                        goto unwind;
4956747b715Smrg                }
4966747b715Smrg                break;
4976747b715Smrg            case XIRemoveMaster:
4986747b715Smrg                {
4996747b715Smrg                    xXIRemoveMasterInfo* r = (xXIRemoveMasterInfo*)any;
5006747b715Smrg
5010b0d8713Smrg	            CHANGE_SIZE_MATCH(xXIRemoveMasterInfo);
5029ace9065Smrg                    rc = remove_master(client, r, flags);
5036747b715Smrg                    if (rc != Success)
5046747b715Smrg                        goto unwind;
5056747b715Smrg                }
5066747b715Smrg                break;
5076747b715Smrg            case XIDetachSlave:
5086747b715Smrg                {
5096747b715Smrg                    xXIDetachSlaveInfo* c = (xXIDetachSlaveInfo*)any;
5106747b715Smrg
5110b0d8713Smrg	            CHANGE_SIZE_MATCH(xXIDetachSlaveInfo);
5129ace9065Smrg                    rc = detach_slave(client, c, flags);
5136747b715Smrg                    if (rc != Success)
5146747b715Smrg                       goto unwind;
5156747b715Smrg                }
5166747b715Smrg                break;
5176747b715Smrg            case XIAttachSlave:
5186747b715Smrg                {
5196747b715Smrg                    xXIAttachSlaveInfo* c = (xXIAttachSlaveInfo*)any;
5206747b715Smrg
5210b0d8713Smrg	            CHANGE_SIZE_MATCH(xXIAttachSlaveInfo);
5229ace9065Smrg                    rc = attach_slave(client, c, flags);
5236747b715Smrg                    if (rc != Success)
5246747b715Smrg                       goto unwind;
5256747b715Smrg                }
5266747b715Smrg                break;
5276747b715Smrg        }
5286747b715Smrg
5290b0d8713Smrg        len -= any->length * 4;
5306747b715Smrg        any = (xXIAnyHierarchyChangeInfo*)((char*)any + any->length * 4);
5316747b715Smrg    }
5326747b715Smrg
5336747b715Smrgunwind:
5346747b715Smrg
5356747b715Smrg    XISendDeviceHierarchyEvent(flags);
5366747b715Smrg    return rc;
5376747b715Smrg}
5386747b715Smrg
539