xichangehierarchy.c revision f7df2e56
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#ifdef HAVE_DIX_CONFIG_H
346747b715Smrg#include <dix-config.h>
356747b715Smrg#endif
366747b715Smrg
37f7df2e56Smrg#include <X11/X.h>              /* for inputstr.h    */
38f7df2e56Smrg#include <X11/Xproto.h>         /* Request macro     */
39f7df2e56Smrg#include "inputstr.h"           /* DeviceIntPtr      */
40f7df2e56Smrg#include "windowstr.h"          /* window structure  */
41f7df2e56Smrg#include "scrnintstr.h"         /* screen structure  */
426747b715Smrg#include <X11/extensions/XI.h>
436747b715Smrg#include <X11/extensions/XI2proto.h>
446747b715Smrg#include <X11/extensions/geproto.h>
456747b715Smrg#include "extnsionst.h"
466747b715Smrg#include "exevents.h"
476747b715Smrg#include "exglobals.h"
486747b715Smrg#include "geext.h"
496747b715Smrg#include "xace.h"
50f7df2e56Smrg#include "xiquerydevice.h"      /* for GetDeviceUse */
516747b715Smrg
526747b715Smrg#include "xkbsrv.h"
536747b715Smrg
546747b715Smrg#include "xichangehierarchy.h"
55f7df2e56Smrg#include "xibarriers.h"
566747b715Smrg
576747b715Smrg/**
586747b715Smrg * Send the current state of the device hierarchy to all clients.
596747b715Smrg */
60f7df2e56Smrgvoid
61f7df2e56SmrgXISendDeviceHierarchyEvent(int flags[MAXDEVICES])
626747b715Smrg{
636747b715Smrg    xXIHierarchyEvent *ev;
646747b715Smrg    xXIHierarchyInfo *info;
656747b715Smrg    DeviceIntRec dummyDev;
666747b715Smrg    DeviceIntPtr dev;
676747b715Smrg    int i;
686747b715Smrg
696747b715Smrg    if (!flags)
706747b715Smrg        return;
716747b715Smrg
726747b715Smrg    ev = calloc(1, sizeof(xXIHierarchyEvent) +
73f7df2e56Smrg                MAXDEVICES * sizeof(xXIHierarchyInfo));
749ace9065Smrg    if (!ev)
759ace9065Smrg        return;
766747b715Smrg    ev->type = GenericEvent;
776747b715Smrg    ev->extension = IReqCode;
786747b715Smrg    ev->evtype = XI_HierarchyChanged;
796747b715Smrg    ev->time = GetTimeInMillis();
806747b715Smrg    ev->flags = 0;
816747b715Smrg    ev->num_info = inputInfo.numDevices;
826747b715Smrg
83f7df2e56Smrg    info = (xXIHierarchyInfo *) &ev[1];
84f7df2e56Smrg    for (dev = inputInfo.devices; dev; dev = dev->next) {
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    }
92f7df2e56Smrg    for (dev = inputInfo.off_devices; dev; dev = dev->next) {
936747b715Smrg        info->deviceid = dev->id;
946747b715Smrg        info->enabled = dev->enabled;
956747b715Smrg        info->use = GetDeviceUse(dev, &info->attachment);
966747b715Smrg        info->flags = flags[dev->id];
976747b715Smrg        ev->flags |= info->flags;
986747b715Smrg        info++;
996747b715Smrg    }
1006747b715Smrg
101f7df2e56Smrg    for (i = 0; i < MAXDEVICES; i++) {
102f7df2e56Smrg        if (flags[i] & (XIMasterRemoved | XISlaveRemoved)) {
1036747b715Smrg            info->deviceid = i;
1046747b715Smrg            info->enabled = FALSE;
1056747b715Smrg            info->flags = flags[i];
1066747b715Smrg            info->use = 0;
1076747b715Smrg            ev->flags |= info->flags;
1086747b715Smrg            ev->num_info++;
1096747b715Smrg            info++;
1106747b715Smrg        }
1116747b715Smrg    }
1126747b715Smrg
1136747b715Smrg    ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo));
1146747b715Smrg
115f7df2e56Smrg    memset(&dummyDev, 0, sizeof(dummyDev));
1166747b715Smrg    dummyDev.id = XIAllDevices;
117f7df2e56Smrg    dummyDev.type = SLAVE;
118f7df2e56Smrg    SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8),
119f7df2e56Smrg                          (xEvent *) ev, 1);
1206747b715Smrg    free(ev);
1216747b715Smrg}
1226747b715Smrg
1236747b715Smrg/***********************************************************************
1246747b715Smrg *
1256747b715Smrg * This procedure allows a client to change the device hierarchy through
1266747b715Smrg * adding new master devices, removing them, etc.
1276747b715Smrg *
1286747b715Smrg */
1296747b715Smrg
130f7df2e56Smrgint
131f7df2e56SmrgSProcXIChangeHierarchy(ClientPtr client)
1326747b715Smrg{
1336747b715Smrg    REQUEST(xXIChangeHierarchyReq);
134f7df2e56Smrg    swaps(&stuff->length);
1356747b715Smrg    return (ProcXIChangeHierarchy(client));
1366747b715Smrg}
1376747b715Smrg
1389ace9065Smrgstatic int
139f7df2e56Smrgadd_master(ClientPtr client, xXIAddMasterInfo * c, int flags[MAXDEVICES])
1409ace9065Smrg{
1419ace9065Smrg    DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
142f7df2e56Smrg    char *name;
1439ace9065Smrg    int rc;
1449ace9065Smrg
1459ace9065Smrg    name = calloc(c->name_len + 1, sizeof(char));
146f7df2e56Smrg    if (name == NULL) {
147f7df2e56Smrg        rc = BadAlloc;
148f7df2e56Smrg        goto unwind;
149f7df2e56Smrg    }
150f7df2e56Smrg    strncpy(name, (char *) &c[1], c->name_len);
1519ace9065Smrg
1529ace9065Smrg    rc = AllocDevicePair(client, name, &ptr, &keybd,
1539ace9065Smrg                         CorePointerProc, CoreKeyboardProc, TRUE);
1549ace9065Smrg    if (rc != Success)
1559ace9065Smrg        goto unwind;
1569ace9065Smrg
1579ace9065Smrg    if (!c->send_core)
158f7df2e56Smrg        ptr->coreEvents = keybd->coreEvents = FALSE;
1599ace9065Smrg
1609ace9065Smrg    /* Allocate virtual slave devices for xtest events */
1619ace9065Smrg    rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, ptr, keybd);
162f7df2e56Smrg    if (rc != Success) {
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
178f7df2e56Smrg    if (c->enable) {
1799ace9065Smrg        EnableDevice(ptr, FALSE);
1809ace9065Smrg        EnableDevice(keybd, FALSE);
1819ace9065Smrg        flags[ptr->id] |= XIDeviceEnabled;
1829ace9065Smrg        flags[keybd->id] |= XIDeviceEnabled;
1839ace9065Smrg
1849ace9065Smrg        EnableDevice(XTestptr, FALSE);
1859ace9065Smrg        EnableDevice(XTestkeybd, FALSE);
1869ace9065Smrg        flags[XTestptr->id] |= XIDeviceEnabled;
1879ace9065Smrg        flags[XTestkeybd->id] |= XIDeviceEnabled;
1889ace9065Smrg    }
1899ace9065Smrg
1909ace9065Smrg    /* Attach the XTest virtual devices to the newly
1919ace9065Smrg       created master device */
1929ace9065Smrg    AttachDevice(NULL, XTestptr, ptr);
1939ace9065Smrg    AttachDevice(NULL, XTestkeybd, keybd);
1949ace9065Smrg    flags[XTestptr->id] |= XISlaveAttached;
1959ace9065Smrg    flags[XTestkeybd->id] |= XISlaveAttached;
1969ace9065Smrg
197f7df2e56Smrg    XIBarrierNewMasterDevice(client, ptr->id);
198f7df2e56Smrg
199f7df2e56Smrg unwind:
2009ace9065Smrg    free(name);
2019ace9065Smrg    return rc;
2029ace9065Smrg}
2039ace9065Smrg
204475c125cSmrgstatic void
205475c125cSmrgdisable_clientpointer(DeviceIntPtr dev)
206475c125cSmrg{
207475c125cSmrg    int i;
208475c125cSmrg
209f7df2e56Smrg    for (i = 0; i < currentMaxClients; i++) {
210475c125cSmrg        ClientPtr client = clients[i];
211f7df2e56Smrg
212475c125cSmrg        if (client && client->clientPtr == dev)
213475c125cSmrg            client->clientPtr = NULL;
214475c125cSmrg    }
215475c125cSmrg}
216475c125cSmrg
2179ace9065Smrgstatic int
218f7df2e56Smrgremove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES])
2199ace9065Smrg{
2209ace9065Smrg    DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
2219ace9065Smrg    int rc = Success;
2229ace9065Smrg
223f7df2e56Smrg    if (r->return_mode != XIAttachToMaster && r->return_mode != XIFloating)
2249ace9065Smrg        return BadValue;
2259ace9065Smrg
2269ace9065Smrg    rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess);
2279ace9065Smrg    if (rc != Success)
2289ace9065Smrg        goto unwind;
2299ace9065Smrg
230f7df2e56Smrg    if (!IsMaster(ptr)) {
2319ace9065Smrg        client->errorValue = r->deviceid;
2329ace9065Smrg        rc = BadDevice;
2339ace9065Smrg        goto unwind;
2349ace9065Smrg    }
2359ace9065Smrg
2369ace9065Smrg    /* XXX: For now, don't allow removal of VCP, VCK */
237f7df2e56Smrg    if (ptr == inputInfo.pointer ||ptr == inputInfo.keyboard) {
2389ace9065Smrg        rc = BadDevice;
2399ace9065Smrg        goto unwind;
2409ace9065Smrg    }
2419ace9065Smrg
2429ace9065Smrg    ptr = GetMaster(ptr, MASTER_POINTER);
2439ace9065Smrg    rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess);
2449ace9065Smrg    if (rc != Success)
2459ace9065Smrg        goto unwind;
2469ace9065Smrg    keybd = GetMaster(ptr, MASTER_KEYBOARD);
2479ace9065Smrg    rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess);
2489ace9065Smrg    if (rc != Success)
2499ace9065Smrg        goto unwind;
2509ace9065Smrg
2519ace9065Smrg    XTestptr = GetXTestDevice(ptr);
2529ace9065Smrg    rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess);
2539ace9065Smrg    if (rc != Success)
2549ace9065Smrg        goto unwind;
2559ace9065Smrg
2569ace9065Smrg    XTestkeybd = GetXTestDevice(keybd);
257f7df2e56Smrg    rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, DixDestroyAccess);
2589ace9065Smrg    if (rc != Success)
2599ace9065Smrg        goto unwind;
2609ace9065Smrg
261475c125cSmrg    disable_clientpointer(ptr);
262475c125cSmrg
2639ace9065Smrg    /* Disabling sends the devices floating, reattach them if
2649ace9065Smrg     * desired. */
265f7df2e56Smrg    if (r->return_mode == XIAttachToMaster) {
266f7df2e56Smrg        DeviceIntPtr attached, newptr, newkeybd;
2679ace9065Smrg
2689ace9065Smrg        rc = dixLookupDevice(&newptr, r->return_pointer, client, DixAddAccess);
2699ace9065Smrg        if (rc != Success)
2709ace9065Smrg            goto unwind;
2719ace9065Smrg
272f7df2e56Smrg        if (!IsMaster(newptr)) {
2739ace9065Smrg            client->errorValue = r->return_pointer;
2749ace9065Smrg            rc = BadDevice;
2759ace9065Smrg            goto unwind;
2769ace9065Smrg        }
2779ace9065Smrg
2789ace9065Smrg        rc = dixLookupDevice(&newkeybd, r->return_keyboard,
2799ace9065Smrg                             client, DixAddAccess);
2809ace9065Smrg        if (rc != Success)
2819ace9065Smrg            goto unwind;
2829ace9065Smrg
283f7df2e56Smrg        if (!IsMaster(newkeybd)) {
2849ace9065Smrg            client->errorValue = r->return_keyboard;
2859ace9065Smrg            rc = BadDevice;
2869ace9065Smrg            goto unwind;
2879ace9065Smrg        }
2889ace9065Smrg
289f7df2e56Smrg        for (attached = inputInfo.devices; attached; attached = attached->next) {
2909ace9065Smrg            if (!IsMaster(attached)) {
291f7df2e56Smrg                if (GetMaster(attached, MASTER_ATTACHED) == ptr) {
2929ace9065Smrg                    AttachDevice(client, attached, newptr);
2939ace9065Smrg                    flags[attached->id] |= XISlaveAttached;
2949ace9065Smrg                }
295f7df2e56Smrg                if (GetMaster(attached, MASTER_ATTACHED) == keybd) {
2969ace9065Smrg                    AttachDevice(client, attached, newkeybd);
2979ace9065Smrg                    flags[attached->id] |= XISlaveAttached;
2989ace9065Smrg                }
2999ace9065Smrg            }
3009ace9065Smrg        }
3019ace9065Smrg    }
3029ace9065Smrg
303f7df2e56Smrg    XIBarrierRemoveMasterDevice(client, ptr->id);
3049ace9065Smrg
3059ace9065Smrg    /* disable the remove the devices, XTest devices must be done first
3069ace9065Smrg       else the sprites they rely on will be destroyed  */
3079ace9065Smrg    DisableDevice(XTestptr, FALSE);
3089ace9065Smrg    DisableDevice(XTestkeybd, FALSE);
3099ace9065Smrg    DisableDevice(keybd, FALSE);
3109ace9065Smrg    DisableDevice(ptr, FALSE);
3119ace9065Smrg    flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached;
3129ace9065Smrg    flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached;
3139ace9065Smrg    flags[keybd->id] |= XIDeviceDisabled;
3149ace9065Smrg    flags[ptr->id] |= XIDeviceDisabled;
3159ace9065Smrg
3169ace9065Smrg    flags[XTestptr->id] |= XISlaveRemoved;
3179ace9065Smrg    flags[XTestkeybd->id] |= XISlaveRemoved;
3189ace9065Smrg    flags[keybd->id] |= XIMasterRemoved;
3199ace9065Smrg    flags[ptr->id] |= XIMasterRemoved;
3209ace9065Smrg
321f7df2e56Smrg    RemoveDevice(XTestptr, FALSE);
322f7df2e56Smrg    RemoveDevice(XTestkeybd, FALSE);
323f7df2e56Smrg    RemoveDevice(keybd, FALSE);
324f7df2e56Smrg    RemoveDevice(ptr, FALSE);
325f7df2e56Smrg
326f7df2e56Smrg unwind:
3279ace9065Smrg    return rc;
3289ace9065Smrg}
3299ace9065Smrg
3309ace9065Smrgstatic int
331f7df2e56Smrgdetach_slave(ClientPtr client, xXIDetachSlaveInfo * c, int flags[MAXDEVICES])
3329ace9065Smrg{
3339ace9065Smrg    DeviceIntPtr dev;
3349ace9065Smrg    int rc;
3359ace9065Smrg
3369ace9065Smrg    rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
3379ace9065Smrg    if (rc != Success)
3389ace9065Smrg        goto unwind;
3399ace9065Smrg
340f7df2e56Smrg    if (IsMaster(dev)) {
3419ace9065Smrg        client->errorValue = c->deviceid;
3429ace9065Smrg        rc = BadDevice;
3439ace9065Smrg        goto unwind;
3449ace9065Smrg    }
3459ace9065Smrg
3469ace9065Smrg    /* Don't allow changes to XTest Devices, these are fixed */
347f7df2e56Smrg    if (IsXTestDevice(dev, NULL)) {
3489ace9065Smrg        client->errorValue = c->deviceid;
3499ace9065Smrg        rc = BadDevice;
3509ace9065Smrg        goto unwind;
3519ace9065Smrg    }
3529ace9065Smrg
3539ace9065Smrg    ReleaseButtonsAndKeys(dev);
3549ace9065Smrg    AttachDevice(client, dev, NULL);
3559ace9065Smrg    flags[dev->id] |= XISlaveDetached;
3569ace9065Smrg
357f7df2e56Smrg unwind:
3589ace9065Smrg    return rc;
3599ace9065Smrg}
3609ace9065Smrg
3619ace9065Smrgstatic int
362f7df2e56Smrgattach_slave(ClientPtr client, xXIAttachSlaveInfo * c, int flags[MAXDEVICES])
3639ace9065Smrg{
3649ace9065Smrg    DeviceIntPtr dev;
3659ace9065Smrg    DeviceIntPtr newmaster;
3669ace9065Smrg    int rc;
3679ace9065Smrg
3689ace9065Smrg    rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
3699ace9065Smrg    if (rc != Success)
3709ace9065Smrg        goto unwind;
3719ace9065Smrg
372f7df2e56Smrg    if (IsMaster(dev)) {
3739ace9065Smrg        client->errorValue = c->deviceid;
3749ace9065Smrg        rc = BadDevice;
3759ace9065Smrg        goto unwind;
3769ace9065Smrg    }
3779ace9065Smrg
3789ace9065Smrg    /* Don't allow changes to XTest Devices, these are fixed */
379f7df2e56Smrg    if (IsXTestDevice(dev, NULL)) {
3809ace9065Smrg        client->errorValue = c->deviceid;
3819ace9065Smrg        rc = BadDevice;
3829ace9065Smrg        goto unwind;
3839ace9065Smrg    }
3849ace9065Smrg
3859ace9065Smrg    rc = dixLookupDevice(&newmaster, c->new_master, client, DixAddAccess);
3869ace9065Smrg    if (rc != Success)
3879ace9065Smrg        goto unwind;
388f7df2e56Smrg    if (!IsMaster(newmaster)) {
3899ace9065Smrg        client->errorValue = c->new_master;
3909ace9065Smrg        rc = BadDevice;
3919ace9065Smrg        goto unwind;
3929ace9065Smrg    }
3939ace9065Smrg
3949ace9065Smrg    if (!((IsPointerDevice(newmaster) && IsPointerDevice(dev)) ||
395f7df2e56Smrg          (IsKeyboardDevice(newmaster) && IsKeyboardDevice(dev)))) {
3969ace9065Smrg        rc = BadDevice;
3979ace9065Smrg        goto unwind;
3989ace9065Smrg    }
3999ace9065Smrg
4009ace9065Smrg    ReleaseButtonsAndKeys(dev);
4019ace9065Smrg    AttachDevice(client, dev, newmaster);
4029ace9065Smrg    flags[dev->id] |= XISlaveAttached;
4039ace9065Smrg
404f7df2e56Smrg unwind:
4059ace9065Smrg    return rc;
4069ace9065Smrg}
4079ace9065Smrg
4086747b715Smrg#define SWAPIF(cmd) if (client->swapped) { cmd; }
4096747b715Smrg
4106747b715Smrgint
4116747b715SmrgProcXIChangeHierarchy(ClientPtr client)
4126747b715Smrg{
4136747b715Smrg    xXIAnyHierarchyChangeInfo *any;
4140b0d8713Smrg    size_t len;			/* length of data remaining in request */
4156747b715Smrg    int rc = Success;
416f7df2e56Smrg    int flags[MAXDEVICES] = { 0 };
4176747b715Smrg
4186747b715Smrg    REQUEST(xXIChangeHierarchyReq);
4196747b715Smrg    REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq);
4206747b715Smrg
4216747b715Smrg    if (!stuff->num_changes)
4226747b715Smrg        return rc;
4236747b715Smrg
424f7df2e56Smrg#if 0
4250b0d8713Smrg    if (stuff->length > (INT_MAX >> 2))
4260b0d8713Smrg        return BadAlloc;
427f7df2e56Smrg#endif
428f7df2e56Smrg    len = ((size_t)stuff->length << 2) - sizeof(xXIAnyHierarchyChangeInfo);
4290b0d8713Smrg
430f7df2e56Smrg    any = (xXIAnyHierarchyChangeInfo *) &stuff[1];
431f7df2e56Smrg    while (stuff->num_changes--) {
4320b0d8713Smrg        if (len < sizeof(xXIAnyHierarchyChangeInfo)) {
4330b0d8713Smrg            rc = BadLength;
4340b0d8713Smrg            goto unwind;
4350b0d8713Smrg        }
4360b0d8713Smrg
437f7df2e56Smrg        SWAPIF(swaps(&any->type));
438f7df2e56Smrg        SWAPIF(swaps(&any->length));
4396747b715Smrg
440f7df2e56Smrg        if (len < ((size_t)any->length << 2))
4416747b715Smrg            return BadLength;
4426747b715Smrg
4430b0d8713Smrg#define CHANGE_SIZE_MATCH(type) \
4440b0d8713Smrg    do { \
4450b0d8713Smrg        if ((len < sizeof(type)) || (any->length != (sizeof(type) >> 2))) { \
4460b0d8713Smrg            rc = BadLength; \
4470b0d8713Smrg            goto unwind; \
4480b0d8713Smrg        } \
4490b0d8713Smrg    } while(0)
4500b0d8713Smrg
451f7df2e56Smrg        switch (any->type) {
452f7df2e56Smrg        case XIAddMaster:
4536747b715Smrg        {
454f7df2e56Smrg            xXIAddMasterInfo *c = (xXIAddMasterInfo *) any;
455f7df2e56Smrg
456f7df2e56Smrg            /* Variable length, due to appended name string */
457f7df2e56Smrg            if (len < sizeof(xXIAddMasterInfo)) {
458f7df2e56Smrg                rc = BadLength;
459f7df2e56Smrg                goto unwind;
460f7df2e56Smrg            }
461f7df2e56Smrg            SWAPIF(swaps(&c->name_len));
462f7df2e56Smrg            if (c->name_len > (len - sizeof(xXIAddMasterInfo))) {
463f7df2e56Smrg                rc = BadLength;
464f7df2e56Smrg                goto unwind;
465f7df2e56Smrg            }
466f7df2e56Smrg
467f7df2e56Smrg            rc = add_master(client, c, flags);
468f7df2e56Smrg            if (rc != Success)
469f7df2e56Smrg                goto unwind;
470f7df2e56Smrg        }
471f7df2e56Smrg            break;
472f7df2e56Smrg        case XIRemoveMaster:
473f7df2e56Smrg        {
474f7df2e56Smrg            xXIRemoveMasterInfo *r = (xXIRemoveMasterInfo *) any;
475f7df2e56Smrg
476f7df2e56Smrg            CHANGE_SIZE_MATCH(xXIRemoveMasterInfo);
477f7df2e56Smrg            rc = remove_master(client, r, flags);
478f7df2e56Smrg            if (rc != Success)
479f7df2e56Smrg                goto unwind;
480f7df2e56Smrg        }
481f7df2e56Smrg            break;
482f7df2e56Smrg        case XIDetachSlave:
483f7df2e56Smrg        {
484f7df2e56Smrg            xXIDetachSlaveInfo *c = (xXIDetachSlaveInfo *) any;
485f7df2e56Smrg
486f7df2e56Smrg            CHANGE_SIZE_MATCH(xXIDetachSlaveInfo);
487f7df2e56Smrg            rc = detach_slave(client, c, flags);
488f7df2e56Smrg            if (rc != Success)
489f7df2e56Smrg                goto unwind;
490f7df2e56Smrg        }
491f7df2e56Smrg            break;
492f7df2e56Smrg        case XIAttachSlave:
493f7df2e56Smrg        {
494f7df2e56Smrg            xXIAttachSlaveInfo *c = (xXIAttachSlaveInfo *) any;
495f7df2e56Smrg
496f7df2e56Smrg            CHANGE_SIZE_MATCH(xXIAttachSlaveInfo);
497f7df2e56Smrg            rc = attach_slave(client, c, flags);
498f7df2e56Smrg            if (rc != Success)
499f7df2e56Smrg                goto unwind;
500f7df2e56Smrg        }
501f7df2e56Smrg            break;
5026747b715Smrg        }
5036747b715Smrg
5040b0d8713Smrg        len -= any->length * 4;
505f7df2e56Smrg        any = (xXIAnyHierarchyChangeInfo *) ((char *) any + any->length * 4);
5066747b715Smrg    }
5076747b715Smrg
508f7df2e56Smrg unwind:
5096747b715Smrg
5106747b715Smrg    XISendDeviceHierarchyEvent(flags);
5116747b715Smrg    return rc;
5126747b715Smrg}
513