xtest.c (20153B)
1 /* 2 3 Copyright 1992, 1998 The Open Group 4 5 Permission to use, copy, modify, distribute, and sell this software and its 6 documentation for any purpose is hereby granted without fee, provided that 7 the above copyright notice appear in all copies and that both that 8 copyright notice and this permission notice appear in supporting 9 documentation. 10 11 The above copyright notice and this permission notice shall be included 12 in all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 OTHER DEALINGS IN THE SOFTWARE. 21 22 Except as contained in this notice, the name of The Open Group shall 23 not be used in advertising or otherwise to promote the sale, use or 24 other dealings in this Software without prior written authorization 25 from The Open Group. 26 27 */ 28 29 #ifdef HAVE_DIX_CONFIG_H 30 #include <dix-config.h> 31 #endif 32 33 #include <X11/X.h> 34 #include <X11/Xproto.h> 35 #include <X11/Xatom.h> 36 #include "misc.h" 37 #include "os.h" 38 #include "dixstruct.h" 39 #include "extnsionst.h" 40 #include "windowstr.h" 41 #include "inputstr.h" 42 #include "scrnintstr.h" 43 #include "dixevents.h" 44 #include "sleepuntil.h" 45 #include "mi.h" 46 #include "xkbsrv.h" 47 #include "xkbstr.h" 48 #include <X11/extensions/xtestproto.h> 49 #include <X11/extensions/XI.h> 50 #include <X11/extensions/XIproto.h> 51 #include "exglobals.h" 52 #include "mipointer.h" 53 #include "xserver-properties.h" 54 #include "exevents.h" 55 #include "eventstr.h" 56 #include "inpututils.h" 57 58 #include "extinit.h" 59 60 /* XTest events are sent during request processing and may be interrupted by 61 * a SIGIO. We need a separate event list to avoid events overwriting each 62 * other's memory. 63 */ 64 static InternalEvent *xtest_evlist; 65 66 /** 67 * xtestpointer 68 * is the virtual pointer for XTest. It is the first slave 69 * device of the VCP. 70 * xtestkeyboard 71 * is the virtual keyboard for XTest. It is the first slave 72 * device of the VCK 73 * 74 * Neither of these devices can be deleted. 75 */ 76 DeviceIntPtr xtestpointer, xtestkeyboard; 77 78 #ifdef PANORAMIX 79 #include "panoramiX.h" 80 #include "panoramiXsrv.h" 81 #endif 82 83 static int XTestSwapFakeInput(ClientPtr /* client */ , 84 xReq * /* req */ 85 ); 86 87 static int 88 ProcXTestGetVersion(ClientPtr client) 89 { 90 xXTestGetVersionReply rep = { 91 .type = X_Reply, 92 .sequenceNumber = client->sequence, 93 .length = 0, 94 .majorVersion = XTestMajorVersion, 95 .minorVersion = XTestMinorVersion 96 }; 97 98 REQUEST_SIZE_MATCH(xXTestGetVersionReq); 99 100 if (client->swapped) { 101 swaps(&rep.sequenceNumber); 102 swaps(&rep.minorVersion); 103 } 104 WriteToClient(client, sizeof(xXTestGetVersionReply), &rep); 105 return Success; 106 } 107 108 static int 109 ProcXTestCompareCursor(ClientPtr client) 110 { 111 REQUEST(xXTestCompareCursorReq); 112 xXTestCompareCursorReply rep; 113 WindowPtr pWin; 114 CursorPtr pCursor; 115 int rc; 116 DeviceIntPtr ptr = PickPointer(client); 117 118 REQUEST_SIZE_MATCH(xXTestCompareCursorReq); 119 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 120 if (rc != Success) 121 return rc; 122 123 if (!ptr) 124 return BadAccess; 125 126 if (stuff->cursor == None) 127 pCursor = NullCursor; 128 else if (stuff->cursor == XTestCurrentCursor) 129 pCursor = GetSpriteCursor(ptr); 130 else { 131 rc = dixLookupResourceByType((void **) &pCursor, stuff->cursor, 132 RT_CURSOR, client, DixReadAccess); 133 if (rc != Success) { 134 client->errorValue = stuff->cursor; 135 return rc; 136 } 137 } 138 rep = (xXTestCompareCursorReply) { 139 .type = X_Reply, 140 .sequenceNumber = client->sequence, 141 .length = 0, 142 .same = (wCursor(pWin) == pCursor) 143 }; 144 if (client->swapped) { 145 swaps(&rep.sequenceNumber); 146 } 147 WriteToClient(client, sizeof(xXTestCompareCursorReply), &rep); 148 return Success; 149 } 150 151 static int 152 ProcXTestFakeInput(ClientPtr client) 153 { 154 REQUEST(xXTestFakeInputReq); 155 int nev, n, type, rc; 156 xEvent *ev; 157 DeviceIntPtr dev = NULL; 158 WindowPtr root; 159 Bool extension = FALSE; 160 ValuatorMask mask; 161 int valuators[MAX_VALUATORS] = { 0 }; 162 int numValuators = 0; 163 int firstValuator = 0; 164 int nevents = 0; 165 int i; 166 int base = 0; 167 int flags = 0; 168 int need_ptr_update = 1; 169 170 nev = (stuff->length << 2) - sizeof(xReq); 171 if ((nev % sizeof(xEvent)) || !nev) 172 return BadLength; 173 nev /= sizeof(xEvent); 174 UpdateCurrentTime(); 175 ev = (xEvent *) &((xReq *) stuff)[1]; 176 type = ev->u.u.type & 0177; 177 178 if (type >= EXTENSION_EVENT_BASE) { 179 extension = TRUE; 180 181 /* check device */ 182 rc = dixLookupDevice(&dev, stuff->deviceid & 0177, client, 183 DixWriteAccess); 184 if (rc != Success) { 185 client->errorValue = stuff->deviceid & 0177; 186 return rc; 187 } 188 189 /* check type */ 190 type -= DeviceValuator; 191 switch (type) { 192 case XI_DeviceKeyPress: 193 case XI_DeviceKeyRelease: 194 if (!dev->key) { 195 client->errorValue = ev->u.u.type; 196 return BadValue; 197 } 198 break; 199 case XI_DeviceButtonPress: 200 case XI_DeviceButtonRelease: 201 if (!dev->button) { 202 client->errorValue = ev->u.u.type; 203 return BadValue; 204 } 205 break; 206 case XI_DeviceMotionNotify: 207 if (!dev->valuator) { 208 client->errorValue = ev->u.u.type; 209 return BadValue; 210 } 211 break; 212 case XI_ProximityIn: 213 case XI_ProximityOut: 214 if (!dev->proximity) { 215 client->errorValue = ev->u.u.type; 216 return BadValue; 217 } 218 break; 219 default: 220 client->errorValue = ev->u.u.type; 221 return BadValue; 222 } 223 224 /* check validity */ 225 if (nev == 1 && type == XI_DeviceMotionNotify) 226 return BadLength; /* DevMotion must be followed by DevValuator */ 227 228 if (type == XI_DeviceMotionNotify) { 229 firstValuator = ((deviceValuator *) (ev + 1))->first_valuator; 230 if (firstValuator > dev->valuator->numAxes) { 231 client->errorValue = ev->u.u.type; 232 return BadValue; 233 } 234 235 if (ev->u.u.detail == xFalse) 236 flags |= POINTER_ABSOLUTE; 237 } 238 else { 239 firstValuator = 0; 240 flags |= POINTER_ABSOLUTE; 241 } 242 243 if (nev > 1 && !dev->valuator) { 244 client->errorValue = firstValuator; 245 return BadValue; 246 } 247 248 /* check validity of valuator events */ 249 base = firstValuator; 250 for (n = 1; n < nev; n++) { 251 deviceValuator *dv = (deviceValuator *) (ev + n); 252 if (dv->type != DeviceValuator) { 253 client->errorValue = dv->type; 254 return BadValue; 255 } 256 if (dv->first_valuator != base) { 257 client->errorValue = dv->first_valuator; 258 return BadValue; 259 } 260 switch (dv->num_valuators) { 261 case 6: 262 valuators[base + 5] = dv->valuator5; 263 case 5: 264 valuators[base + 4] = dv->valuator4; 265 case 4: 266 valuators[base + 3] = dv->valuator3; 267 case 3: 268 valuators[base + 2] = dv->valuator2; 269 case 2: 270 valuators[base + 1] = dv->valuator1; 271 case 1: 272 valuators[base] = dv->valuator0; 273 break; 274 default: 275 client->errorValue = dv->num_valuators; 276 return BadValue; 277 } 278 279 base += dv->num_valuators; 280 numValuators += dv->num_valuators; 281 282 if (firstValuator + numValuators > dev->valuator->numAxes) { 283 client->errorValue = dv->num_valuators; 284 return BadValue; 285 } 286 } 287 type = type - XI_DeviceKeyPress + KeyPress; 288 289 } 290 else { 291 if (nev != 1) 292 return BadLength; 293 switch (type) { 294 case KeyPress: 295 case KeyRelease: 296 dev = PickKeyboard(client); 297 break; 298 case ButtonPress: 299 case ButtonRelease: 300 dev = PickPointer(client); 301 break; 302 case MotionNotify: 303 dev = PickPointer(client); 304 valuators[0] = ev->u.keyButtonPointer.rootX; 305 valuators[1] = ev->u.keyButtonPointer.rootY; 306 numValuators = 2; 307 firstValuator = 0; 308 if (ev->u.u.detail == xFalse) 309 flags = POINTER_ABSOLUTE | POINTER_DESKTOP; 310 break; 311 default: 312 client->errorValue = ev->u.u.type; 313 return BadValue; 314 } 315 316 /* Technically the protocol doesn't allow for BadAccess here but 317 * this can only happen when all MDs are disabled. */ 318 if (!dev) 319 return BadAccess; 320 321 dev = GetXTestDevice(dev); 322 } 323 324 325 /* If the event has a time set, wait for it to pass */ 326 if (ev->u.keyButtonPointer.time) { 327 TimeStamp activateTime; 328 CARD32 ms; 329 330 activateTime = currentTime; 331 ms = activateTime.milliseconds + ev->u.keyButtonPointer.time; 332 if (ms < activateTime.milliseconds) 333 activateTime.months++; 334 activateTime.milliseconds = ms; 335 ev->u.keyButtonPointer.time = 0; 336 337 /* see mbuf.c:QueueDisplayRequest (from the deprecated Multibuffer 338 * extension) for code similar to this */ 339 340 if (!ClientSleepUntil(client, &activateTime, NULL, NULL)) { 341 return BadAlloc; 342 } 343 /* swap the request back so we can simply re-execute it */ 344 if (client->swapped) { 345 (void) XTestSwapFakeInput(client, (xReq *) stuff); 346 swaps(&stuff->length); 347 } 348 ResetCurrentRequest(client); 349 client->sequence--; 350 return Success; 351 } 352 353 switch (type) { 354 case KeyPress: 355 case KeyRelease: 356 if (!dev->key) 357 return BadDevice; 358 359 if (ev->u.u.detail < dev->key->xkbInfo->desc->min_key_code || 360 ev->u.u.detail > dev->key->xkbInfo->desc->max_key_code) { 361 client->errorValue = ev->u.u.detail; 362 return BadValue; 363 } 364 365 need_ptr_update = 0; 366 break; 367 case MotionNotify: 368 if (!dev->valuator) 369 return BadDevice; 370 371 if (!(extension || ev->u.keyButtonPointer.root == None)) { 372 rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root, 373 client, DixGetAttrAccess); 374 if (rc != Success) 375 return rc; 376 if (root->parent) { 377 client->errorValue = ev->u.keyButtonPointer.root; 378 return BadValue; 379 } 380 381 /* Add the root window's offset to the valuators */ 382 if ((flags & POINTER_ABSOLUTE) && firstValuator <= 1 && numValuators > 0) { 383 if (firstValuator == 0) 384 valuators[0] += root->drawable.pScreen->x; 385 if (firstValuator < 2 && firstValuator + numValuators > 1) 386 valuators[1 - firstValuator] += root->drawable.pScreen->y; 387 } 388 } 389 if (ev->u.u.detail != xTrue && ev->u.u.detail != xFalse) { 390 client->errorValue = ev->u.u.detail; 391 return BadValue; 392 } 393 394 /* FIXME: Xinerama! */ 395 396 break; 397 case ButtonPress: 398 case ButtonRelease: 399 if (!dev->button) 400 return BadDevice; 401 402 if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons) { 403 client->errorValue = ev->u.u.detail; 404 return BadValue; 405 } 406 break; 407 } 408 if (screenIsSaved == SCREEN_SAVER_ON) 409 dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); 410 411 switch (type) { 412 case MotionNotify: 413 valuator_mask_set_range(&mask, firstValuator, numValuators, valuators); 414 nevents = GetPointerEvents(xtest_evlist, dev, type, 0, flags, &mask); 415 break; 416 case ButtonPress: 417 case ButtonRelease: 418 valuator_mask_set_range(&mask, firstValuator, numValuators, valuators); 419 nevents = GetPointerEvents(xtest_evlist, dev, type, ev->u.u.detail, 420 flags, &mask); 421 break; 422 case KeyPress: 423 case KeyRelease: 424 nevents = 425 GetKeyboardEvents(xtest_evlist, dev, type, ev->u.u.detail); 426 break; 427 } 428 429 for (i = 0; i < nevents; i++) 430 mieqProcessDeviceEvent(dev, &xtest_evlist[i], miPointerGetScreen(inputInfo.pointer)); 431 432 if (need_ptr_update) 433 miPointerUpdateSprite(dev); 434 return Success; 435 } 436 437 static int 438 ProcXTestGrabControl(ClientPtr client) 439 { 440 REQUEST(xXTestGrabControlReq); 441 442 REQUEST_SIZE_MATCH(xXTestGrabControlReq); 443 if ((stuff->impervious != xTrue) && (stuff->impervious != xFalse)) { 444 client->errorValue = stuff->impervious; 445 return BadValue; 446 } 447 if (stuff->impervious) 448 MakeClientGrabImpervious(client); 449 else 450 MakeClientGrabPervious(client); 451 return Success; 452 } 453 454 static int 455 ProcXTestDispatch(ClientPtr client) 456 { 457 REQUEST(xReq); 458 switch (stuff->data) { 459 case X_XTestGetVersion: 460 return ProcXTestGetVersion(client); 461 case X_XTestCompareCursor: 462 return ProcXTestCompareCursor(client); 463 case X_XTestFakeInput: 464 return ProcXTestFakeInput(client); 465 case X_XTestGrabControl: 466 return ProcXTestGrabControl(client); 467 default: 468 return BadRequest; 469 } 470 } 471 472 static int _X_COLD 473 SProcXTestGetVersion(ClientPtr client) 474 { 475 REQUEST(xXTestGetVersionReq); 476 477 swaps(&stuff->length); 478 REQUEST_SIZE_MATCH(xXTestGetVersionReq); 479 swaps(&stuff->minorVersion); 480 return ProcXTestGetVersion(client); 481 } 482 483 static int _X_COLD 484 SProcXTestCompareCursor(ClientPtr client) 485 { 486 REQUEST(xXTestCompareCursorReq); 487 488 swaps(&stuff->length); 489 REQUEST_SIZE_MATCH(xXTestCompareCursorReq); 490 swapl(&stuff->window); 491 swapl(&stuff->cursor); 492 return ProcXTestCompareCursor(client); 493 } 494 495 static int _X_COLD 496 XTestSwapFakeInput(ClientPtr client, xReq * req) 497 { 498 int nev; 499 xEvent *ev; 500 xEvent sev; 501 EventSwapPtr proc; 502 503 nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent); 504 for (ev = (xEvent *) &req[1]; --nev >= 0; ev++) { 505 /* Swap event */ 506 proc = EventSwapVector[ev->u.u.type & 0177]; 507 /* no swapping proc; invalid event type? */ 508 if (!proc || proc == NotImplemented) { 509 client->errorValue = ev->u.u.type; 510 return BadValue; 511 } 512 (*proc) (ev, &sev); 513 *ev = sev; 514 } 515 return Success; 516 } 517 518 static int _X_COLD 519 SProcXTestFakeInput(ClientPtr client) 520 { 521 int n; 522 523 REQUEST(xReq); 524 525 swaps(&stuff->length); 526 n = XTestSwapFakeInput(client, stuff); 527 if (n != Success) 528 return n; 529 return ProcXTestFakeInput(client); 530 } 531 532 static int _X_COLD 533 SProcXTestGrabControl(ClientPtr client) 534 { 535 REQUEST(xXTestGrabControlReq); 536 537 swaps(&stuff->length); 538 REQUEST_SIZE_MATCH(xXTestGrabControlReq); 539 return ProcXTestGrabControl(client); 540 } 541 542 static int _X_COLD 543 SProcXTestDispatch(ClientPtr client) 544 { 545 REQUEST(xReq); 546 switch (stuff->data) { 547 case X_XTestGetVersion: 548 return SProcXTestGetVersion(client); 549 case X_XTestCompareCursor: 550 return SProcXTestCompareCursor(client); 551 case X_XTestFakeInput: 552 return SProcXTestFakeInput(client); 553 case X_XTestGrabControl: 554 return SProcXTestGrabControl(client); 555 default: 556 return BadRequest; 557 } 558 } 559 560 /** 561 * Allocate an virtual slave device for xtest events, this 562 * is a slave device to inputInfo master devices 563 */ 564 void 565 InitXTestDevices(void) 566 { 567 if (AllocXTestDevice(serverClient, "Virtual core", 568 &xtestpointer, &xtestkeyboard, 569 inputInfo.pointer, inputInfo.keyboard) != Success) 570 FatalError("Failed to allocate XTest devices"); 571 572 if (ActivateDevice(xtestpointer, TRUE) != Success || 573 ActivateDevice(xtestkeyboard, TRUE) != Success) 574 FatalError("Failed to activate XTest core devices."); 575 if (!EnableDevice(xtestpointer, TRUE) || !EnableDevice(xtestkeyboard, TRUE)) 576 FatalError("Failed to enable XTest core devices."); 577 578 AttachDevice(NULL, xtestpointer, inputInfo.pointer); 579 580 AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard); 581 } 582 583 /** 584 * Don't allow changing the XTest property. 585 */ 586 static int 587 DeviceSetXTestProperty(DeviceIntPtr dev, Atom property, 588 XIPropertyValuePtr prop, BOOL checkonly) 589 { 590 if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE)) 591 return BadAccess; 592 593 return Success; 594 } 595 596 /** 597 * Allocate a device pair that is initialised as a slave 598 * device with properties that identify the devices as belonging 599 * to XTest subsystem. 600 * This only creates the pair, Activate/Enable Device 601 * still need to be called. 602 */ 603 int 604 AllocXTestDevice(ClientPtr client, const char *name, 605 DeviceIntPtr *ptr, DeviceIntPtr *keybd, 606 DeviceIntPtr master_ptr, DeviceIntPtr master_keybd) 607 { 608 int retval; 609 char *xtestname; 610 char dummy = 1; 611 612 if (asprintf(&xtestname, "%s XTEST", name) == -1) 613 return BadAlloc; 614 615 retval = 616 AllocDevicePair(client, xtestname, ptr, keybd, CorePointerProc, 617 CoreKeyboardProc, FALSE); 618 if (retval == Success) { 619 (*ptr)->xtest_master_id = master_ptr->id; 620 (*keybd)->xtest_master_id = master_keybd->id; 621 622 XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 623 XA_INTEGER, 8, PropModeReplace, 1, &dummy, 624 FALSE); 625 XISetDevicePropertyDeletable(*ptr, 626 XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 627 FALSE); 628 XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL); 629 XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 630 XA_INTEGER, 8, PropModeReplace, 1, &dummy, 631 FALSE); 632 XISetDevicePropertyDeletable(*keybd, 633 XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 634 FALSE); 635 XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL); 636 } 637 638 free(xtestname); 639 640 return retval; 641 } 642 643 /** 644 * If master is NULL, return TRUE if the given device is an xtest device or 645 * FALSE otherwise. 646 * If master is not NULL, return TRUE if the given device is this master's 647 * xtest device. 648 */ 649 BOOL 650 IsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master) 651 { 652 if (IsMaster(dev)) 653 return FALSE; 654 655 /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest 656 * device */ 657 if (master) 658 return dev->xtest_master_id == master->id; 659 660 return dev->xtest_master_id != 0; 661 } 662 663 /** 664 * @return The X Test virtual device for the given master. 665 */ 666 DeviceIntPtr 667 GetXTestDevice(DeviceIntPtr master) 668 { 669 DeviceIntPtr it; 670 671 for (it = inputInfo.devices; it; it = it->next) { 672 if (IsXTestDevice(it, master)) 673 return it; 674 } 675 676 /* This only happens if master is a slave device. don't do that */ 677 return NULL; 678 } 679 680 static void 681 XTestExtensionTearDown(ExtensionEntry * e) 682 { 683 FreeEventList(xtest_evlist, GetMaximumEventsNum()); 684 xtest_evlist = NULL; 685 } 686 687 void 688 XTestExtensionInit(void) 689 { 690 AddExtension(XTestExtensionName, 0, 0, 691 ProcXTestDispatch, SProcXTestDispatch, 692 XTestExtensionTearDown, StandardMinorOpcode); 693 694 xtest_evlist = InitEventList(GetMaximumEventsNum()); 695 }