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