xichangehierarchy.c revision 9ace9065
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
2039ace9065Smrgstatic int
2049ace9065Smrgremove_master(ClientPtr client, xXIRemoveMasterInfo *r,
2059ace9065Smrg              int flags[MAXDEVICES])
2069ace9065Smrg{
2079ace9065Smrg    DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd;
2089ace9065Smrg    int rc = Success;
2099ace9065Smrg
2109ace9065Smrg    if (r->return_mode != XIAttachToMaster &&
2119ace9065Smrg        r->return_mode != XIFloating)
2129ace9065Smrg        return BadValue;
2139ace9065Smrg
2149ace9065Smrg    rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess);
2159ace9065Smrg    if (rc != Success)
2169ace9065Smrg        goto unwind;
2179ace9065Smrg
2189ace9065Smrg    if (!IsMaster(ptr))
2199ace9065Smrg    {
2209ace9065Smrg        client->errorValue = r->deviceid;
2219ace9065Smrg        rc = BadDevice;
2229ace9065Smrg        goto unwind;
2239ace9065Smrg    }
2249ace9065Smrg
2259ace9065Smrg    /* XXX: For now, don't allow removal of VCP, VCK */
2269ace9065Smrg    if (ptr == inputInfo.pointer || ptr == inputInfo.keyboard)
2279ace9065Smrg    {
2289ace9065Smrg        rc = BadDevice;
2299ace9065Smrg        goto unwind;
2309ace9065Smrg    }
2319ace9065Smrg
2329ace9065Smrg
2339ace9065Smrg    ptr = GetMaster(ptr, MASTER_POINTER);
2349ace9065Smrg    rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess);
2359ace9065Smrg    if (rc != Success)
2369ace9065Smrg        goto unwind;
2379ace9065Smrg    keybd = GetMaster(ptr, MASTER_KEYBOARD);
2389ace9065Smrg    rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess);
2399ace9065Smrg    if (rc != Success)
2409ace9065Smrg        goto unwind;
2419ace9065Smrg
2429ace9065Smrg    XTestptr = GetXTestDevice(ptr);
2439ace9065Smrg    rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess);
2449ace9065Smrg    if (rc != Success)
2459ace9065Smrg        goto unwind;
2469ace9065Smrg
2479ace9065Smrg    XTestkeybd = GetXTestDevice(keybd);
2489ace9065Smrg    rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client,
2499ace9065Smrg                         DixDestroyAccess);
2509ace9065Smrg    if (rc != Success)
2519ace9065Smrg        goto unwind;
2529ace9065Smrg
2539ace9065Smrg    /* Disabling sends the devices floating, reattach them if
2549ace9065Smrg     * desired. */
2559ace9065Smrg    if (r->return_mode == XIAttachToMaster)
2569ace9065Smrg    {
2579ace9065Smrg        DeviceIntPtr attached,
2589ace9065Smrg                     newptr,
2599ace9065Smrg                     newkeybd;
2609ace9065Smrg
2619ace9065Smrg        rc = dixLookupDevice(&newptr, r->return_pointer, client, DixAddAccess);
2629ace9065Smrg        if (rc != Success)
2639ace9065Smrg            goto unwind;
2649ace9065Smrg
2659ace9065Smrg        if (!IsMaster(newptr))
2669ace9065Smrg        {
2679ace9065Smrg            client->errorValue = r->return_pointer;
2689ace9065Smrg            rc = BadDevice;
2699ace9065Smrg            goto unwind;
2709ace9065Smrg        }
2719ace9065Smrg
2729ace9065Smrg        rc = dixLookupDevice(&newkeybd, r->return_keyboard,
2739ace9065Smrg                             client, DixAddAccess);
2749ace9065Smrg        if (rc != Success)
2759ace9065Smrg            goto unwind;
2769ace9065Smrg
2779ace9065Smrg        if (!IsMaster(newkeybd))
2789ace9065Smrg        {
2799ace9065Smrg            client->errorValue = r->return_keyboard;
2809ace9065Smrg            rc = BadDevice;
2819ace9065Smrg            goto unwind;
2829ace9065Smrg        }
2839ace9065Smrg
2849ace9065Smrg        for (attached = inputInfo.devices; attached; attached = attached->next)
2859ace9065Smrg        {
2869ace9065Smrg            if (!IsMaster(attached)) {
2879ace9065Smrg                if (attached->u.master == ptr)
2889ace9065Smrg                {
2899ace9065Smrg                    AttachDevice(client, attached, newptr);
2909ace9065Smrg                    flags[attached->id] |= XISlaveAttached;
2919ace9065Smrg                }
2929ace9065Smrg                if (attached->u.master == keybd)
2939ace9065Smrg                {
2949ace9065Smrg                    AttachDevice(client, attached, newkeybd);
2959ace9065Smrg                    flags[attached->id] |= XISlaveAttached;
2969ace9065Smrg                }
2979ace9065Smrg            }
2989ace9065Smrg        }
2999ace9065Smrg    }
3009ace9065Smrg
3019ace9065Smrg    /* can't disable until we removed pairing */
3029ace9065Smrg    keybd->spriteInfo->paired = NULL;
3039ace9065Smrg    ptr->spriteInfo->paired = NULL;
3049ace9065Smrg    XTestptr->spriteInfo->paired = NULL;
3059ace9065Smrg    XTestkeybd->spriteInfo->paired = NULL;
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    RemoveDevice(XTestptr, FALSE);
3199ace9065Smrg    RemoveDevice(XTestkeybd, FALSE);
3209ace9065Smrg    RemoveDevice(keybd, FALSE);
3219ace9065Smrg    RemoveDevice(ptr, FALSE);
3229ace9065Smrg    flags[XTestptr->id] |= XISlaveRemoved;
3239ace9065Smrg    flags[XTestkeybd->id] |= XISlaveRemoved;
3249ace9065Smrg    flags[keybd->id] |= XIMasterRemoved;
3259ace9065Smrg    flags[ptr->id] |= XIMasterRemoved;
3269ace9065Smrg
3279ace9065Smrgunwind:
3289ace9065Smrg    return rc;
3299ace9065Smrg}
3309ace9065Smrg
3319ace9065Smrgstatic int
3329ace9065Smrgdetach_slave(ClientPtr client, xXIDetachSlaveInfo *c, int flags[MAXDEVICES])
3339ace9065Smrg{
3349ace9065Smrg    DeviceIntPtr dev;
3359ace9065Smrg    int rc;
3369ace9065Smrg
3379ace9065Smrg    rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
3389ace9065Smrg    if (rc != Success)
3399ace9065Smrg        goto unwind;
3409ace9065Smrg
3419ace9065Smrg    if (IsMaster(dev))
3429ace9065Smrg    {
3439ace9065Smrg        client->errorValue = c->deviceid;
3449ace9065Smrg        rc = BadDevice;
3459ace9065Smrg        goto unwind;
3469ace9065Smrg    }
3479ace9065Smrg
3489ace9065Smrg    /* Don't allow changes to XTest Devices, these are fixed */
3499ace9065Smrg    if (IsXTestDevice(dev, NULL))
3509ace9065Smrg    {
3519ace9065Smrg        client->errorValue = c->deviceid;
3529ace9065Smrg        rc = BadDevice;
3539ace9065Smrg        goto unwind;
3549ace9065Smrg    }
3559ace9065Smrg
3569ace9065Smrg    ReleaseButtonsAndKeys(dev);
3579ace9065Smrg    AttachDevice(client, dev, NULL);
3589ace9065Smrg    flags[dev->id] |= XISlaveDetached;
3599ace9065Smrg
3609ace9065Smrgunwind:
3619ace9065Smrg    return rc;
3629ace9065Smrg}
3639ace9065Smrg
3649ace9065Smrgstatic int
3659ace9065Smrgattach_slave(ClientPtr client, xXIAttachSlaveInfo *c,
3669ace9065Smrg             int flags[MAXDEVICES])
3679ace9065Smrg{
3689ace9065Smrg    DeviceIntPtr dev;
3699ace9065Smrg    DeviceIntPtr newmaster;
3709ace9065Smrg    int rc;
3719ace9065Smrg
3729ace9065Smrg    rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess);
3739ace9065Smrg    if (rc != Success)
3749ace9065Smrg        goto unwind;
3759ace9065Smrg
3769ace9065Smrg    if (IsMaster(dev))
3779ace9065Smrg    {
3789ace9065Smrg        client->errorValue = c->deviceid;
3799ace9065Smrg        rc = BadDevice;
3809ace9065Smrg        goto unwind;
3819ace9065Smrg    }
3829ace9065Smrg
3839ace9065Smrg    /* Don't allow changes to XTest Devices, these are fixed */
3849ace9065Smrg    if (IsXTestDevice(dev, NULL))
3859ace9065Smrg    {
3869ace9065Smrg        client->errorValue = c->deviceid;
3879ace9065Smrg        rc = BadDevice;
3889ace9065Smrg        goto unwind;
3899ace9065Smrg    }
3909ace9065Smrg
3919ace9065Smrg    rc = dixLookupDevice(&newmaster, c->new_master, client, DixAddAccess);
3929ace9065Smrg    if (rc != Success)
3939ace9065Smrg        goto unwind;
3949ace9065Smrg    if (!IsMaster(newmaster))
3959ace9065Smrg    {
3969ace9065Smrg        client->errorValue = c->new_master;
3979ace9065Smrg        rc = BadDevice;
3989ace9065Smrg        goto unwind;
3999ace9065Smrg    }
4009ace9065Smrg
4019ace9065Smrg    if (!((IsPointerDevice(newmaster) && IsPointerDevice(dev)) ||
4029ace9065Smrg        (IsKeyboardDevice(newmaster) && IsKeyboardDevice(dev))))
4039ace9065Smrg    {
4049ace9065Smrg        rc = BadDevice;
4059ace9065Smrg        goto unwind;
4069ace9065Smrg    }
4079ace9065Smrg
4089ace9065Smrg    ReleaseButtonsAndKeys(dev);
4099ace9065Smrg    AttachDevice(client, dev, newmaster);
4109ace9065Smrg    flags[dev->id] |= XISlaveAttached;
4119ace9065Smrg
4129ace9065Smrgunwind:
4139ace9065Smrg    return rc;
4149ace9065Smrg}
4159ace9065Smrg
4169ace9065Smrg
4179ace9065Smrg
4186747b715Smrg#define SWAPIF(cmd) if (client->swapped) { cmd; }
4196747b715Smrg
4206747b715Smrgint
4216747b715SmrgProcXIChangeHierarchy(ClientPtr client)
4226747b715Smrg{
4236747b715Smrg    xXIAnyHierarchyChangeInfo *any;
4246747b715Smrg    int required_len = sizeof(xXIChangeHierarchyReq);
4256747b715Smrg    char n;
4266747b715Smrg    int rc = Success;
4276747b715Smrg    int flags[MAXDEVICES] = {0};
4286747b715Smrg
4296747b715Smrg    REQUEST(xXIChangeHierarchyReq);
4306747b715Smrg    REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq);
4316747b715Smrg
4326747b715Smrg    if (!stuff->num_changes)
4336747b715Smrg        return rc;
4346747b715Smrg
4356747b715Smrg    any = (xXIAnyHierarchyChangeInfo*)&stuff[1];
4366747b715Smrg    while(stuff->num_changes--)
4376747b715Smrg    {
4386747b715Smrg        SWAPIF(swapl(&any->type, n));
4396747b715Smrg        SWAPIF(swaps(&any->length, n));
4406747b715Smrg
4416747b715Smrg        required_len += any->length;
4426747b715Smrg        if ((stuff->length * 4) < required_len)
4436747b715Smrg            return BadLength;
4446747b715Smrg
4456747b715Smrg        switch(any->type)
4466747b715Smrg        {
4476747b715Smrg            case XIAddMaster:
4486747b715Smrg                {
4496747b715Smrg                    xXIAddMasterInfo* c = (xXIAddMasterInfo*)any;
4506747b715Smrg                    SWAPIF(swaps(&c->name_len, n));
4516747b715Smrg
4529ace9065Smrg                    rc = add_master(client, c, flags);
4536747b715Smrg                    if (rc != Success)
4546747b715Smrg                        goto unwind;
4556747b715Smrg                }
4566747b715Smrg                break;
4576747b715Smrg            case XIRemoveMaster:
4586747b715Smrg                {
4596747b715Smrg                    xXIRemoveMasterInfo* r = (xXIRemoveMasterInfo*)any;
4606747b715Smrg
4619ace9065Smrg                    rc = remove_master(client, r, flags);
4626747b715Smrg                    if (rc != Success)
4636747b715Smrg                        goto unwind;
4646747b715Smrg                }
4656747b715Smrg                break;
4666747b715Smrg            case XIDetachSlave:
4676747b715Smrg                {
4686747b715Smrg                    xXIDetachSlaveInfo* c = (xXIDetachSlaveInfo*)any;
4696747b715Smrg
4709ace9065Smrg                    rc = detach_slave(client, c, flags);
4716747b715Smrg                    if (rc != Success)
4726747b715Smrg                       goto unwind;
4736747b715Smrg                }
4746747b715Smrg                break;
4756747b715Smrg            case XIAttachSlave:
4766747b715Smrg                {
4776747b715Smrg                    xXIAttachSlaveInfo* c = (xXIAttachSlaveInfo*)any;
4786747b715Smrg
4799ace9065Smrg                    rc = attach_slave(client, c, flags);
4806747b715Smrg                    if (rc != Success)
4816747b715Smrg                       goto unwind;
4826747b715Smrg                }
4836747b715Smrg                break;
4846747b715Smrg        }
4856747b715Smrg
4866747b715Smrg        any = (xXIAnyHierarchyChangeInfo*)((char*)any + any->length * 4);
4876747b715Smrg    }
4886747b715Smrg
4896747b715Smrgunwind:
4906747b715Smrg
4916747b715Smrg    XISendDeviceHierarchyEvent(flags);
4926747b715Smrg    return rc;
4936747b715Smrg}
4946747b715Smrg
495