xichangehierarchy.c revision 9ace9065
1/* 2 * Copyright 2007-2008 Peter Hutterer 3 * Copyright 2009 Red Hat, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 * 24 * Author: Peter Hutterer, University of South Australia, NICTA 25 */ 26 27/*********************************************************************** 28 * 29 * Request change in the device hierarchy. 30 * 31 */ 32 33 34#ifdef HAVE_DIX_CONFIG_H 35#include <dix-config.h> 36#endif 37 38#include <X11/X.h> /* for inputstr.h */ 39#include <X11/Xproto.h> /* Request macro */ 40#include "inputstr.h" /* DeviceIntPtr */ 41#include "windowstr.h" /* window structure */ 42#include "scrnintstr.h" /* screen structure */ 43#include <X11/extensions/XI.h> 44#include <X11/extensions/XI2proto.h> 45#include <X11/extensions/geproto.h> 46#include "extnsionst.h" 47#include "exevents.h" 48#include "exglobals.h" 49#include "geext.h" 50#include "xace.h" 51#include "xiquerydevice.h" /* for GetDeviceUse */ 52 53#include "xkbsrv.h" 54 55#include "xichangehierarchy.h" 56 57/** 58 * Send the current state of the device hierarchy to all clients. 59 */ 60void XISendDeviceHierarchyEvent(int flags[MAXDEVICES]) 61{ 62 xXIHierarchyEvent *ev; 63 xXIHierarchyInfo *info; 64 DeviceIntRec dummyDev; 65 DeviceIntPtr dev; 66 int i; 67 68 if (!flags) 69 return; 70 71 ev = calloc(1, sizeof(xXIHierarchyEvent) + 72 MAXDEVICES * sizeof(xXIHierarchyInfo)); 73 if (!ev) 74 return; 75 ev->type = GenericEvent; 76 ev->extension = IReqCode; 77 ev->evtype = XI_HierarchyChanged; 78 ev->time = GetTimeInMillis(); 79 ev->flags = 0; 80 ev->num_info = inputInfo.numDevices; 81 82 info = (xXIHierarchyInfo*)&ev[1]; 83 for (dev = inputInfo.devices; dev; dev = dev->next) 84 { 85 info->deviceid = dev->id; 86 info->enabled = dev->enabled; 87 info->use = GetDeviceUse(dev, &info->attachment); 88 info->flags = flags[dev->id]; 89 ev->flags |= info->flags; 90 info++; 91 } 92 for (dev = inputInfo.off_devices; dev; dev = dev->next) 93 { 94 info->deviceid = dev->id; 95 info->enabled = dev->enabled; 96 info->use = GetDeviceUse(dev, &info->attachment); 97 info->flags = flags[dev->id]; 98 ev->flags |= info->flags; 99 info++; 100 } 101 102 103 for (i = 0; i < MAXDEVICES; i++) 104 { 105 if (flags[i] & (XIMasterRemoved | XISlaveRemoved)) 106 { 107 info->deviceid = i; 108 info->enabled = FALSE; 109 info->flags = flags[i]; 110 info->use = 0; 111 ev->flags |= info->flags; 112 ev->num_info++; 113 info++; 114 } 115 } 116 117 ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo)); 118 119 dummyDev.id = XIAllDevices; 120 SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8), (xEvent*)ev, 1); 121 free(ev); 122} 123 124 125/*********************************************************************** 126 * 127 * This procedure allows a client to change the device hierarchy through 128 * adding new master devices, removing them, etc. 129 * 130 */ 131 132int SProcXIChangeHierarchy(ClientPtr client) 133{ 134 char n; 135 136 REQUEST(xXIChangeHierarchyReq); 137 swaps(&stuff->length, n); 138 return (ProcXIChangeHierarchy(client)); 139} 140 141static int 142add_master(ClientPtr client, xXIAddMasterInfo *c, int flags[MAXDEVICES]) 143{ 144 DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd; 145 char* name; 146 int rc; 147 148 name = calloc(c->name_len + 1, sizeof(char)); 149 strncpy(name, (char*)&c[1], c->name_len); 150 151 rc = AllocDevicePair(client, name, &ptr, &keybd, 152 CorePointerProc, CoreKeyboardProc, TRUE); 153 if (rc != Success) 154 goto unwind; 155 156 if (!c->send_core) 157 ptr->coreEvents = keybd->coreEvents = FALSE; 158 159 /* Allocate virtual slave devices for xtest events */ 160 rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, ptr, keybd); 161 if (rc != Success) 162 { 163 DeleteInputDeviceRequest(ptr); 164 DeleteInputDeviceRequest(keybd); 165 goto unwind; 166 } 167 168 ActivateDevice(ptr, FALSE); 169 ActivateDevice(keybd, FALSE); 170 flags[ptr->id] |= XIMasterAdded; 171 flags[keybd->id] |= XIMasterAdded; 172 173 ActivateDevice(XTestptr, FALSE); 174 ActivateDevice(XTestkeybd, FALSE); 175 flags[XTestptr->id] |= XISlaveAdded; 176 flags[XTestkeybd->id] |= XISlaveAdded; 177 178 if (c->enable) 179 { 180 EnableDevice(ptr, FALSE); 181 EnableDevice(keybd, FALSE); 182 flags[ptr->id] |= XIDeviceEnabled; 183 flags[keybd->id] |= XIDeviceEnabled; 184 185 EnableDevice(XTestptr, FALSE); 186 EnableDevice(XTestkeybd, FALSE); 187 flags[XTestptr->id] |= XIDeviceEnabled; 188 flags[XTestkeybd->id] |= XIDeviceEnabled; 189 } 190 191 /* Attach the XTest virtual devices to the newly 192 created master device */ 193 AttachDevice(NULL, XTestptr, ptr); 194 AttachDevice(NULL, XTestkeybd, keybd); 195 flags[XTestptr->id] |= XISlaveAttached; 196 flags[XTestkeybd->id] |= XISlaveAttached; 197 198unwind: 199 free(name); 200 return rc; 201} 202 203static int 204remove_master(ClientPtr client, xXIRemoveMasterInfo *r, 205 int flags[MAXDEVICES]) 206{ 207 DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd; 208 int rc = Success; 209 210 if (r->return_mode != XIAttachToMaster && 211 r->return_mode != XIFloating) 212 return BadValue; 213 214 rc = dixLookupDevice(&ptr, r->deviceid, client, DixDestroyAccess); 215 if (rc != Success) 216 goto unwind; 217 218 if (!IsMaster(ptr)) 219 { 220 client->errorValue = r->deviceid; 221 rc = BadDevice; 222 goto unwind; 223 } 224 225 /* XXX: For now, don't allow removal of VCP, VCK */ 226 if (ptr == inputInfo.pointer || ptr == inputInfo.keyboard) 227 { 228 rc = BadDevice; 229 goto unwind; 230 } 231 232 233 ptr = GetMaster(ptr, MASTER_POINTER); 234 rc = dixLookupDevice(&ptr, ptr->id, client, DixDestroyAccess); 235 if (rc != Success) 236 goto unwind; 237 keybd = GetMaster(ptr, MASTER_KEYBOARD); 238 rc = dixLookupDevice(&keybd, keybd->id, client, DixDestroyAccess); 239 if (rc != Success) 240 goto unwind; 241 242 XTestptr = GetXTestDevice(ptr); 243 rc = dixLookupDevice(&XTestptr, XTestptr->id, client, DixDestroyAccess); 244 if (rc != Success) 245 goto unwind; 246 247 XTestkeybd = GetXTestDevice(keybd); 248 rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, 249 DixDestroyAccess); 250 if (rc != Success) 251 goto unwind; 252 253 /* Disabling sends the devices floating, reattach them if 254 * desired. */ 255 if (r->return_mode == XIAttachToMaster) 256 { 257 DeviceIntPtr attached, 258 newptr, 259 newkeybd; 260 261 rc = dixLookupDevice(&newptr, r->return_pointer, client, DixAddAccess); 262 if (rc != Success) 263 goto unwind; 264 265 if (!IsMaster(newptr)) 266 { 267 client->errorValue = r->return_pointer; 268 rc = BadDevice; 269 goto unwind; 270 } 271 272 rc = dixLookupDevice(&newkeybd, r->return_keyboard, 273 client, DixAddAccess); 274 if (rc != Success) 275 goto unwind; 276 277 if (!IsMaster(newkeybd)) 278 { 279 client->errorValue = r->return_keyboard; 280 rc = BadDevice; 281 goto unwind; 282 } 283 284 for (attached = inputInfo.devices; attached; attached = attached->next) 285 { 286 if (!IsMaster(attached)) { 287 if (attached->u.master == ptr) 288 { 289 AttachDevice(client, attached, newptr); 290 flags[attached->id] |= XISlaveAttached; 291 } 292 if (attached->u.master == keybd) 293 { 294 AttachDevice(client, attached, newkeybd); 295 flags[attached->id] |= XISlaveAttached; 296 } 297 } 298 } 299 } 300 301 /* can't disable until we removed pairing */ 302 keybd->spriteInfo->paired = NULL; 303 ptr->spriteInfo->paired = NULL; 304 XTestptr->spriteInfo->paired = NULL; 305 XTestkeybd->spriteInfo->paired = NULL; 306 307 /* disable the remove the devices, XTest devices must be done first 308 else the sprites they rely on will be destroyed */ 309 DisableDevice(XTestptr, FALSE); 310 DisableDevice(XTestkeybd, FALSE); 311 DisableDevice(keybd, FALSE); 312 DisableDevice(ptr, FALSE); 313 flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached; 314 flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached; 315 flags[keybd->id] |= XIDeviceDisabled; 316 flags[ptr->id] |= XIDeviceDisabled; 317 318 RemoveDevice(XTestptr, FALSE); 319 RemoveDevice(XTestkeybd, FALSE); 320 RemoveDevice(keybd, FALSE); 321 RemoveDevice(ptr, FALSE); 322 flags[XTestptr->id] |= XISlaveRemoved; 323 flags[XTestkeybd->id] |= XISlaveRemoved; 324 flags[keybd->id] |= XIMasterRemoved; 325 flags[ptr->id] |= XIMasterRemoved; 326 327unwind: 328 return rc; 329} 330 331static int 332detach_slave(ClientPtr client, xXIDetachSlaveInfo *c, int flags[MAXDEVICES]) 333{ 334 DeviceIntPtr dev; 335 int rc; 336 337 rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess); 338 if (rc != Success) 339 goto unwind; 340 341 if (IsMaster(dev)) 342 { 343 client->errorValue = c->deviceid; 344 rc = BadDevice; 345 goto unwind; 346 } 347 348 /* Don't allow changes to XTest Devices, these are fixed */ 349 if (IsXTestDevice(dev, NULL)) 350 { 351 client->errorValue = c->deviceid; 352 rc = BadDevice; 353 goto unwind; 354 } 355 356 ReleaseButtonsAndKeys(dev); 357 AttachDevice(client, dev, NULL); 358 flags[dev->id] |= XISlaveDetached; 359 360unwind: 361 return rc; 362} 363 364static int 365attach_slave(ClientPtr client, xXIAttachSlaveInfo *c, 366 int flags[MAXDEVICES]) 367{ 368 DeviceIntPtr dev; 369 DeviceIntPtr newmaster; 370 int rc; 371 372 rc = dixLookupDevice(&dev, c->deviceid, client, DixManageAccess); 373 if (rc != Success) 374 goto unwind; 375 376 if (IsMaster(dev)) 377 { 378 client->errorValue = c->deviceid; 379 rc = BadDevice; 380 goto unwind; 381 } 382 383 /* Don't allow changes to XTest Devices, these are fixed */ 384 if (IsXTestDevice(dev, NULL)) 385 { 386 client->errorValue = c->deviceid; 387 rc = BadDevice; 388 goto unwind; 389 } 390 391 rc = dixLookupDevice(&newmaster, c->new_master, client, DixAddAccess); 392 if (rc != Success) 393 goto unwind; 394 if (!IsMaster(newmaster)) 395 { 396 client->errorValue = c->new_master; 397 rc = BadDevice; 398 goto unwind; 399 } 400 401 if (!((IsPointerDevice(newmaster) && IsPointerDevice(dev)) || 402 (IsKeyboardDevice(newmaster) && IsKeyboardDevice(dev)))) 403 { 404 rc = BadDevice; 405 goto unwind; 406 } 407 408 ReleaseButtonsAndKeys(dev); 409 AttachDevice(client, dev, newmaster); 410 flags[dev->id] |= XISlaveAttached; 411 412unwind: 413 return rc; 414} 415 416 417 418#define SWAPIF(cmd) if (client->swapped) { cmd; } 419 420int 421ProcXIChangeHierarchy(ClientPtr client) 422{ 423 xXIAnyHierarchyChangeInfo *any; 424 int required_len = sizeof(xXIChangeHierarchyReq); 425 char n; 426 int rc = Success; 427 int flags[MAXDEVICES] = {0}; 428 429 REQUEST(xXIChangeHierarchyReq); 430 REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq); 431 432 if (!stuff->num_changes) 433 return rc; 434 435 any = (xXIAnyHierarchyChangeInfo*)&stuff[1]; 436 while(stuff->num_changes--) 437 { 438 SWAPIF(swapl(&any->type, n)); 439 SWAPIF(swaps(&any->length, n)); 440 441 required_len += any->length; 442 if ((stuff->length * 4) < required_len) 443 return BadLength; 444 445 switch(any->type) 446 { 447 case XIAddMaster: 448 { 449 xXIAddMasterInfo* c = (xXIAddMasterInfo*)any; 450 SWAPIF(swaps(&c->name_len, n)); 451 452 rc = add_master(client, c, flags); 453 if (rc != Success) 454 goto unwind; 455 } 456 break; 457 case XIRemoveMaster: 458 { 459 xXIRemoveMasterInfo* r = (xXIRemoveMasterInfo*)any; 460 461 rc = remove_master(client, r, flags); 462 if (rc != Success) 463 goto unwind; 464 } 465 break; 466 case XIDetachSlave: 467 { 468 xXIDetachSlaveInfo* c = (xXIDetachSlaveInfo*)any; 469 470 rc = detach_slave(client, c, flags); 471 if (rc != Success) 472 goto unwind; 473 } 474 break; 475 case XIAttachSlave: 476 { 477 xXIAttachSlaveInfo* c = (xXIAttachSlaveInfo*)any; 478 479 rc = attach_slave(client, c, flags); 480 if (rc != Success) 481 goto unwind; 482 } 483 break; 484 } 485 486 any = (xXIAnyHierarchyChangeInfo*)((char*)any + any->length * 4); 487 } 488 489unwind: 490 491 XISendDeviceHierarchyEvent(flags); 492 return rc; 493} 494 495