xichangehierarchy.c revision 6747b715
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 ev->type = GenericEvent; 74 ev->extension = IReqCode; 75 ev->evtype = XI_HierarchyChanged; 76 ev->time = GetTimeInMillis(); 77 ev->flags = 0; 78 ev->num_info = inputInfo.numDevices; 79 80 info = (xXIHierarchyInfo*)&ev[1]; 81 for (dev = inputInfo.devices; dev; dev = dev->next) 82 { 83 info->deviceid = dev->id; 84 info->enabled = dev->enabled; 85 info->use = GetDeviceUse(dev, &info->attachment); 86 info->flags = flags[dev->id]; 87 ev->flags |= info->flags; 88 info++; 89 } 90 for (dev = inputInfo.off_devices; dev; dev = dev->next) 91 { 92 info->deviceid = dev->id; 93 info->enabled = dev->enabled; 94 info->use = GetDeviceUse(dev, &info->attachment); 95 info->flags = flags[dev->id]; 96 ev->flags |= info->flags; 97 info++; 98 } 99 100 101 for (i = 0; i < MAXDEVICES; i++) 102 { 103 if (flags[i] & (XIMasterRemoved | XISlaveRemoved)) 104 { 105 info->deviceid = i; 106 info->enabled = FALSE; 107 info->flags = flags[i]; 108 info->use = 0; 109 ev->flags |= info->flags; 110 ev->num_info++; 111 info++; 112 } 113 } 114 115 ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo)); 116 117 dummyDev.id = XIAllDevices; 118 SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8), (xEvent*)ev, 1); 119 free(ev); 120} 121 122 123/*********************************************************************** 124 * 125 * This procedure allows a client to change the device hierarchy through 126 * adding new master devices, removing them, etc. 127 * 128 */ 129 130int SProcXIChangeHierarchy(ClientPtr client) 131{ 132 char n; 133 134 REQUEST(xXIChangeHierarchyReq); 135 swaps(&stuff->length, n); 136 return (ProcXIChangeHierarchy(client)); 137} 138 139#define SWAPIF(cmd) if (client->swapped) { cmd; } 140 141int 142ProcXIChangeHierarchy(ClientPtr client) 143{ 144 DeviceIntPtr ptr, keybd, XTestptr, XTestkeybd; 145 xXIAnyHierarchyChangeInfo *any; 146 int required_len = sizeof(xXIChangeHierarchyReq); 147 char n; 148 int rc = Success; 149 int flags[MAXDEVICES] = {0}; 150 151 REQUEST(xXIChangeHierarchyReq); 152 REQUEST_AT_LEAST_SIZE(xXIChangeHierarchyReq); 153 154 if (!stuff->num_changes) 155 return rc; 156 157 any = (xXIAnyHierarchyChangeInfo*)&stuff[1]; 158 while(stuff->num_changes--) 159 { 160 SWAPIF(swapl(&any->type, n)); 161 SWAPIF(swaps(&any->length, n)); 162 163 required_len += any->length; 164 if ((stuff->length * 4) < required_len) 165 return BadLength; 166 167 switch(any->type) 168 { 169 case XIAddMaster: 170 { 171 xXIAddMasterInfo* c = (xXIAddMasterInfo*)any; 172 char* name; 173 174 SWAPIF(swaps(&c->name_len, n)); 175 name = calloc(c->name_len + 1, sizeof(char)); 176 strncpy(name, (char*)&c[1], c->name_len); 177 178 179 rc = AllocDevicePair(client, name, &ptr, &keybd, 180 CorePointerProc, CoreKeyboardProc, 181 TRUE); 182 if (rc != Success) 183 { 184 free(name); 185 goto unwind; 186 } 187 188 if (!c->send_core) 189 ptr->coreEvents = keybd->coreEvents = FALSE; 190 191 /* Allocate virtual slave devices for xtest events */ 192 rc = AllocXTestDevice(client, name, &XTestptr, &XTestkeybd, 193 ptr, keybd); 194 if (rc != Success) 195 { 196 197 free(name); 198 goto unwind; 199 } 200 201 ActivateDevice(ptr, FALSE); 202 ActivateDevice(keybd, FALSE); 203 flags[ptr->id] |= XIMasterAdded; 204 flags[keybd->id] |= XIMasterAdded; 205 206 ActivateDevice(XTestptr, FALSE); 207 ActivateDevice(XTestkeybd, FALSE); 208 flags[XTestptr->id] |= XISlaveAdded; 209 flags[XTestkeybd->id] |= XISlaveAdded; 210 211 if (c->enable) 212 { 213 EnableDevice(ptr, FALSE); 214 EnableDevice(keybd, FALSE); 215 flags[ptr->id] |= XIDeviceEnabled; 216 flags[keybd->id] |= XIDeviceEnabled; 217 218 EnableDevice(XTestptr, FALSE); 219 EnableDevice(XTestkeybd, FALSE); 220 flags[XTestptr->id] |= XIDeviceEnabled; 221 flags[XTestkeybd->id] |= XIDeviceEnabled; 222 } 223 224 /* Attach the XTest virtual devices to the newly 225 created master device */ 226 AttachDevice(NULL, XTestptr, ptr); 227 AttachDevice(NULL, XTestkeybd, keybd); 228 flags[XTestptr->id] |= XISlaveAttached; 229 flags[XTestkeybd->id] |= XISlaveAttached; 230 231 free(name); 232 } 233 break; 234 case XIRemoveMaster: 235 { 236 xXIRemoveMasterInfo* r = (xXIRemoveMasterInfo*)any; 237 238 if (r->return_mode != XIAttachToMaster && 239 r->return_mode != XIFloating) 240 return BadValue; 241 242 rc = dixLookupDevice(&ptr, r->deviceid, client, 243 DixDestroyAccess); 244 if (rc != Success) 245 goto unwind; 246 247 if (!IsMaster(ptr)) 248 { 249 client->errorValue = r->deviceid; 250 rc = BadDevice; 251 goto unwind; 252 } 253 254 /* XXX: For now, don't allow removal of VCP, VCK */ 255 if (ptr == inputInfo.pointer || 256 ptr == inputInfo.keyboard) 257 { 258 rc = BadDevice; 259 goto unwind; 260 } 261 262 263 ptr = GetMaster(ptr, MASTER_POINTER); 264 rc = dixLookupDevice(&ptr, 265 ptr->id, 266 client, 267 DixDestroyAccess); 268 if (rc != Success) 269 goto unwind; 270 keybd = GetMaster(ptr, MASTER_KEYBOARD); 271 rc = dixLookupDevice(&keybd, 272 keybd->id, 273 client, 274 DixDestroyAccess); 275 if (rc != Success) 276 goto unwind; 277 278 XTestptr = GetXTestDevice(ptr); 279 rc = dixLookupDevice(&XTestptr, XTestptr->id, client, 280 DixDestroyAccess); 281 if (rc != Success) 282 goto unwind; 283 284 XTestkeybd = GetXTestDevice(keybd); 285 rc = dixLookupDevice(&XTestkeybd, XTestkeybd->id, client, 286 DixDestroyAccess); 287 if (rc != Success) 288 goto unwind; 289 290 /* Disabling sends the devices floating, reattach them if 291 * desired. */ 292 if (r->return_mode == XIAttachToMaster) 293 { 294 DeviceIntPtr attached, 295 newptr, 296 newkeybd; 297 298 rc = dixLookupDevice(&newptr, r->return_pointer, 299 client, DixAddAccess); 300 if (rc != Success) 301 goto unwind; 302 303 if (!IsMaster(newptr)) 304 { 305 client->errorValue = r->return_pointer; 306 rc = BadDevice; 307 goto unwind; 308 } 309 310 rc = dixLookupDevice(&newkeybd, r->return_keyboard, 311 client, DixAddAccess); 312 if (rc != Success) 313 goto unwind; 314 315 if (!IsMaster(newkeybd)) 316 { 317 client->errorValue = r->return_keyboard; 318 rc = BadDevice; 319 goto unwind; 320 } 321 322 for (attached = inputInfo.devices; 323 attached; 324 attached = attached->next) 325 { 326 if (!IsMaster(attached)) { 327 if (attached->u.master == ptr) 328 { 329 AttachDevice(client, attached, newptr); 330 flags[attached->id] |= XISlaveAttached; 331 } 332 if (attached->u.master == keybd) 333 { 334 AttachDevice(client, attached, newkeybd); 335 flags[attached->id] |= XISlaveAttached; 336 } 337 } 338 } 339 } 340 341 /* can't disable until we removed pairing */ 342 keybd->spriteInfo->paired = NULL; 343 ptr->spriteInfo->paired = NULL; 344 XTestptr->spriteInfo->paired = NULL; 345 XTestkeybd->spriteInfo->paired = NULL; 346 347 /* disable the remove the devices, XTest devices must be done first 348 else the sprites they rely on will be destroyed */ 349 DisableDevice(XTestptr, FALSE); 350 DisableDevice(XTestkeybd, FALSE); 351 DisableDevice(keybd, FALSE); 352 DisableDevice(ptr, FALSE); 353 flags[XTestptr->id] |= XIDeviceDisabled | XISlaveDetached; 354 flags[XTestkeybd->id] |= XIDeviceDisabled | XISlaveDetached; 355 flags[keybd->id] |= XIDeviceDisabled; 356 flags[ptr->id] |= XIDeviceDisabled; 357 358 RemoveDevice(XTestptr, FALSE); 359 RemoveDevice(XTestkeybd, FALSE); 360 RemoveDevice(keybd, FALSE); 361 RemoveDevice(ptr, FALSE); 362 flags[XTestptr->id] |= XISlaveRemoved; 363 flags[XTestkeybd->id] |= XISlaveRemoved; 364 flags[keybd->id] |= XIMasterRemoved; 365 flags[ptr->id] |= XIMasterRemoved; 366 } 367 break; 368 case XIDetachSlave: 369 { 370 xXIDetachSlaveInfo* c = (xXIDetachSlaveInfo*)any; 371 372 rc = dixLookupDevice(&ptr, c->deviceid, client, 373 DixManageAccess); 374 if (rc != Success) 375 goto unwind; 376 377 if (IsMaster(ptr)) 378 { 379 client->errorValue = c->deviceid; 380 rc = BadDevice; 381 goto unwind; 382 } 383 384 /* Don't allow changes to XTest Devices, these are fixed */ 385 if (IsXTestDevice(ptr, NULL)) 386 { 387 client->errorValue = c->deviceid; 388 rc = BadDevice; 389 goto unwind; 390 } 391 392 AttachDevice(client, ptr, NULL); 393 flags[ptr->id] |= XISlaveDetached; 394 } 395 break; 396 case XIAttachSlave: 397 { 398 xXIAttachSlaveInfo* c = (xXIAttachSlaveInfo*)any; 399 DeviceIntPtr newmaster; 400 401 rc = dixLookupDevice(&ptr, c->deviceid, client, 402 DixManageAccess); 403 if (rc != Success) 404 goto unwind; 405 406 if (IsMaster(ptr)) 407 { 408 client->errorValue = c->deviceid; 409 rc = BadDevice; 410 goto unwind; 411 } 412 413 /* Don't allow changes to XTest Devices, these are fixed */ 414 if (IsXTestDevice(ptr, NULL)) 415 { 416 client->errorValue = c->deviceid; 417 rc = BadDevice; 418 goto unwind; 419 } 420 421 rc = dixLookupDevice(&newmaster, c->new_master, 422 client, DixAddAccess); 423 if (rc != Success) 424 goto unwind; 425 if (!IsMaster(newmaster)) 426 { 427 client->errorValue = c->new_master; 428 rc = BadDevice; 429 goto unwind; 430 } 431 432 if (!((IsPointerDevice(newmaster) && 433 IsPointerDevice(ptr)) || 434 (IsKeyboardDevice(newmaster) && 435 IsKeyboardDevice(ptr)))) 436 { 437 rc = BadDevice; 438 goto unwind; 439 } 440 AttachDevice(client, ptr, newmaster); 441 flags[ptr->id] |= XISlaveAttached; 442 } 443 break; 444 } 445 446 any = (xXIAnyHierarchyChangeInfo*)((char*)any + any->length * 4); 447 } 448 449unwind: 450 451 XISendDeviceHierarchyEvent(flags); 452 return rc; 453} 454 455