xtest.c revision 2d19872a
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 */ 64static 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 */ 76DeviceIntPtr xtestpointer, xtestkeyboard; 77 78#ifdef PANORAMIX 79#include "panoramiX.h" 80#include "panoramiXsrv.h" 81#endif 82 83static int XTestSwapFakeInput(ClientPtr /* client */ , 84 xReq * /* req */ 85 ); 86 87static int 88ProcXTestGetVersion(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 108static int 109ProcXTestCompareCursor(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 151static int 152ProcXTestFakeInput(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 437static int 438ProcXTestGrabControl(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 454static int 455ProcXTestDispatch(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 472static int _X_COLD 473SProcXTestGetVersion(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 483static int _X_COLD 484SProcXTestCompareCursor(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 495static int _X_COLD 496XTestSwapFakeInput(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 int evtype = ev->u.u.type & 0177; 506 /* Swap event */ 507 proc = EventSwapVector[evtype]; 508 /* no swapping proc; invalid event type? */ 509 if (!proc || proc == NotImplemented || evtype == GenericEvent) { 510 client->errorValue = ev->u.u.type; 511 return BadValue; 512 } 513 (*proc) (ev, &sev); 514 *ev = sev; 515 } 516 return Success; 517} 518 519static int _X_COLD 520SProcXTestFakeInput(ClientPtr client) 521{ 522 int n; 523 524 REQUEST(xReq); 525 526 swaps(&stuff->length); 527 n = XTestSwapFakeInput(client, stuff); 528 if (n != Success) 529 return n; 530 return ProcXTestFakeInput(client); 531} 532 533static int _X_COLD 534SProcXTestGrabControl(ClientPtr client) 535{ 536 REQUEST(xXTestGrabControlReq); 537 538 swaps(&stuff->length); 539 REQUEST_SIZE_MATCH(xXTestGrabControlReq); 540 return ProcXTestGrabControl(client); 541} 542 543static int _X_COLD 544SProcXTestDispatch(ClientPtr client) 545{ 546 REQUEST(xReq); 547 switch (stuff->data) { 548 case X_XTestGetVersion: 549 return SProcXTestGetVersion(client); 550 case X_XTestCompareCursor: 551 return SProcXTestCompareCursor(client); 552 case X_XTestFakeInput: 553 return SProcXTestFakeInput(client); 554 case X_XTestGrabControl: 555 return SProcXTestGrabControl(client); 556 default: 557 return BadRequest; 558 } 559} 560 561/** 562 * Allocate an virtual slave device for xtest events, this 563 * is a slave device to inputInfo master devices 564 */ 565void 566InitXTestDevices(void) 567{ 568 if (AllocXTestDevice(serverClient, "Virtual core", 569 &xtestpointer, &xtestkeyboard, 570 inputInfo.pointer, inputInfo.keyboard) != Success) 571 FatalError("Failed to allocate XTest devices"); 572 573 if (ActivateDevice(xtestpointer, TRUE) != Success || 574 ActivateDevice(xtestkeyboard, TRUE) != Success) 575 FatalError("Failed to activate XTest core devices."); 576 if (!EnableDevice(xtestpointer, TRUE) || !EnableDevice(xtestkeyboard, TRUE)) 577 FatalError("Failed to enable XTest core devices."); 578 579 AttachDevice(NULL, xtestpointer, inputInfo.pointer); 580 581 AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard); 582} 583 584/** 585 * Don't allow changing the XTest property. 586 */ 587static int 588DeviceSetXTestProperty(DeviceIntPtr dev, Atom property, 589 XIPropertyValuePtr prop, BOOL checkonly) 590{ 591 if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE)) 592 return BadAccess; 593 594 return Success; 595} 596 597/** 598 * Allocate a device pair that is initialised as a slave 599 * device with properties that identify the devices as belonging 600 * to XTest subsystem. 601 * This only creates the pair, Activate/Enable Device 602 * still need to be called. 603 */ 604int 605AllocXTestDevice(ClientPtr client, const char *name, 606 DeviceIntPtr *ptr, DeviceIntPtr *keybd, 607 DeviceIntPtr master_ptr, DeviceIntPtr master_keybd) 608{ 609 int retval; 610 char *xtestname; 611 char dummy = 1; 612 613 if (asprintf(&xtestname, "%s XTEST", name) == -1) 614 return BadAlloc; 615 616 retval = 617 AllocDevicePair(client, xtestname, ptr, keybd, CorePointerProc, 618 CoreKeyboardProc, FALSE); 619 if (retval == Success) { 620 (*ptr)->xtest_master_id = master_ptr->id; 621 (*keybd)->xtest_master_id = master_keybd->id; 622 623 XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 624 XA_INTEGER, 8, PropModeReplace, 1, &dummy, 625 FALSE); 626 XISetDevicePropertyDeletable(*ptr, 627 XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 628 FALSE); 629 XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL); 630 XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 631 XA_INTEGER, 8, PropModeReplace, 1, &dummy, 632 FALSE); 633 XISetDevicePropertyDeletable(*keybd, 634 XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 635 FALSE); 636 XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL); 637 } 638 639 free(xtestname); 640 641 return retval; 642} 643 644/** 645 * If master is NULL, return TRUE if the given device is an xtest device or 646 * FALSE otherwise. 647 * If master is not NULL, return TRUE if the given device is this master's 648 * xtest device. 649 */ 650BOOL 651IsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master) 652{ 653 if (IsMaster(dev)) 654 return FALSE; 655 656 /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest 657 * device */ 658 if (master) 659 return dev->xtest_master_id == master->id; 660 661 return dev->xtest_master_id != 0; 662} 663 664/** 665 * @return The X Test virtual device for the given master. 666 */ 667DeviceIntPtr 668GetXTestDevice(DeviceIntPtr master) 669{ 670 DeviceIntPtr it; 671 672 for (it = inputInfo.devices; it; it = it->next) { 673 if (IsXTestDevice(it, master)) 674 return it; 675 } 676 677 /* This only happens if master is a slave device. don't do that */ 678 return NULL; 679} 680 681static void 682XTestExtensionTearDown(ExtensionEntry * e) 683{ 684 FreeEventList(xtest_evlist, GetMaximumEventsNum()); 685 xtest_evlist = NULL; 686} 687 688void 689XTestExtensionInit(void) 690{ 691 AddExtension(XTestExtensionName, 0, 0, 692 ProcXTestDispatch, SProcXTestDispatch, 693 XTestExtensionTearDown, StandardMinorOpcode); 694 695 xtest_evlist = InitEventList(GetMaximumEventsNum()); 696} 697