xtest.c revision 05b261ec
1/* 2 3Copyright 1992, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from 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#define NEED_EVENTS 35#include <X11/Xproto.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#define _XTEST_SERVER_ 46#include <X11/extensions/XTest.h> 47#include <X11/extensions/xteststr.h> 48#ifdef XINPUT 49#include <X11/extensions/XI.h> 50#include <X11/extensions/XIproto.h> 51#define EXTENSION_EVENT_BASE 64 52#include "extinit.h" /* LookupDeviceIntRec */ 53#endif /* XINPUT */ 54 55#include "modinit.h" 56 57#if 0 58static unsigned char XTestReqCode; 59#endif 60 61#ifdef XINPUT 62extern int DeviceValuator; 63#endif /* XINPUT */ 64 65#ifdef PANORAMIX 66#include "panoramiX.h" 67#include "panoramiXsrv.h" 68#endif 69 70static void XTestResetProc( 71 ExtensionEntry * /* extEntry */ 72); 73static int XTestSwapFakeInput( 74 ClientPtr /* client */, 75 xReq * /* req */ 76); 77 78static DISPATCH_PROC(ProcXTestCompareCursor); 79static DISPATCH_PROC(ProcXTestDispatch); 80static DISPATCH_PROC(ProcXTestFakeInput); 81static DISPATCH_PROC(ProcXTestGetVersion); 82static DISPATCH_PROC(ProcXTestGrabControl); 83static DISPATCH_PROC(SProcXTestCompareCursor); 84static DISPATCH_PROC(SProcXTestDispatch); 85static DISPATCH_PROC(SProcXTestFakeInput); 86static DISPATCH_PROC(SProcXTestGetVersion); 87static DISPATCH_PROC(SProcXTestGrabControl); 88 89void 90XTestExtensionInit(INITARGS) 91{ 92#if 0 93 ExtensionEntry *extEntry; 94 95 if ((extEntry = AddExtension(XTestExtensionName, 0, 0, 96 ProcXTestDispatch, SProcXTestDispatch, 97 XTestResetProc, StandardMinorOpcode)) != 0) 98 XTestReqCode = (unsigned char)extEntry->base; 99#else 100 (void) AddExtension(XTestExtensionName, 0, 0, 101 ProcXTestDispatch, SProcXTestDispatch, 102 XTestResetProc, StandardMinorOpcode); 103#endif 104} 105 106/*ARGSUSED*/ 107static void 108XTestResetProc (extEntry) 109ExtensionEntry *extEntry; 110{ 111} 112 113static int 114ProcXTestGetVersion(client) 115 register ClientPtr client; 116{ 117 xXTestGetVersionReply rep; 118 register int n; 119 120 REQUEST_SIZE_MATCH(xXTestGetVersionReq); 121 rep.type = X_Reply; 122 rep.length = 0; 123 rep.sequenceNumber = client->sequence; 124 rep.majorVersion = XTestMajorVersion; 125 rep.minorVersion = XTestMinorVersion; 126 if (client->swapped) { 127 swaps(&rep.sequenceNumber, n); 128 swaps(&rep.minorVersion, n); 129 } 130 WriteToClient(client, sizeof(xXTestGetVersionReply), (char *)&rep); 131 return(client->noClientException); 132} 133 134static int 135ProcXTestCompareCursor(client) 136 register ClientPtr client; 137{ 138 REQUEST(xXTestCompareCursorReq); 139 xXTestCompareCursorReply rep; 140 WindowPtr pWin; 141 CursorPtr pCursor; 142 register int n, rc; 143 144 REQUEST_SIZE_MATCH(xXTestCompareCursorReq); 145 rc = dixLookupWindow(&pWin, stuff->window, client, DixUnknownAccess); 146 if (rc != Success) 147 return rc; 148 if (stuff->cursor == None) 149 pCursor = NullCursor; 150 else if (stuff->cursor == XTestCurrentCursor) 151 pCursor = GetSpriteCursor(); 152 else { 153 pCursor = (CursorPtr)LookupIDByType(stuff->cursor, RT_CURSOR); 154 if (!pCursor) 155 { 156 client->errorValue = stuff->cursor; 157 return (BadCursor); 158 } 159 } 160 rep.type = X_Reply; 161 rep.length = 0; 162 rep.sequenceNumber = client->sequence; 163 rep.same = (wCursor(pWin) == pCursor); 164 if (client->swapped) { 165 swaps(&rep.sequenceNumber, n); 166 } 167 WriteToClient(client, sizeof(xXTestCompareCursorReply), (char *)&rep); 168 return(client->noClientException); 169} 170 171static int 172ProcXTestFakeInput(client) 173 register ClientPtr client; 174{ 175 REQUEST(xXTestFakeInputReq); 176 int nev, n, type, rc; 177 xEvent *ev; 178 DeviceIntPtr dev = NULL; 179 WindowPtr root; 180#ifdef XINPUT 181 Bool extension = FALSE; 182 deviceValuator *dv = NULL; 183 int base; 184 int *values; 185#endif /* XINPUT */ 186 187 nev = (stuff->length << 2) - sizeof(xReq); 188 if ((nev % sizeof(xEvent)) || !nev) 189 return BadLength; 190 nev /= sizeof(xEvent); 191 UpdateCurrentTime(); 192 ev = (xEvent *)&((xReq *)stuff)[1]; 193 type = ev->u.u.type & 0177; 194#ifdef XINPUT 195 if (type >= EXTENSION_EVENT_BASE) 196 { 197 type -= DeviceValuator; 198 switch (type) { 199 case XI_DeviceKeyPress: 200 case XI_DeviceKeyRelease: 201 case XI_DeviceButtonPress: 202 case XI_DeviceButtonRelease: 203 case XI_DeviceMotionNotify: 204 case XI_ProximityIn: 205 case XI_ProximityOut: 206 break; 207 default: 208 client->errorValue = ev->u.u.type; 209 return BadValue; 210 } 211 if (nev == 1 && type == XI_DeviceMotionNotify) 212 return BadLength; 213 if (type == XI_DeviceMotionNotify) 214 base = ((deviceValuator *)(ev+1))->first_valuator; 215 else 216 base = 0; 217 for (n = 1; n < nev; n++) 218 { 219 dv = (deviceValuator *)(ev + n); 220 if (dv->type != DeviceValuator) 221 { 222 client->errorValue = dv->type; 223 return BadValue; 224 } 225 if (dv->first_valuator != base) 226 { 227 client->errorValue = dv->first_valuator; 228 return BadValue; 229 } 230 if (!dv->num_valuators || dv->num_valuators > 6) 231 { 232 client->errorValue = dv->num_valuators; 233 return BadValue; 234 } 235 base += dv->num_valuators; 236 } 237 type = type - XI_DeviceKeyPress + KeyPress; 238 extension = TRUE; 239 } 240 else 241#endif /* XINPUT */ 242 { 243 if (nev != 1) 244 return BadLength; 245 switch (type) 246 { 247 case KeyPress: 248 case KeyRelease: 249 case MotionNotify: 250 case ButtonPress: 251 case ButtonRelease: 252 break; 253 default: 254 client->errorValue = ev->u.u.type; 255 return BadValue; 256 } 257 } 258 if (ev->u.keyButtonPointer.time) 259 { 260 TimeStamp activateTime; 261 CARD32 ms; 262 263 activateTime = currentTime; 264 ms = activateTime.milliseconds + ev->u.keyButtonPointer.time; 265 if (ms < activateTime.milliseconds) 266 activateTime.months++; 267 activateTime.milliseconds = ms; 268 ev->u.keyButtonPointer.time = 0; 269 270 /* see mbuf.c:QueueDisplayRequest for code similar to this */ 271 272 if (!ClientSleepUntil(client, &activateTime, NULL, NULL)) 273 { 274 return BadAlloc; 275 } 276 /* swap the request back so we can simply re-execute it */ 277 if (client->swapped) 278 { 279 (void) XTestSwapFakeInput(client, (xReq *)stuff); 280 swaps(&stuff->length, n); 281 } 282 ResetCurrentRequest (client); 283 client->sequence--; 284 return Success; 285 } 286#ifdef XINPUT 287 if (extension) 288 { 289 dev = LookupDeviceIntRec(stuff->deviceid & 0177); 290 if (!dev) 291 { 292 client->errorValue = stuff->deviceid & 0177; 293 return BadValue; 294 } 295 if (nev > 1) 296 { 297 dv = (deviceValuator *)(ev + 1); 298 if (!dev->valuator || dv->first_valuator >= dev->valuator->numAxes) 299 { 300 client->errorValue = dv->first_valuator; 301 return BadValue; 302 } 303 if (dv->first_valuator + dv->num_valuators > 304 dev->valuator->numAxes) 305 { 306 client->errorValue = dv->num_valuators; 307 return BadValue; 308 } 309 } 310 } 311#endif /* XINPUT */ 312 switch (type) 313 { 314 case KeyPress: 315 case KeyRelease: 316#ifdef XINPUT 317 if (!extension) 318#endif /* XINPUT */ 319 dev = (DeviceIntPtr)LookupKeyboardDevice(); 320 if (ev->u.u.detail < dev->key->curKeySyms.minKeyCode || 321 ev->u.u.detail > dev->key->curKeySyms.maxKeyCode) 322 { 323 client->errorValue = ev->u.u.detail; 324 return BadValue; 325 } 326 break; 327 case MotionNotify: 328#ifdef XINPUT 329 if (extension) 330 { 331 if (ev->u.u.detail != xFalse && ev->u.u.detail != xTrue) 332 { 333 client->errorValue = ev->u.u.detail; 334 return BadValue; 335 } 336 if (ev->u.u.detail == xTrue && dev->valuator->mode == Absolute) 337 { 338 values = dev->valuator->axisVal + dv->first_valuator; 339 for (n = 1; n < nev; n++) 340 { 341 dv = (deviceValuator *)(ev + n); 342 switch (dv->num_valuators) 343 { 344 case 6: 345 dv->valuator5 += values[5]; 346 case 5: 347 dv->valuator4 += values[4]; 348 case 4: 349 dv->valuator3 += values[3]; 350 case 3: 351 dv->valuator2 += values[2]; 352 case 2: 353 dv->valuator1 += values[1]; 354 case 1: 355 dv->valuator0 += values[0]; 356 } 357 values += 6; 358 } 359 } 360 break; 361 } 362#endif /* XINPUT */ 363 dev = (DeviceIntPtr)LookupPointerDevice(); 364 if (ev->u.keyButtonPointer.root == None) 365 root = GetCurrentRootWindow(); 366 else 367 { 368 rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root, client, 369 DixUnknownAccess); 370 if (rc != Success) 371 return rc; 372 if (root->parent) 373 { 374 client->errorValue = ev->u.keyButtonPointer.root; 375 return BadValue; 376 } 377 } 378 if (ev->u.u.detail == xTrue) 379 { 380 int x, y; 381 GetSpritePosition(&x, &y); 382 ev->u.keyButtonPointer.rootX += x; 383 ev->u.keyButtonPointer.rootY += y; 384 } 385 else if (ev->u.u.detail != xFalse) 386 { 387 client->errorValue = ev->u.u.detail; 388 return BadValue; 389 } 390 391#ifdef PANORAMIX 392 if (!noPanoramiXExtension) { 393 ScreenPtr pScreen = root->drawable.pScreen; 394 BoxRec box; 395 int i; 396 int x = ev->u.keyButtonPointer.rootX + panoramiXdataPtr[0].x; 397 int y = ev->u.keyButtonPointer.rootY + panoramiXdataPtr[0].y; 398 if (!POINT_IN_REGION(pScreen, &XineramaScreenRegions[pScreen->myNum], 399 x, y, &box)) { 400 FOR_NSCREENS(i) { 401 if (i == pScreen->myNum) continue; 402 if (POINT_IN_REGION(pScreen, 403 &XineramaScreenRegions[i], 404 x, y, &box)) { 405 root = WindowTable[i]; 406 x -= panoramiXdataPtr[i].x; 407 y -= panoramiXdataPtr[i].y; 408 ev->u.keyButtonPointer.rootX = x; 409 ev->u.keyButtonPointer.rootY = y; 410 break; 411 } 412 } 413 } 414 } 415#endif 416 417 if (ev->u.keyButtonPointer.rootX < 0) 418 ev->u.keyButtonPointer.rootX = 0; 419 else if (ev->u.keyButtonPointer.rootX >= root->drawable.width) 420 ev->u.keyButtonPointer.rootX = root->drawable.width - 1; 421 if (ev->u.keyButtonPointer.rootY < 0) 422 ev->u.keyButtonPointer.rootY = 0; 423 else if (ev->u.keyButtonPointer.rootY >= root->drawable.height) 424 ev->u.keyButtonPointer.rootY = root->drawable.height - 1; 425 426#ifdef PANORAMIX 427 if ((!noPanoramiXExtension 428 && root->drawable.pScreen->myNum != XineramaGetCursorScreen()) 429 || (noPanoramiXExtension && root != GetCurrentRootWindow())) 430 431#else 432 if (root != GetCurrentRootWindow()) 433#endif 434 { 435 NewCurrentScreen(root->drawable.pScreen, 436 ev->u.keyButtonPointer.rootX, 437 ev->u.keyButtonPointer.rootY); 438 return client->noClientException; 439 } 440 (*root->drawable.pScreen->SetCursorPosition) 441 (root->drawable.pScreen, 442 ev->u.keyButtonPointer.rootX, 443 ev->u.keyButtonPointer.rootY, FALSE); 444 dev->valuator->lastx = ev->u.keyButtonPointer.rootX; 445 dev->valuator->lasty = ev->u.keyButtonPointer.rootY; 446 break; 447 case ButtonPress: 448 case ButtonRelease: 449#ifdef XINPUT 450 if (!extension) 451#endif /* XINPUT */ 452 dev = (DeviceIntPtr)LookupPointerDevice(); 453 if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons) 454 { 455 client->errorValue = ev->u.u.detail; 456 return BadValue; 457 } 458 break; 459 } 460 if (screenIsSaved == SCREEN_SAVER_ON) 461 SaveScreens(SCREEN_SAVER_OFF, ScreenSaverReset); 462 ev->u.keyButtonPointer.time = currentTime.milliseconds; 463 (*dev->public.processInputProc)(ev, dev, nev); 464 return client->noClientException; 465} 466 467static int 468ProcXTestGrabControl(client) 469 register ClientPtr client; 470{ 471 REQUEST(xXTestGrabControlReq); 472 473 REQUEST_SIZE_MATCH(xXTestGrabControlReq); 474 if ((stuff->impervious != xTrue) && (stuff->impervious != xFalse)) 475 { 476 client->errorValue = stuff->impervious; 477 return(BadValue); 478 } 479 if (stuff->impervious) 480 MakeClientGrabImpervious(client); 481 else 482 MakeClientGrabPervious(client); 483 return(client->noClientException); 484} 485 486static int 487ProcXTestDispatch (client) 488 register ClientPtr client; 489{ 490 REQUEST(xReq); 491 switch (stuff->data) 492 { 493 case X_XTestGetVersion: 494 return ProcXTestGetVersion(client); 495 case X_XTestCompareCursor: 496 return ProcXTestCompareCursor(client); 497 case X_XTestFakeInput: 498 return ProcXTestFakeInput(client); 499 case X_XTestGrabControl: 500 return ProcXTestGrabControl(client); 501 default: 502 return BadRequest; 503 } 504} 505 506static int 507SProcXTestGetVersion(client) 508 register ClientPtr client; 509{ 510 register int n; 511 REQUEST(xXTestGetVersionReq); 512 513 swaps(&stuff->length, n); 514 REQUEST_SIZE_MATCH(xXTestGetVersionReq); 515 swaps(&stuff->minorVersion, n); 516 return ProcXTestGetVersion(client); 517} 518 519static int 520SProcXTestCompareCursor(client) 521 register ClientPtr client; 522{ 523 register int n; 524 REQUEST(xXTestCompareCursorReq); 525 526 swaps(&stuff->length, n); 527 REQUEST_SIZE_MATCH(xXTestCompareCursorReq); 528 swapl(&stuff->window, n); 529 swapl(&stuff->cursor, n); 530 return ProcXTestCompareCursor(client); 531} 532 533static int 534XTestSwapFakeInput(client, req) 535 register ClientPtr client; 536 xReq *req; 537{ 538 register int nev; 539 register xEvent *ev; 540 xEvent sev; 541 EventSwapPtr proc; 542 543 nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent); 544 for (ev = (xEvent *)&req[1]; --nev >= 0; ev++) 545 { 546 /* Swap event */ 547 proc = EventSwapVector[ev->u.u.type & 0177]; 548 /* no swapping proc; invalid event type? */ 549 if (!proc || proc == NotImplemented) { 550 client->errorValue = ev->u.u.type; 551 return BadValue; 552 } 553 (*proc)(ev, &sev); 554 *ev = sev; 555 } 556 return Success; 557} 558 559static int 560SProcXTestFakeInput(client) 561 register ClientPtr client; 562{ 563 register int n; 564 REQUEST(xReq); 565 566 swaps(&stuff->length, n); 567 n = XTestSwapFakeInput(client, stuff); 568 if (n != Success) 569 return n; 570 return ProcXTestFakeInput(client); 571} 572 573static int 574SProcXTestGrabControl(client) 575 register ClientPtr client; 576{ 577 register int n; 578 REQUEST(xXTestGrabControlReq); 579 580 swaps(&stuff->length, n); 581 REQUEST_SIZE_MATCH(xXTestGrabControlReq); 582 return ProcXTestGrabControl(client); 583} 584 585static int 586SProcXTestDispatch (client) 587 register ClientPtr client; 588{ 589 REQUEST(xReq); 590 switch (stuff->data) 591 { 592 case X_XTestGetVersion: 593 return SProcXTestGetVersion(client); 594 case X_XTestCompareCursor: 595 return SProcXTestCompareCursor(client); 596 case X_XTestFakeInput: 597 return SProcXTestFakeInput(client); 598 case X_XTestGrabControl: 599 return SProcXTestGrabControl(client); 600 default: 601 return BadRequest; 602 } 603} 604