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" 49d566a54bSmrg#include "misc.h" 506747b715Smrg#include "xace.h" 51f7df2e56Smrg#include "xiquerydevice.h" /* for GetDeviceUse */ 526747b715Smrg 536747b715Smrg#include "xkbsrv.h" 546747b715Smrg 556747b715Smrg#include "xichangehierarchy.h" 56f7df2e56Smrg#include "xibarriers.h" 576747b715Smrg 586747b715Smrg/** 596747b715Smrg * Send the current state of the device hierarchy to all clients. 606747b715Smrg */ 61f7df2e56Smrgvoid 62f7df2e56SmrgXISendDeviceHierarchyEvent(int flags[MAXDEVICES]) 636747b715Smrg{ 646747b715Smrg xXIHierarchyEvent *ev; 656747b715Smrg xXIHierarchyInfo *info; 666747b715Smrg DeviceIntRec dummyDev; 676747b715Smrg DeviceIntPtr dev; 686747b715Smrg int i; 696747b715Smrg 706747b715Smrg if (!flags) 716747b715Smrg return; 726747b715Smrg 736747b715Smrg ev = calloc(1, sizeof(xXIHierarchyEvent) + 74f7df2e56Smrg MAXDEVICES * sizeof(xXIHierarchyInfo)); 759ace9065Smrg if (!ev) 769ace9065Smrg return; 776747b715Smrg ev->type = GenericEvent; 786747b715Smrg ev->extension = IReqCode; 796747b715Smrg ev->evtype = XI_HierarchyChanged; 806747b715Smrg ev->time = GetTimeInMillis(); 816747b715Smrg ev->flags = 0; 826747b715Smrg ev->num_info = inputInfo.numDevices; 836747b715Smrg 84f7df2e56Smrg info = (xXIHierarchyInfo *) &ev[1]; 85f7df2e56Smrg for (dev = inputInfo.devices; dev; dev = dev->next) { 866747b715Smrg info->deviceid = dev->id; 876747b715Smrg info->enabled = dev->enabled; 886747b715Smrg info->use = GetDeviceUse(dev, &info->attachment); 896747b715Smrg info->flags = flags[dev->id]; 906747b715Smrg ev->flags |= info->flags; 916747b715Smrg info++; 926747b715Smrg } 93f7df2e56Smrg for (dev = inputInfo.off_devices; dev; dev = dev->next) { 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 102f7df2e56Smrg for (i = 0; i < MAXDEVICES; i++) { 103f7df2e56Smrg if (flags[i] & (XIMasterRemoved | XISlaveRemoved)) { 1046747b715Smrg info->deviceid = i; 1056747b715Smrg info->enabled = FALSE; 1066747b715Smrg info->flags = flags[i]; 1076747b715Smrg info->use = 0; 1086747b715Smrg ev->flags |= info->flags; 1096747b715Smrg ev->num_info++; 1106747b715Smrg info++; 1116747b715Smrg } 1126747b715Smrg } 1136747b715Smrg 1146747b715Smrg ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo)); 1156747b715Smrg 116f7df2e56Smrg memset(&dummyDev, 0, sizeof(dummyDev)); 1176747b715Smrg dummyDev.id = XIAllDevices; 118f7df2e56Smrg dummyDev.type = SLAVE; 119f7df2e56Smrg SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8), 120f7df2e56Smrg (xEvent *) ev, 1); 1216747b715Smrg free(ev); 1226747b715Smrg} 1236747b715Smrg 1246747b715Smrg/*********************************************************************** 1256747b715Smrg * 1266747b715Smrg * This procedure allows a client to change the device hierarchy through 1276747b715Smrg * adding new master devices, removing them, etc. 1286747b715Smrg * 1296747b715Smrg */ 1306747b715Smrg 1317e31ba66Smrgint _X_COLD 132f7df2e56SmrgSProcXIChangeHierarchy(ClientPtr client) 1336747b715Smrg{ 1346747b715Smrg REQUEST(xXIChangeHierarchyReq); 135f7df2e56Smrg swaps(&stuff->length); 1366747b715Smrg return (ProcXIChangeHierarchy(client)); 1376747b715Smrg} 1386747b715Smrg 1399ace9065Smrgstatic int 140f7df2e56Smrgadd_master(ClientPtr client, xXIAddMasterInfo * c, int flags[MAXDEVICES]) 1419ace9065Smrg{ 1429ace9065Smrg DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd; 143f7df2e56Smrg char *name; 1449ace9065Smrg int rc; 1459ace9065Smrg 1469ace9065Smrg name = calloc(c->name_len + 1, sizeof(char)); 147f7df2e56Smrg if (name == NULL) { 148f7df2e56Smrg rc = BadAlloc; 149f7df2e56Smrg goto unwind; 150f7df2e56Smrg } 151f7df2e56Smrg strncpy(name, (char *) &c[1], c->name_len); 1529ace9065Smrg 1539ace9065Smrg rc = AllocDevicePair(client, name, &ptr, &keybd, 1549ace9065Smrg CorePointerProc, CoreKeyboardProc, TRUE); 1559ace9065Smrg if (rc != Success) 1569ace9065Smrg goto unwind; 1579ace9065Smrg 1589ace9065Smrg if (!c->send_core) 159f7df2e56Smrg ptr->coreEvents = keybd->coreEvents = FALSE; 1609ace9065Smrg 1619ace9065Smrg /* Allocate virtual slave devices for xtest events */ 1629ace9065Smrg rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, ptr, keybd); 163f7df2e56Smrg if (rc != Success) { 1649ace9065Smrg DeleteInputDeviceRequest(ptr); 1659ace9065Smrg DeleteInputDeviceRequest(keybd); 1669ace9065Smrg goto unwind; 1679ace9065Smrg } 1689ace9065Smrg 1699ace9065Smrg ActivateDevice(ptr, FALSE); 1709ace9065Smrg ActivateDevice(keybd, FALSE); 1719ace9065Smrg flags[ptr->id] |= XIMasterAdded; 1729ace9065Smrg flags[keybd->id] |= XIMasterAdded; 1739ace9065Smrg 1749ace9065Smrg ActivateDevice(XTestptr, FALSE); 1759ace9065Smrg ActivateDevice(XTestkeybd, FALSE); 1769ace9065Smrg flags[XTestptr->id] |= XISlaveAdded; 1779ace9065Smrg flags[XTestkeybd->id] |= XISlaveAdded; 1789ace9065Smrg 179f7df2e56Smrg if (c->enable) { 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 1987e31ba66Smrg for (int i = 0; i < currentMaxClients; i++) 1997e31ba66Smrg XIBarrierNewMasterDevice(clients[i], ptr->id); 200f7df2e56Smrg 201f7df2e56Smrg unwind: 2029ace9065Smrg free(name); 2039ace9065Smrg return rc; 2049ace9065Smrg} 2059ace9065Smrg 206475c125cSmrgstatic void 207475c125cSmrgdisable_clientpointer(DeviceIntPtr dev) 208475c125cSmrg{ 209475c125cSmrg int i; 210475c125cSmrg 211f7df2e56Smrg for (i = 0; i < currentMaxClients; i++) { 212475c125cSmrg ClientPtr client = clients[i]; 213f7df2e56Smrg 214475c125cSmrg if (client && client->clientPtr == dev) 215475c125cSmrg client->clientPtr = NULL; 216475c125cSmrg } 217475c125cSmrg} 218475c125cSmrg 219d566a54bSmrgstatic DeviceIntPtr 220d566a54bSmrgfind_disabled_master(int type) 221d566a54bSmrg{ 222d566a54bSmrg DeviceIntPtr dev; 223d566a54bSmrg 224d566a54bSmrg /* Once a master device is disabled it loses the pairing, so returning the first 225d566a54bSmrg * match is good enough */ 226d566a54bSmrg for (dev = inputInfo.off_devices; dev; dev = dev->next) { 227d566a54bSmrg if (dev->type == type) 228d566a54bSmrg return dev; 229d566a54bSmrg } 230d566a54bSmrg 231d566a54bSmrg return NULL; 232d566a54bSmrg} 233d566a54bSmrg 2349ace9065Smrgstatic int 235f7df2e56Smrgremove_master(ClientPtr client, xXIRemoveMasterInfo * r, int flags[MAXDEVICES]) 2369ace9065Smrg{ 237d566a54bSmrg DeviceIntPtr dev, ptr, keybd, XTestptr, XTestkeybd; 2389ace9065Smrg int rc = Success; 2399ace9065Smrg 240f7df2e56Smrg if (r->return_mode != XIAttachToMaster && r->return_mode != XIFloating) 2419ace9065Smrg return BadValue; 2429ace9065Smrg 243d566a54bSmrg rc = dixLookupDevice(&dev, r->deviceid, client, DixDestroyAccess); 2449ace9065Smrg if (rc != Success) 2459ace9065Smrg goto unwind; 2469ace9065Smrg 247d566a54bSmrg if (!IsMaster(dev)) { 2489ace9065Smrg client->errorValue = r->deviceid; 2499ace9065Smrg rc = BadDevice; 2509ace9065Smrg goto unwind; 2519ace9065Smrg } 2529ace9065Smrg 2539ace9065Smrg /* XXX: For now, don't allow removal of VCP, VCK */ 254d566a54bSmrg if (dev == inputInfo.pointer || dev == inputInfo.keyboard) { 2559ace9065Smrg rc = BadDevice; 2569ace9065Smrg goto unwind; 2579ace9065Smrg } 2589ace9065Smrg 259d566a54bSmrg if ((ptr = GetMaster(dev, MASTER_POINTER)) == NULL) 260d566a54bSmrg ptr = find_disabled_master(MASTER_POINTER); 261d566a54bSmrg BUG_RETURN_VAL(ptr == NULL, BadDevice); 2629ace9065Smrg rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess); 2639ace9065Smrg if (rc != Success) 2649ace9065Smrg goto unwind; 265d566a54bSmrg 266d566a54bSmrg if ((keybd = GetMaster(dev, MASTER_KEYBOARD)) == NULL) 267d566a54bSmrg keybd = find_disabled_master(MASTER_KEYBOARD); 268d566a54bSmrg BUG_RETURN_VAL(keybd == NULL, BadDevice); 2699ace9065Smrg rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess); 2709ace9065Smrg if (rc != Success) 2719ace9065Smrg goto unwind; 2729ace9065Smrg 2739ace9065Smrg XTestptr = GetXTestDevice(ptr); 274d566a54bSmrg BUG_RETURN_VAL(XTestptr == NULL, BadDevice); 2759ace9065Smrg rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess); 2769ace9065Smrg if (rc != Success) 2779ace9065Smrg goto unwind; 2789ace9065Smrg 2799ace9065Smrg XTestkeybd = GetXTestDevice(keybd); 280d566a54bSmrg BUG_RETURN_VAL(XTestkeybd == NULL, BadDevice); 281f7df2e56Smrg rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, DixDestroyAccess); 2829ace9065Smrg if (rc != Success) 2839ace9065Smrg goto unwind; 2849ace9065Smrg 285475c125cSmrg disable_clientpointer(ptr); 286475c125cSmrg 2879ace9065Smrg /* Disabling sends the devices floating, reattach them if 2889ace9065Smrg * desired. */ 289f7df2e56Smrg if (r->return_mode == XIAttachToMaster) { 290f7df2e56Smrg DeviceIntPtr attached, newptr, newkeybd; 2919ace9065Smrg 2929ace9065Smrg rc = dixLookupDevice(&newptr, r->return_pointer, client, DixAddAccess); 2939ace9065Smrg if (rc != Success) 2949ace9065Smrg goto unwind; 2959ace9065Smrg 296f7df2e56Smrg if (!IsMaster(newptr)) { 2979ace9065Smrg client->errorValue = r->return_pointer; 2989ace9065Smrg rc = BadDevice; 2999ace9065Smrg goto unwind; 3009ace9065Smrg } 3019ace9065Smrg 3029ace9065Smrg rc = dixLookupDevice(&newkeybd, r->return_keyboard, 3039ace9065Smrg client, DixAddAccess); 3049ace9065Smrg if (rc != Success) 3059ace9065Smrg goto unwind; 3069ace9065Smrg 307f7df2e56Smrg if (!IsMaster(newkeybd)) { 3089ace9065Smrg client->errorValue = r->return_keyboard; 3099ace9065Smrg rc = BadDevice; 3109ace9065Smrg goto unwind; 3119ace9065Smrg } 3129ace9065Smrg 313f7df2e56Smrg for (attached = inputInfo.devices; attached; attached = attached->next) { 3149ace9065Smrg if (!IsMaster(attached)) { 315f7df2e56Smrg if (GetMaster(attached, MASTER_ATTACHED) == ptr) { 3169ace9065Smrg AttachDevice(client, attached, newptr); 3179ace9065Smrg flags[attached->id] |= XISlaveAttached; 3189ace9065Smrg } 319f7df2e56Smrg if (GetMaster(attached, MASTER_ATTACHED) == keybd) { 3209ace9065Smrg AttachDevice(client, attached, newkeybd); 3219ace9065Smrg flags[attached->id] |= XISlaveAttached; 3229ace9065Smrg } 3239ace9065Smrg } 3249ace9065Smrg } 3259ace9065Smrg } 3269ace9065Smrg 3277e31ba66Smrg for (int i = 0; i < currentMaxClients; i++) 3287e31ba66Smrg XIBarrierRemoveMasterDevice(clients[i], ptr->id); 3299ace9065Smrg 3309ace9065Smrg /* disable the remove the devices, XTest devices must be done first 3319ace9065Smrg else the sprites they rely on will be destroyed */ 3329ace9065Smrg DisableDevice(XTestptr, FALSE); 3339ace9065Smrg DisableDevice(XTestkeybd, FALSE); 3349ace9065Smrg DisableDevice(keybd, FALSE); 3359ace9065Smrg DisableDevice(ptr, FALSE); 3369ace9065Smrg flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached; 3379ace9065Smrg flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached; 3389ace9065Smrg flags[keybd->id] |= XIDeviceDisabled; 3399ace9065Smrg flags[ptr->id] |= XIDeviceDisabled; 3409ace9065Smrg 3419ace9065Smrg flags[XTestptr->id] |= XISlaveRemoved; 3429ace9065Smrg flags[XTestkeybd->id] |= XISlaveRemoved; 3439ace9065Smrg flags[keybd->id] |= XIMasterRemoved; 3449ace9065Smrg flags[ptr->id] |= XIMasterRemoved; 3459ace9065Smrg 346f7df2e56Smrg RemoveDevice(XTestptr, FALSE); 347f7df2e56Smrg RemoveDevice(XTestkeybd, FALSE); 348f7df2e56Smrg RemoveDevice(keybd, FALSE); 349f7df2e56Smrg RemoveDevice(ptr, FALSE); 350f7df2e56Smrg 351f7df2e56Smrg unwind: 3529ace9065Smrg return rc; 3539ace9065Smrg} 3549ace9065Smrg 3559ace9065Smrgstatic int 356f7df2e56Smrgdetach_slave(ClientPtr client, xXIDetachSlaveInfo * c, int flags[MAXDEVICES]) 3579ace9065Smrg{ 3589ace9065Smrg DeviceIntPtr dev; 3599ace9065Smrg int rc; 3609ace9065Smrg 3619ace9065Smrg rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess); 3629ace9065Smrg if (rc != Success) 3639ace9065Smrg goto unwind; 3649ace9065Smrg 365f7df2e56Smrg if (IsMaster(dev)) { 3669ace9065Smrg client->errorValue = c->deviceid; 3679ace9065Smrg rc = BadDevice; 3689ace9065Smrg goto unwind; 3699ace9065Smrg } 3709ace9065Smrg 3719ace9065Smrg /* Don't allow changes to XTest Devices, these are fixed */ 372f7df2e56Smrg if (IsXTestDevice(dev, NULL)) { 3739ace9065Smrg client->errorValue = c->deviceid; 3749ace9065Smrg rc = BadDevice; 3759ace9065Smrg goto unwind; 3769ace9065Smrg } 3779ace9065Smrg 3789ace9065Smrg ReleaseButtonsAndKeys(dev); 3799ace9065Smrg AttachDevice(client, dev, NULL); 3809ace9065Smrg flags[dev->id] |= XISlaveDetached; 3819ace9065Smrg 382f7df2e56Smrg unwind: 3839ace9065Smrg return rc; 3849ace9065Smrg} 3859ace9065Smrg 3869ace9065Smrgstatic int 387f7df2e56Smrgattach_slave(ClientPtr client, xXIAttachSlaveInfo * c, int flags[MAXDEVICES]) 3889ace9065Smrg{ 3899ace9065Smrg DeviceIntPtr dev; 3909ace9065Smrg DeviceIntPtr newmaster; 3919ace9065Smrg int rc; 3929ace9065Smrg 3939ace9065Smrg rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess); 3949ace9065Smrg if (rc != Success) 3959ace9065Smrg goto unwind; 3969ace9065Smrg 397f7df2e56Smrg if (IsMaster(dev)) { 3989ace9065Smrg client->errorValue = c->deviceid; 3999ace9065Smrg rc = BadDevice; 4009ace9065Smrg goto unwind; 4019ace9065Smrg } 4029ace9065Smrg 4039ace9065Smrg /* Don't allow changes to XTest Devices, these are fixed */ 404f7df2e56Smrg if (IsXTestDevice(dev, NULL)) { 4059ace9065Smrg client->errorValue = c->deviceid; 4069ace9065Smrg rc = BadDevice; 4079ace9065Smrg goto unwind; 4089ace9065Smrg } 4099ace9065Smrg 4109ace9065Smrg rc = dixLookupDevice(&newmaster, c->new_master, client, DixAddAccess); 4119ace9065Smrg if (rc != Success) 4129ace9065Smrg goto unwind; 413f7df2e56Smrg if (!IsMaster(newmaster)) { 4149ace9065Smrg client->errorValue = c->new_master; 4159ace9065Smrg rc = BadDevice; 4169ace9065Smrg goto unwind; 4179ace9065Smrg } 4189ace9065Smrg 4199ace9065Smrg if (!((IsPointerDevice(newmaster) && IsPointerDevice(dev)) || 420f7df2e56Smrg (IsKeyboardDevice(newmaster) && IsKeyboardDevice(dev)))) { 4219ace9065Smrg rc = BadDevice; 4229ace9065Smrg goto unwind; 4239ace9065Smrg } 4249ace9065Smrg 4259ace9065Smrg ReleaseButtonsAndKeys(dev); 4269ace9065Smrg AttachDevice(client, dev, newmaster); 4279ace9065Smrg flags[dev->id] |= XISlaveAttached; 4289ace9065Smrg 429f7df2e56Smrg unwind: 4309ace9065Smrg return rc; 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 int rc = Success; 441f7df2e56Smrg int flags[MAXDEVICES] = { 0 }; 442875c6e4fSmrg enum { 443875c6e4fSmrg NO_CHANGE, 444875c6e4fSmrg FLUSH, 445875c6e4fSmrg CHANGED, 446875c6e4fSmrg } changes = NO_CHANGE; 4476747b715Smrg 4486747b715Smrg REQUEST(xXIChangeHierarchyReq); 4496747b715Smrg REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq); 4506747b715Smrg 4516747b715Smrg if (!stuff->num_changes) 4526747b715Smrg return rc; 4536747b715Smrg 454806e81e9Smrg len = ((size_t)client->req_len << 2) - sizeof(xXIChangeHierarchyReq); 4550b0d8713Smrg 456f7df2e56Smrg any = (xXIAnyHierarchyChangeInfo *) &stuff[1]; 457f7df2e56Smrg while (stuff->num_changes--) { 4580b0d8713Smrg if (len < sizeof(xXIAnyHierarchyChangeInfo)) { 4590b0d8713Smrg rc = BadLength; 4600b0d8713Smrg goto unwind; 4610b0d8713Smrg } 4620b0d8713Smrg 463f7df2e56Smrg SWAPIF(swaps(&any->type)); 464f7df2e56Smrg SWAPIF(swaps(&any->length)); 4656747b715Smrg 466f7df2e56Smrg if (len < ((size_t)any->length << 2)) 4676747b715Smrg return BadLength; 4686747b715Smrg 4690b0d8713Smrg#define CHANGE_SIZE_MATCH(type) \ 4700b0d8713Smrg do { \ 4710b0d8713Smrg if ((len < sizeof(type)) || (any->length != (sizeof(type) >> 2))) { \ 4720b0d8713Smrg rc = BadLength; \ 4730b0d8713Smrg goto unwind; \ 4740b0d8713Smrg } \ 4750b0d8713Smrg } while(0) 4760b0d8713Smrg 477f7df2e56Smrg switch (any->type) { 478f7df2e56Smrg case XIAddMaster: 4796747b715Smrg { 480f7df2e56Smrg xXIAddMasterInfo *c = (xXIAddMasterInfo *) any; 481f7df2e56Smrg 482f7df2e56Smrg /* Variable length, due to appended name string */ 483f7df2e56Smrg if (len < sizeof(xXIAddMasterInfo)) { 484f7df2e56Smrg rc = BadLength; 485f7df2e56Smrg goto unwind; 486f7df2e56Smrg } 487f7df2e56Smrg SWAPIF(swaps(&c->name_len)); 488f7df2e56Smrg if (c->name_len > (len - sizeof(xXIAddMasterInfo))) { 489f7df2e56Smrg rc = BadLength; 490f7df2e56Smrg goto unwind; 491f7df2e56Smrg } 492f7df2e56Smrg 493f7df2e56Smrg rc = add_master(client, c, flags); 494f7df2e56Smrg if (rc != Success) 495f7df2e56Smrg goto unwind; 496875c6e4fSmrg changes = FLUSH; 497f7df2e56Smrg break; 498875c6e4fSmrg } 499f7df2e56Smrg case XIRemoveMaster: 500f7df2e56Smrg { 501f7df2e56Smrg xXIRemoveMasterInfo *r = (xXIRemoveMasterInfo *) any; 502f7df2e56Smrg 503f7df2e56Smrg CHANGE_SIZE_MATCH(xXIRemoveMasterInfo); 504f7df2e56Smrg rc = remove_master(client, r, flags); 505f7df2e56Smrg if (rc != Success) 506f7df2e56Smrg goto unwind; 507875c6e4fSmrg changes = FLUSH; 508f7df2e56Smrg break; 509875c6e4fSmrg } 510f7df2e56Smrg case XIDetachSlave: 511f7df2e56Smrg { 512f7df2e56Smrg xXIDetachSlaveInfo *c = (xXIDetachSlaveInfo *) any; 513f7df2e56Smrg 514f7df2e56Smrg CHANGE_SIZE_MATCH(xXIDetachSlaveInfo); 515f7df2e56Smrg rc = detach_slave(client, c, flags); 516f7df2e56Smrg if (rc != Success) 517f7df2e56Smrg goto unwind; 518875c6e4fSmrg changes = CHANGED; 519f7df2e56Smrg break; 520875c6e4fSmrg } 521f7df2e56Smrg case XIAttachSlave: 522f7df2e56Smrg { 523f7df2e56Smrg xXIAttachSlaveInfo *c = (xXIAttachSlaveInfo *) any; 524f7df2e56Smrg 525f7df2e56Smrg CHANGE_SIZE_MATCH(xXIAttachSlaveInfo); 526f7df2e56Smrg rc = attach_slave(client, c, flags); 527f7df2e56Smrg if (rc != Success) 528f7df2e56Smrg goto unwind; 529875c6e4fSmrg changes = CHANGED; 530875c6e4fSmrg break; 531f7df2e56Smrg } 532875c6e4fSmrg default: 533f7df2e56Smrg break; 5346747b715Smrg } 5356747b715Smrg 536875c6e4fSmrg if (changes == FLUSH) { 537875c6e4fSmrg XISendDeviceHierarchyEvent(flags); 538875c6e4fSmrg memset(flags, 0, sizeof(flags)); 539875c6e4fSmrg changes = NO_CHANGE; 540875c6e4fSmrg } 541875c6e4fSmrg 5420b0d8713Smrg len -= any->length * 4; 543f7df2e56Smrg any = (xXIAnyHierarchyChangeInfo *) ((char *) any + any->length * 4); 5446747b715Smrg } 5456747b715Smrg 546f7df2e56Smrg unwind: 547875c6e4fSmrg if (changes != NO_CHANGE) 548875c6e4fSmrg XISendDeviceHierarchyEvent(flags); 5496747b715Smrg return rc; 5506747b715Smrg} 551