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