xichangehierarchy.c revision 806e81e9
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
1307e31ba66Smrgint _X_COLD
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
1977e31ba66Smrg    for (int i = 0; i < currentMaxClients; i++)
1987e31ba66Smrg        XIBarrierNewMasterDevice(clients[i], ptr->id);
199f7df2e56Smrg
200f7df2e56Smrg unwind:
2019ace9065Smrg    free(name);
2029ace9065Smrg    return rc;
2039ace9065Smrg}
2049ace9065Smrg
205475c125cSmrgstatic void
206475c125cSmrgdisable_clientpointer(DeviceIntPtr dev)
207475c125cSmrg{
208475c125cSmrg    int i;
209475c125cSmrg
210f7df2e56Smrg    for (i = 0; i < currentMaxClients; i++) {
211475c125cSmrg        ClientPtr client = clients[i];
212f7df2e56Smrg
213475c125cSmrg        if (client && client->clientPtr == dev)
214475c125cSmrg            client->clientPtr = NULL;
215475c125cSmrg    }
216475c125cSmrg}
217475c125cSmrg
2189ace9065Smrgstatic int
219f7df2e56Smrgremove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES])
2209ace9065Smrg{
2219ace9065Smrg    DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
2229ace9065Smrg    int rc = Success;
2239ace9065Smrg
224f7df2e56Smrg    if (r->return_mode != XIAttachToMaster && r->return_mode != XIFloating)
2259ace9065Smrg        return BadValue;
2269ace9065Smrg
2279ace9065Smrg    rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess);
2289ace9065Smrg    if (rc != Success)
2299ace9065Smrg        goto unwind;
2309ace9065Smrg
231f7df2e56Smrg    if (!IsMaster(ptr)) {
2329ace9065Smrg        client->errorValue = r->deviceid;
2339ace9065Smrg        rc = BadDevice;
2349ace9065Smrg        goto unwind;
2359ace9065Smrg    }
2369ace9065Smrg
2379ace9065Smrg    /* XXX: For now, don't allow removal of VCP, VCK */
238f7df2e56Smrg    if (ptr == inputInfo.pointer ||ptr == inputInfo.keyboard) {
2399ace9065Smrg        rc = BadDevice;
2409ace9065Smrg        goto unwind;
2419ace9065Smrg    }
2429ace9065Smrg
2439ace9065Smrg    ptr = GetMaster(ptr, MASTER_POINTER);
2449ace9065Smrg    rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess);
2459ace9065Smrg    if (rc != Success)
2469ace9065Smrg        goto unwind;
2479ace9065Smrg    keybd = GetMaster(ptr, MASTER_KEYBOARD);
2489ace9065Smrg    rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess);
2499ace9065Smrg    if (rc != Success)
2509ace9065Smrg        goto unwind;
2519ace9065Smrg
2529ace9065Smrg    XTestptr = GetXTestDevice(ptr);
2539ace9065Smrg    rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess);
2549ace9065Smrg    if (rc != Success)
2559ace9065Smrg        goto unwind;
2569ace9065Smrg
2579ace9065Smrg    XTestkeybd = GetXTestDevice(keybd);
258f7df2e56Smrg    rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, DixDestroyAccess);
2599ace9065Smrg    if (rc != Success)
2609ace9065Smrg        goto unwind;
2619ace9065Smrg
262475c125cSmrg    disable_clientpointer(ptr);
263475c125cSmrg
2649ace9065Smrg    /* Disabling sends the devices floating, reattach them if
2659ace9065Smrg     * desired. */
266f7df2e56Smrg    if (r->return_mode == XIAttachToMaster) {
267f7df2e56Smrg        DeviceIntPtr attached, newptr, newkeybd;
2689ace9065Smrg
2699ace9065Smrg        rc = dixLookupDevice(&newptr, r->return_pointer, client, DixAddAccess);
2709ace9065Smrg        if (rc != Success)
2719ace9065Smrg            goto unwind;
2729ace9065Smrg
273f7df2e56Smrg        if (!IsMaster(newptr)) {
2749ace9065Smrg            client->errorValue = r->return_pointer;
2759ace9065Smrg            rc = BadDevice;
2769ace9065Smrg            goto unwind;
2779ace9065Smrg        }
2789ace9065Smrg
2799ace9065Smrg        rc = dixLookupDevice(&newkeybd, r->return_keyboard,
2809ace9065Smrg                             client, DixAddAccess);
2819ace9065Smrg        if (rc != Success)
2829ace9065Smrg            goto unwind;
2839ace9065Smrg
284f7df2e56Smrg        if (!IsMaster(newkeybd)) {
2859ace9065Smrg            client->errorValue = r->return_keyboard;
2869ace9065Smrg            rc = BadDevice;
2879ace9065Smrg            goto unwind;
2889ace9065Smrg        }
2899ace9065Smrg
290f7df2e56Smrg        for (attached = inputInfo.devices; attached; attached = attached->next) {
2919ace9065Smrg            if (!IsMaster(attached)) {
292f7df2e56Smrg                if (GetMaster(attached, MASTER_ATTACHED) == ptr) {
2939ace9065Smrg                    AttachDevice(client, attached, newptr);
2949ace9065Smrg                    flags[attached->id] |= XISlaveAttached;
2959ace9065Smrg                }
296f7df2e56Smrg                if (GetMaster(attached, MASTER_ATTACHED) == keybd) {
2979ace9065Smrg                    AttachDevice(client, attached, newkeybd);
2989ace9065Smrg                    flags[attached->id] |= XISlaveAttached;
2999ace9065Smrg                }
3009ace9065Smrg            }
3019ace9065Smrg        }
3029ace9065Smrg    }
3039ace9065Smrg
3047e31ba66Smrg    for (int i = 0; i < currentMaxClients; i++)
3057e31ba66Smrg        XIBarrierRemoveMasterDevice(clients[i], ptr->id);
3069ace9065Smrg
3079ace9065Smrg    /* disable the remove the devices, XTest devices must be done first
3089ace9065Smrg       else the sprites they rely on will be destroyed  */
3099ace9065Smrg    DisableDevice(XTestptr, FALSE);
3109ace9065Smrg    DisableDevice(XTestkeybd, FALSE);
3119ace9065Smrg    DisableDevice(keybd, FALSE);
3129ace9065Smrg    DisableDevice(ptr, FALSE);
3139ace9065Smrg    flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached;
3149ace9065Smrg    flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached;
3159ace9065Smrg    flags[keybd->id] |= XIDeviceDisabled;
3169ace9065Smrg    flags[ptr->id] |= XIDeviceDisabled;
3179ace9065Smrg
3189ace9065Smrg    flags[XTestptr->id] |= XISlaveRemoved;
3199ace9065Smrg    flags[XTestkeybd->id] |= XISlaveRemoved;
3209ace9065Smrg    flags[keybd->id] |= XIMasterRemoved;
3219ace9065Smrg    flags[ptr->id] |= XIMasterRemoved;
3229ace9065Smrg
323f7df2e56Smrg    RemoveDevice(XTestptr, FALSE);
324f7df2e56Smrg    RemoveDevice(XTestkeybd, FALSE);
325f7df2e56Smrg    RemoveDevice(keybd, FALSE);
326f7df2e56Smrg    RemoveDevice(ptr, FALSE);
327f7df2e56Smrg
328f7df2e56Smrg unwind:
3299ace9065Smrg    return rc;
3309ace9065Smrg}
3319ace9065Smrg
3329ace9065Smrgstatic int
333f7df2e56Smrgdetach_slave(ClientPtr client, xXIDetachSlaveInfo * c, int flags[MAXDEVICES])
3349ace9065Smrg{
3359ace9065Smrg    DeviceIntPtr dev;
3369ace9065Smrg    int rc;
3379ace9065Smrg
3389ace9065Smrg    rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
3399ace9065Smrg    if (rc != Success)
3409ace9065Smrg        goto unwind;
3419ace9065Smrg
342f7df2e56Smrg    if (IsMaster(dev)) {
3439ace9065Smrg        client->errorValue = c->deviceid;
3449ace9065Smrg        rc = BadDevice;
3459ace9065Smrg        goto unwind;
3469ace9065Smrg    }
3479ace9065Smrg
3489ace9065Smrg    /* Don't allow changes to XTest Devices, these are fixed */
349f7df2e56Smrg    if (IsXTestDevice(dev, NULL)) {
3509ace9065Smrg        client->errorValue = c->deviceid;
3519ace9065Smrg        rc = BadDevice;
3529ace9065Smrg        goto unwind;
3539ace9065Smrg    }
3549ace9065Smrg
3559ace9065Smrg    ReleaseButtonsAndKeys(dev);
3569ace9065Smrg    AttachDevice(client, dev, NULL);
3579ace9065Smrg    flags[dev->id] |= XISlaveDetached;
3589ace9065Smrg
359f7df2e56Smrg unwind:
3609ace9065Smrg    return rc;
3619ace9065Smrg}
3629ace9065Smrg
3639ace9065Smrgstatic int
364f7df2e56Smrgattach_slave(ClientPtr client, xXIAttachSlaveInfo * c, int flags[MAXDEVICES])
3659ace9065Smrg{
3669ace9065Smrg    DeviceIntPtr dev;
3679ace9065Smrg    DeviceIntPtr newmaster;
3689ace9065Smrg    int rc;
3699ace9065Smrg
3709ace9065Smrg    rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
3719ace9065Smrg    if (rc != Success)
3729ace9065Smrg        goto unwind;
3739ace9065Smrg
374f7df2e56Smrg    if (IsMaster(dev)) {
3759ace9065Smrg        client->errorValue = c->deviceid;
3769ace9065Smrg        rc = BadDevice;
3779ace9065Smrg        goto unwind;
3789ace9065Smrg    }
3799ace9065Smrg
3809ace9065Smrg    /* Don't allow changes to XTest Devices, these are fixed */
381f7df2e56Smrg    if (IsXTestDevice(dev, NULL)) {
3829ace9065Smrg        client->errorValue = c->deviceid;
3839ace9065Smrg        rc = BadDevice;
3849ace9065Smrg        goto unwind;
3859ace9065Smrg    }
3869ace9065Smrg
3879ace9065Smrg    rc = dixLookupDevice(&newmaster, c->new_master, client, DixAddAccess);
3889ace9065Smrg    if (rc != Success)
3899ace9065Smrg        goto unwind;
390f7df2e56Smrg    if (!IsMaster(newmaster)) {
3919ace9065Smrg        client->errorValue = c->new_master;
3929ace9065Smrg        rc = BadDevice;
3939ace9065Smrg        goto unwind;
3949ace9065Smrg    }
3959ace9065Smrg
3969ace9065Smrg    if (!((IsPointerDevice(newmaster) && IsPointerDevice(dev)) ||
397f7df2e56Smrg          (IsKeyboardDevice(newmaster) && IsKeyboardDevice(dev)))) {
3989ace9065Smrg        rc = BadDevice;
3999ace9065Smrg        goto unwind;
4009ace9065Smrg    }
4019ace9065Smrg
4029ace9065Smrg    ReleaseButtonsAndKeys(dev);
4039ace9065Smrg    AttachDevice(client, dev, newmaster);
4049ace9065Smrg    flags[dev->id] |= XISlaveAttached;
4059ace9065Smrg
406f7df2e56Smrg unwind:
4079ace9065Smrg    return rc;
4089ace9065Smrg}
4099ace9065Smrg
4106747b715Smrg#define SWAPIF(cmd) if (client->swapped) { cmd; }
4116747b715Smrg
4126747b715Smrgint
4136747b715SmrgProcXIChangeHierarchy(ClientPtr client)
4146747b715Smrg{
4156747b715Smrg    xXIAnyHierarchyChangeInfo *any;
4160b0d8713Smrg    size_t len;			/* length of data remaining in request */
4176747b715Smrg    int rc = Success;
418f7df2e56Smrg    int flags[MAXDEVICES] = { 0 };
4196747b715Smrg
4206747b715Smrg    REQUEST(xXIChangeHierarchyReq);
4216747b715Smrg    REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq);
4226747b715Smrg
4236747b715Smrg    if (!stuff->num_changes)
4246747b715Smrg        return rc;
4256747b715Smrg
426806e81e9Smrg    len = ((size_t)client->req_len << 2) - sizeof(xXIChangeHierarchyReq);
4270b0d8713Smrg
428f7df2e56Smrg    any = (xXIAnyHierarchyChangeInfo *) &stuff[1];
429f7df2e56Smrg    while (stuff->num_changes--) {
4300b0d8713Smrg        if (len < sizeof(xXIAnyHierarchyChangeInfo)) {
4310b0d8713Smrg            rc = BadLength;
4320b0d8713Smrg            goto unwind;
4330b0d8713Smrg        }
4340b0d8713Smrg
435f7df2e56Smrg        SWAPIF(swaps(&any->type));
436f7df2e56Smrg        SWAPIF(swaps(&any->length));
4376747b715Smrg
438f7df2e56Smrg        if (len < ((size_t)any->length << 2))
4396747b715Smrg            return BadLength;
4406747b715Smrg
4410b0d8713Smrg#define CHANGE_SIZE_MATCH(type) \
4420b0d8713Smrg    do { \
4430b0d8713Smrg        if ((len < sizeof(type)) || (any->length != (sizeof(type) >> 2))) { \
4440b0d8713Smrg            rc = BadLength; \
4450b0d8713Smrg            goto unwind; \
4460b0d8713Smrg        } \
4470b0d8713Smrg    } while(0)
4480b0d8713Smrg
449f7df2e56Smrg        switch (any->type) {
450f7df2e56Smrg        case XIAddMaster:
4516747b715Smrg        {
452f7df2e56Smrg            xXIAddMasterInfo *c = (xXIAddMasterInfo *) any;
453f7df2e56Smrg
454f7df2e56Smrg            /* Variable length, due to appended name string */
455f7df2e56Smrg            if (len < sizeof(xXIAddMasterInfo)) {
456f7df2e56Smrg                rc = BadLength;
457f7df2e56Smrg                goto unwind;
458f7df2e56Smrg            }
459f7df2e56Smrg            SWAPIF(swaps(&c->name_len));
460f7df2e56Smrg            if (c->name_len > (len - sizeof(xXIAddMasterInfo))) {
461f7df2e56Smrg                rc = BadLength;
462f7df2e56Smrg                goto unwind;
463f7df2e56Smrg            }
464f7df2e56Smrg
465f7df2e56Smrg            rc = add_master(client, c, flags);
466f7df2e56Smrg            if (rc != Success)
467f7df2e56Smrg                goto unwind;
468f7df2e56Smrg        }
469f7df2e56Smrg            break;
470f7df2e56Smrg        case XIRemoveMaster:
471f7df2e56Smrg        {
472f7df2e56Smrg            xXIRemoveMasterInfo *r = (xXIRemoveMasterInfo *) any;
473f7df2e56Smrg
474f7df2e56Smrg            CHANGE_SIZE_MATCH(xXIRemoveMasterInfo);
475f7df2e56Smrg            rc = remove_master(client, r, flags);
476f7df2e56Smrg            if (rc != Success)
477f7df2e56Smrg                goto unwind;
478f7df2e56Smrg        }
479f7df2e56Smrg            break;
480f7df2e56Smrg        case XIDetachSlave:
481f7df2e56Smrg        {
482f7df2e56Smrg            xXIDetachSlaveInfo *c = (xXIDetachSlaveInfo *) any;
483f7df2e56Smrg
484f7df2e56Smrg            CHANGE_SIZE_MATCH(xXIDetachSlaveInfo);
485f7df2e56Smrg            rc = detach_slave(client, c, flags);
486f7df2e56Smrg            if (rc != Success)
487f7df2e56Smrg                goto unwind;
488f7df2e56Smrg        }
489f7df2e56Smrg            break;
490f7df2e56Smrg        case XIAttachSlave:
491f7df2e56Smrg        {
492f7df2e56Smrg            xXIAttachSlaveInfo *c = (xXIAttachSlaveInfo *) any;
493f7df2e56Smrg
494f7df2e56Smrg            CHANGE_SIZE_MATCH(xXIAttachSlaveInfo);
495f7df2e56Smrg            rc = attach_slave(client, c, flags);
496f7df2e56Smrg            if (rc != Success)
497f7df2e56Smrg                goto unwind;
498f7df2e56Smrg        }
499f7df2e56Smrg            break;
5006747b715Smrg        }
5016747b715Smrg
5020b0d8713Smrg        len -= any->length * 4;
503f7df2e56Smrg        any = (xXIAnyHierarchyChangeInfo *) ((char *) any + any->length * 4);
5046747b715Smrg    }
5056747b715Smrg
506f7df2e56Smrg unwind:
5076747b715Smrg
5086747b715Smrg    XISendDeviceHierarchyEvent(flags);
5096747b715Smrg    return rc;
5106747b715Smrg}
511