105b261ecSmrg/* 205b261ecSmrg 34642e01fSmrg Copyright 1992, 1998 The Open Group 405b261ecSmrg 54642e01fSmrg Permission to use, copy, modify, distribute, and sell this software and its 64642e01fSmrg documentation for any purpose is hereby granted without fee, provided that 74642e01fSmrg the above copyright notice appear in all copies and that both that 84642e01fSmrg copyright notice and this permission notice appear in supporting 94642e01fSmrg documentation. 1005b261ecSmrg 114642e01fSmrg The above copyright notice and this permission notice shall be included 124642e01fSmrg in all copies or substantial portions of the Software. 1305b261ecSmrg 144642e01fSmrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 154642e01fSmrg OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 164642e01fSmrg MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 174642e01fSmrg IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 184642e01fSmrg OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 194642e01fSmrg ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 204642e01fSmrg OTHER DEALINGS IN THE SOFTWARE. 2105b261ecSmrg 224642e01fSmrg Except as contained in this notice, the name of The Open Group shall 234642e01fSmrg not be used in advertising or otherwise to promote the sale, use or 244642e01fSmrg other dealings in this Software without prior written authorization 254642e01fSmrg from The Open Group. 2605b261ecSmrg 274642e01fSmrg */ 2805b261ecSmrg 2905b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 3005b261ecSmrg#include <dix-config.h> 3105b261ecSmrg#endif 3205b261ecSmrg 3305b261ecSmrg#include <X11/X.h> 3405b261ecSmrg#include <X11/Xproto.h> 354202a189Smrg#include <X11/Xatom.h> 3605b261ecSmrg#include "misc.h" 3705b261ecSmrg#include "os.h" 3805b261ecSmrg#include "dixstruct.h" 3905b261ecSmrg#include "extnsionst.h" 4005b261ecSmrg#include "windowstr.h" 4105b261ecSmrg#include "inputstr.h" 4205b261ecSmrg#include "scrnintstr.h" 4305b261ecSmrg#include "dixevents.h" 4405b261ecSmrg#include "sleepuntil.h" 454642e01fSmrg#include "mi.h" 464202a189Smrg#include "xkbsrv.h" 474202a189Smrg#include "xkbstr.h" 48684baedfSmrg#include <X11/extensions/xtestproto.h> 4905b261ecSmrg#include <X11/extensions/XI.h> 5005b261ecSmrg#include <X11/extensions/XIproto.h> 514202a189Smrg#include "exglobals.h" 524202a189Smrg#include "mipointer.h" 534202a189Smrg#include "xserver-properties.h" 544202a189Smrg#include "exevents.h" 55f7df2e56Smrg#include "eventstr.h" 5665b04b38Smrg#include "inpututils.h" 5705b261ecSmrg 58f7df2e56Smrg#include "extinit.h" 594202a189Smrg 605a112b11Smrg/* XTest events are sent during request processing and may be interrupted by 614202a189Smrg * a SIGIO. We need a separate event list to avoid events overwriting each 625a112b11Smrg * other's memory. 635a112b11Smrg */ 64f7df2e56Smrgstatic InternalEvent *xtest_evlist; 654202a189Smrg 664202a189Smrg/** 674202a189Smrg * xtestpointer 684202a189Smrg * is the virtual pointer for XTest. It is the first slave 694202a189Smrg * device of the VCP. 704202a189Smrg * xtestkeyboard 714202a189Smrg * is the virtual keyboard for XTest. It is the first slave 724202a189Smrg * device of the VCK 734202a189Smrg * 744202a189Smrg * Neither of these devices can be deleted. 754202a189Smrg */ 764202a189SmrgDeviceIntPtr xtestpointer, xtestkeyboard; 7705b261ecSmrg 7805b261ecSmrg#ifdef PANORAMIX 7905b261ecSmrg#include "panoramiX.h" 8005b261ecSmrg#include "panoramiXsrv.h" 8105b261ecSmrg#endif 8205b261ecSmrg 83f7df2e56Smrgstatic int XTestSwapFakeInput(ClientPtr /* client */ , 84f7df2e56Smrg xReq * /* req */ 85f7df2e56Smrg ); 8605b261ecSmrg 8705b261ecSmrgstatic int 884202a189SmrgProcXTestGetVersion(ClientPtr client) 8905b261ecSmrg{ 90f7df2e56Smrg xXTestGetVersionReply rep = { 91f7df2e56Smrg .type = X_Reply, 92f7df2e56Smrg .sequenceNumber = client->sequence, 93f7df2e56Smrg .length = 0, 94f7df2e56Smrg .majorVersion = XTestMajorVersion, 95f7df2e56Smrg .minorVersion = XTestMinorVersion 96f7df2e56Smrg }; 9705b261ecSmrg 9805b261ecSmrg REQUEST_SIZE_MATCH(xXTestGetVersionReq); 99f7df2e56Smrg 10005b261ecSmrg if (client->swapped) { 101f7df2e56Smrg swaps(&rep.sequenceNumber); 102f7df2e56Smrg swaps(&rep.minorVersion); 10305b261ecSmrg } 104f7df2e56Smrg WriteToClient(client, sizeof(xXTestGetVersionReply), &rep); 1054202a189Smrg return Success; 10605b261ecSmrg} 10705b261ecSmrg 10805b261ecSmrgstatic int 1094202a189SmrgProcXTestCompareCursor(ClientPtr client) 11005b261ecSmrg{ 11105b261ecSmrg REQUEST(xXTestCompareCursorReq); 11205b261ecSmrg xXTestCompareCursorReply rep; 11305b261ecSmrg WindowPtr pWin; 11405b261ecSmrg CursorPtr pCursor; 115f7df2e56Smrg int rc; 1164642e01fSmrg DeviceIntPtr ptr = PickPointer(client); 11705b261ecSmrg 11805b261ecSmrg REQUEST_SIZE_MATCH(xXTestCompareCursorReq); 1194642e01fSmrg rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 12005b261ecSmrg if (rc != Success) 12105b261ecSmrg return rc; 122f7df2e56Smrg 123f7df2e56Smrg if (!ptr) 124f7df2e56Smrg return BadAccess; 125f7df2e56Smrg 12605b261ecSmrg if (stuff->cursor == None) 1274642e01fSmrg pCursor = NullCursor; 12805b261ecSmrg else if (stuff->cursor == XTestCurrentCursor) 1294642e01fSmrg pCursor = GetSpriteCursor(ptr); 13005b261ecSmrg else { 131f7df2e56Smrg rc = dixLookupResourceByType((void **) &pCursor, stuff->cursor, 132f7df2e56Smrg RT_CURSOR, client, DixReadAccess); 133f7df2e56Smrg if (rc != Success) { 1344642e01fSmrg client->errorValue = stuff->cursor; 1354202a189Smrg return rc; 1364642e01fSmrg } 13705b261ecSmrg } 138f7df2e56Smrg rep = (xXTestCompareCursorReply) { 139f7df2e56Smrg .type = X_Reply, 140f7df2e56Smrg .sequenceNumber = client->sequence, 141f7df2e56Smrg .length = 0, 142f7df2e56Smrg .same = (wCursor(pWin) == pCursor) 143f7df2e56Smrg }; 14405b261ecSmrg if (client->swapped) { 145f7df2e56Smrg swaps(&rep.sequenceNumber); 14605b261ecSmrg } 147f7df2e56Smrg WriteToClient(client, sizeof(xXTestCompareCursorReply), &rep); 1484202a189Smrg return Success; 14905b261ecSmrg} 15005b261ecSmrg 15105b261ecSmrgstatic int 1524202a189SmrgProcXTestFakeInput(ClientPtr client) 15305b261ecSmrg{ 15405b261ecSmrg REQUEST(xXTestFakeInputReq); 15505b261ecSmrg int nev, n, type, rc; 15605b261ecSmrg xEvent *ev; 15705b261ecSmrg DeviceIntPtr dev = NULL; 15805b261ecSmrg WindowPtr root; 15905b261ecSmrg Bool extension = FALSE; 16065b04b38Smrg ValuatorMask mask; 161f7df2e56Smrg int valuators[MAX_VALUATORS] = { 0 }; 1624642e01fSmrg int numValuators = 0; 1634642e01fSmrg int firstValuator = 0; 164b86d567bSmrg int nevents = 0; 1654642e01fSmrg int i; 1664642e01fSmrg int base = 0; 1674642e01fSmrg int flags = 0; 1684202a189Smrg int need_ptr_update = 1; 16905b261ecSmrg 17005b261ecSmrg nev = (stuff->length << 2) - sizeof(xReq); 17105b261ecSmrg if ((nev % sizeof(xEvent)) || !nev) 1724642e01fSmrg return BadLength; 17305b261ecSmrg nev /= sizeof(xEvent); 17405b261ecSmrg UpdateCurrentTime(); 175f7df2e56Smrg ev = (xEvent *) &((xReq *) stuff)[1]; 17605b261ecSmrg type = ev->u.u.type & 0177; 1774642e01fSmrg 178f7df2e56Smrg if (type >= EXTENSION_EVENT_BASE) { 1794642e01fSmrg extension = TRUE; 1804642e01fSmrg 1814642e01fSmrg /* check device */ 1824642e01fSmrg rc = dixLookupDevice(&dev, stuff->deviceid & 0177, client, 183f7df2e56Smrg DixWriteAccess); 184f7df2e56Smrg if (rc != Success) { 1854642e01fSmrg client->errorValue = stuff->deviceid & 0177; 1864642e01fSmrg return rc; 1874642e01fSmrg } 1884642e01fSmrg 1894642e01fSmrg /* check type */ 1904642e01fSmrg type -= DeviceValuator; 1914642e01fSmrg switch (type) { 192f7df2e56Smrg case XI_DeviceKeyPress: 193f7df2e56Smrg case XI_DeviceKeyRelease: 194f7df2e56Smrg if (!dev->key) { 1954642e01fSmrg client->errorValue = ev->u.u.type; 1964642e01fSmrg return BadValue; 197f7df2e56Smrg } 198f7df2e56Smrg break; 199f7df2e56Smrg case XI_DeviceButtonPress: 200f7df2e56Smrg case XI_DeviceButtonRelease: 201f7df2e56Smrg if (!dev->button) { 202f7df2e56Smrg client->errorValue = ev->u.u.type; 203f7df2e56Smrg return BadValue; 204f7df2e56Smrg } 205f7df2e56Smrg break; 206f7df2e56Smrg case XI_DeviceMotionNotify: 207f7df2e56Smrg if (!dev->valuator) { 208f7df2e56Smrg client->errorValue = ev->u.u.type; 209f7df2e56Smrg return BadValue; 210f7df2e56Smrg } 211f7df2e56Smrg break; 212f7df2e56Smrg case XI_ProximityIn: 213f7df2e56Smrg case XI_ProximityOut: 214f7df2e56Smrg if (!dev->proximity) { 215f7df2e56Smrg client->errorValue = ev->u.u.type; 216f7df2e56Smrg return BadValue; 217f7df2e56Smrg } 218f7df2e56Smrg break; 219f7df2e56Smrg default: 220f7df2e56Smrg client->errorValue = ev->u.u.type; 221f7df2e56Smrg return BadValue; 2224642e01fSmrg } 2234642e01fSmrg 2244642e01fSmrg /* check validity */ 2254642e01fSmrg if (nev == 1 && type == XI_DeviceMotionNotify) 226f7df2e56Smrg return BadLength; /* DevMotion must be followed by DevValuator */ 2274642e01fSmrg 228f7df2e56Smrg if (type == XI_DeviceMotionNotify) { 229f7df2e56Smrg firstValuator = ((deviceValuator *) (ev + 1))->first_valuator; 230f7df2e56Smrg if (firstValuator > dev->valuator->numAxes) { 2314642e01fSmrg client->errorValue = ev->u.u.type; 2324642e01fSmrg return BadValue; 2334642e01fSmrg } 2344642e01fSmrg 2354642e01fSmrg if (ev->u.u.detail == xFalse) 2364642e01fSmrg flags |= POINTER_ABSOLUTE; 237f7df2e56Smrg } 238f7df2e56Smrg else { 2394642e01fSmrg firstValuator = 0; 2404642e01fSmrg flags |= POINTER_ABSOLUTE; 2414642e01fSmrg } 2424642e01fSmrg 243f7df2e56Smrg if (nev > 1 && !dev->valuator) { 244f7df2e56Smrg client->errorValue = firstValuator; 2454642e01fSmrg return BadValue; 2464642e01fSmrg } 2474642e01fSmrg 2484642e01fSmrg /* check validity of valuator events */ 2494642e01fSmrg base = firstValuator; 250f7df2e56Smrg for (n = 1; n < nev; n++) { 251f7df2e56Smrg deviceValuator *dv = (deviceValuator *) (ev + n); 252f7df2e56Smrg if (dv->type != DeviceValuator) { 2534642e01fSmrg client->errorValue = dv->type; 2544642e01fSmrg return BadValue; 2554642e01fSmrg } 256f7df2e56Smrg if (dv->first_valuator != base) { 2574642e01fSmrg client->errorValue = dv->first_valuator; 2584642e01fSmrg return BadValue; 2594642e01fSmrg } 260f7df2e56Smrg switch (dv->num_valuators) { 261f7df2e56Smrg case 6: 262f7df2e56Smrg valuators[base + 5] = dv->valuator5; 263f7df2e56Smrg case 5: 264f7df2e56Smrg valuators[base + 4] = dv->valuator4; 265f7df2e56Smrg case 4: 266f7df2e56Smrg valuators[base + 3] = dv->valuator3; 267f7df2e56Smrg case 3: 268f7df2e56Smrg valuators[base + 2] = dv->valuator2; 269f7df2e56Smrg case 2: 270f7df2e56Smrg valuators[base + 1] = dv->valuator1; 271f7df2e56Smrg case 1: 272f7df2e56Smrg valuators[base] = dv->valuator0; 273f7df2e56Smrg break; 274f7df2e56Smrg default: 275f7df2e56Smrg client->errorValue = dv->num_valuators; 276f7df2e56Smrg return BadValue; 2774642e01fSmrg } 2784642e01fSmrg 2794642e01fSmrg base += dv->num_valuators; 2804642e01fSmrg numValuators += dv->num_valuators; 2814642e01fSmrg 282f7df2e56Smrg if (firstValuator + numValuators > dev->valuator->numAxes) { 2834642e01fSmrg client->errorValue = dv->num_valuators; 2844642e01fSmrg return BadValue; 2854642e01fSmrg } 2864642e01fSmrg } 2874642e01fSmrg type = type - XI_DeviceKeyPress + KeyPress; 2884642e01fSmrg 289f7df2e56Smrg } 290f7df2e56Smrg else { 2914642e01fSmrg if (nev != 1) 2924642e01fSmrg return BadLength; 293f7df2e56Smrg switch (type) { 294f7df2e56Smrg case KeyPress: 295f7df2e56Smrg case KeyRelease: 296f7df2e56Smrg dev = PickKeyboard(client); 297f7df2e56Smrg break; 298f7df2e56Smrg case ButtonPress: 299f7df2e56Smrg case ButtonRelease: 300f7df2e56Smrg dev = PickPointer(client); 301f7df2e56Smrg break; 302f7df2e56Smrg case MotionNotify: 303f7df2e56Smrg dev = PickPointer(client); 304f7df2e56Smrg valuators[0] = ev->u.keyButtonPointer.rootX; 305f7df2e56Smrg valuators[1] = ev->u.keyButtonPointer.rootY; 306f7df2e56Smrg numValuators = 2; 307f7df2e56Smrg firstValuator = 0; 308f7df2e56Smrg if (ev->u.u.detail == xFalse) 309f7df2e56Smrg flags = POINTER_ABSOLUTE | POINTER_DESKTOP; 310f7df2e56Smrg break; 311f7df2e56Smrg default: 312f7df2e56Smrg client->errorValue = ev->u.u.type; 313f7df2e56Smrg return BadValue; 3144642e01fSmrg } 3154642e01fSmrg 316f7df2e56Smrg /* Technically the protocol doesn't allow for BadAccess here but 317f7df2e56Smrg * this can only happen when all MDs are disabled. */ 318f7df2e56Smrg if (!dev) 319f7df2e56Smrg return BadAccess; 320f7df2e56Smrg 3214202a189Smrg dev = GetXTestDevice(dev); 32205b261ecSmrg } 3234642e01fSmrg 324f7df2e56Smrg 3254642e01fSmrg /* If the event has a time set, wait for it to pass */ 326f7df2e56Smrg if (ev->u.keyButtonPointer.time) { 3274642e01fSmrg TimeStamp activateTime; 3284642e01fSmrg CARD32 ms; 3294642e01fSmrg 3304642e01fSmrg activateTime = currentTime; 3314642e01fSmrg ms = activateTime.milliseconds + ev->u.keyButtonPointer.time; 3324642e01fSmrg if (ms < activateTime.milliseconds) 3334642e01fSmrg activateTime.months++; 3344642e01fSmrg activateTime.milliseconds = ms; 3354642e01fSmrg ev->u.keyButtonPointer.time = 0; 3364642e01fSmrg 3374202a189Smrg /* see mbuf.c:QueueDisplayRequest (from the deprecated Multibuffer 3384202a189Smrg * extension) for code similar to this */ 3394642e01fSmrg 340f7df2e56Smrg if (!ClientSleepUntil(client, &activateTime, NULL, NULL)) { 3414642e01fSmrg return BadAlloc; 3424642e01fSmrg } 3434642e01fSmrg /* swap the request back so we can simply re-execute it */ 344f7df2e56Smrg if (client->swapped) { 345f7df2e56Smrg (void) XTestSwapFakeInput(client, (xReq *) stuff); 346f7df2e56Smrg swaps(&stuff->length); 3474642e01fSmrg } 348f7df2e56Smrg ResetCurrentRequest(client); 3494642e01fSmrg client->sequence--; 3504642e01fSmrg return Success; 35105b261ecSmrg } 3524642e01fSmrg 353f7df2e56Smrg switch (type) { 354f7df2e56Smrg case KeyPress: 355f7df2e56Smrg case KeyRelease: 356f7df2e56Smrg if (!dev->key) 357f7df2e56Smrg return BadDevice; 3584202a189Smrg 359f7df2e56Smrg if (ev->u.u.detail < dev->key->xkbInfo->desc->min_key_code || 360f7df2e56Smrg ev->u.u.detail > dev->key->xkbInfo->desc->max_key_code) { 361f7df2e56Smrg client->errorValue = ev->u.u.detail; 362f7df2e56Smrg return BadValue; 363f7df2e56Smrg } 364f7df2e56Smrg 365f7df2e56Smrg need_ptr_update = 0; 366f7df2e56Smrg break; 367f7df2e56Smrg case MotionNotify: 368f7df2e56Smrg if (!dev->valuator) 369f7df2e56Smrg return BadDevice; 370f7df2e56Smrg 371f7df2e56Smrg if (!(extension || ev->u.keyButtonPointer.root == None)) { 372f7df2e56Smrg rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root, 373f7df2e56Smrg client, DixGetAttrAccess); 374f7df2e56Smrg if (rc != Success) 375f7df2e56Smrg return rc; 376f7df2e56Smrg if (root->parent) { 377f7df2e56Smrg client->errorValue = ev->u.keyButtonPointer.root; 3784642e01fSmrg return BadValue; 3794642e01fSmrg } 3804202a189Smrg 381f7df2e56Smrg /* Add the root window's offset to the valuators */ 382f7df2e56Smrg if ((flags & POINTER_ABSOLUTE) && firstValuator <= 1 && numValuators > 0) { 383f7df2e56Smrg if (firstValuator == 0) 384f7df2e56Smrg valuators[0] += root->drawable.pScreen->x; 385f7df2e56Smrg if (firstValuator < 2 && firstValuator + numValuators > 1) 386f7df2e56Smrg valuators[1 - firstValuator] += root->drawable.pScreen->y; 3874642e01fSmrg } 388f7df2e56Smrg } 389f7df2e56Smrg if (ev->u.u.detail != xTrue && ev->u.u.detail != xFalse) { 390f7df2e56Smrg client->errorValue = ev->u.u.detail; 391f7df2e56Smrg return BadValue; 392f7df2e56Smrg } 3934642e01fSmrg 394f7df2e56Smrg /* FIXME: Xinerama! */ 3954642e01fSmrg 396f7df2e56Smrg break; 397f7df2e56Smrg case ButtonPress: 398f7df2e56Smrg case ButtonRelease: 399f7df2e56Smrg if (!dev->button) 400f7df2e56Smrg return BadDevice; 4014202a189Smrg 402f7df2e56Smrg if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons) { 403f7df2e56Smrg client->errorValue = ev->u.u.detail; 404f7df2e56Smrg return BadValue; 405f7df2e56Smrg } 406f7df2e56Smrg break; 40705b261ecSmrg } 40805b261ecSmrg if (screenIsSaved == SCREEN_SAVER_ON) 4094642e01fSmrg dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); 4104642e01fSmrg 411f7df2e56Smrg switch (type) { 412f7df2e56Smrg case MotionNotify: 413f7df2e56Smrg valuator_mask_set_range(&mask, firstValuator, numValuators, valuators); 414f7df2e56Smrg nevents = GetPointerEvents(xtest_evlist, dev, type, 0, flags, &mask); 415f7df2e56Smrg break; 416f7df2e56Smrg case ButtonPress: 417f7df2e56Smrg case ButtonRelease: 418f7df2e56Smrg valuator_mask_set_range(&mask, firstValuator, numValuators, valuators); 419f7df2e56Smrg nevents = GetPointerEvents(xtest_evlist, dev, type, ev->u.u.detail, 420f7df2e56Smrg flags, &mask); 421f7df2e56Smrg break; 422f7df2e56Smrg case KeyPress: 423f7df2e56Smrg case KeyRelease: 424f7df2e56Smrg nevents = 425f7df2e56Smrg GetKeyboardEvents(xtest_evlist, dev, type, ev->u.u.detail); 426f7df2e56Smrg break; 4274642e01fSmrg } 4284642e01fSmrg 4294642e01fSmrg for (i = 0; i < nevents; i++) 430f7df2e56Smrg mieqProcessDeviceEvent(dev, &xtest_evlist[i], miPointerGetScreen(inputInfo.pointer)); 4314642e01fSmrg 4324202a189Smrg if (need_ptr_update) 4334202a189Smrg miPointerUpdateSprite(dev); 4344202a189Smrg return Success; 43505b261ecSmrg} 43605b261ecSmrg 43705b261ecSmrgstatic int 4384202a189SmrgProcXTestGrabControl(ClientPtr client) 43905b261ecSmrg{ 44005b261ecSmrg REQUEST(xXTestGrabControlReq); 44105b261ecSmrg 44205b261ecSmrg REQUEST_SIZE_MATCH(xXTestGrabControlReq); 443f7df2e56Smrg if ((stuff->impervious != xTrue) && (stuff->impervious != xFalse)) { 4444642e01fSmrg client->errorValue = stuff->impervious; 4454202a189Smrg return BadValue; 44605b261ecSmrg } 44705b261ecSmrg if (stuff->impervious) 4484642e01fSmrg MakeClientGrabImpervious(client); 44905b261ecSmrg else 4504642e01fSmrg MakeClientGrabPervious(client); 4514202a189Smrg return Success; 45205b261ecSmrg} 45305b261ecSmrg 45405b261ecSmrgstatic int 455f7df2e56SmrgProcXTestDispatch(ClientPtr client) 45605b261ecSmrg{ 45705b261ecSmrg REQUEST(xReq); 458f7df2e56Smrg switch (stuff->data) { 459f7df2e56Smrg case X_XTestGetVersion: 460f7df2e56Smrg return ProcXTestGetVersion(client); 461f7df2e56Smrg case X_XTestCompareCursor: 462f7df2e56Smrg return ProcXTestCompareCursor(client); 463f7df2e56Smrg case X_XTestFakeInput: 464f7df2e56Smrg return ProcXTestFakeInput(client); 465f7df2e56Smrg case X_XTestGrabControl: 466f7df2e56Smrg return ProcXTestGrabControl(client); 467f7df2e56Smrg default: 468f7df2e56Smrg return BadRequest; 46905b261ecSmrg } 47005b261ecSmrg} 47105b261ecSmrg 4727e31ba66Smrgstatic int _X_COLD 4734202a189SmrgSProcXTestGetVersion(ClientPtr client) 47405b261ecSmrg{ 47505b261ecSmrg REQUEST(xXTestGetVersionReq); 47605b261ecSmrg 477f7df2e56Smrg swaps(&stuff->length); 47805b261ecSmrg REQUEST_SIZE_MATCH(xXTestGetVersionReq); 479f7df2e56Smrg swaps(&stuff->minorVersion); 48005b261ecSmrg return ProcXTestGetVersion(client); 48105b261ecSmrg} 48205b261ecSmrg 4837e31ba66Smrgstatic int _X_COLD 4844202a189SmrgSProcXTestCompareCursor(ClientPtr client) 48505b261ecSmrg{ 48605b261ecSmrg REQUEST(xXTestCompareCursorReq); 48705b261ecSmrg 488f7df2e56Smrg swaps(&stuff->length); 48905b261ecSmrg REQUEST_SIZE_MATCH(xXTestCompareCursorReq); 490f7df2e56Smrg swapl(&stuff->window); 491f7df2e56Smrg swapl(&stuff->cursor); 49205b261ecSmrg return ProcXTestCompareCursor(client); 49305b261ecSmrg} 49405b261ecSmrg 4957e31ba66Smrgstatic int _X_COLD 496f7df2e56SmrgXTestSwapFakeInput(ClientPtr client, xReq * req) 49705b261ecSmrg{ 4984642e01fSmrg int nev; 4994642e01fSmrg xEvent *ev; 50005b261ecSmrg xEvent sev; 50105b261ecSmrg EventSwapPtr proc; 50205b261ecSmrg 50305b261ecSmrg nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent); 504f7df2e56Smrg for (ev = (xEvent *) &req[1]; --nev >= 0; ev++) { 5052d19872aSmrg int evtype = ev->u.u.type & 0177; 5064642e01fSmrg /* Swap event */ 507e383896cSmrg proc = EventSwapVector[evtype]; 5084642e01fSmrg /* no swapping proc; invalid event type? */ 509e383896cSmrg if (!proc || proc == NotImplemented || evtype == GenericEvent) { 5104642e01fSmrg client->errorValue = ev->u.u.type; 5114642e01fSmrg return BadValue; 5124642e01fSmrg } 513f7df2e56Smrg (*proc) (ev, &sev); 5144642e01fSmrg *ev = sev; 51505b261ecSmrg } 51605b261ecSmrg return Success; 51705b261ecSmrg} 51805b261ecSmrg 5197e31ba66Smrgstatic int _X_COLD 5204202a189SmrgSProcXTestFakeInput(ClientPtr client) 52105b261ecSmrg{ 5224642e01fSmrg int n; 523f7df2e56Smrg 52405b261ecSmrg REQUEST(xReq); 52505b261ecSmrg 526f7df2e56Smrg swaps(&stuff->length); 52705b261ecSmrg n = XTestSwapFakeInput(client, stuff); 52805b261ecSmrg if (n != Success) 5294642e01fSmrg return n; 53005b261ecSmrg return ProcXTestFakeInput(client); 53105b261ecSmrg} 53205b261ecSmrg 5337e31ba66Smrgstatic int _X_COLD 5344202a189SmrgSProcXTestGrabControl(ClientPtr client) 53505b261ecSmrg{ 53605b261ecSmrg REQUEST(xXTestGrabControlReq); 53705b261ecSmrg 538f7df2e56Smrg swaps(&stuff->length); 53905b261ecSmrg REQUEST_SIZE_MATCH(xXTestGrabControlReq); 54005b261ecSmrg return ProcXTestGrabControl(client); 54105b261ecSmrg} 54205b261ecSmrg 5437e31ba66Smrgstatic int _X_COLD 544f7df2e56SmrgSProcXTestDispatch(ClientPtr client) 54505b261ecSmrg{ 54605b261ecSmrg REQUEST(xReq); 547f7df2e56Smrg switch (stuff->data) { 548f7df2e56Smrg case X_XTestGetVersion: 549f7df2e56Smrg return SProcXTestGetVersion(client); 550f7df2e56Smrg case X_XTestCompareCursor: 551f7df2e56Smrg return SProcXTestCompareCursor(client); 552f7df2e56Smrg case X_XTestFakeInput: 553f7df2e56Smrg return SProcXTestFakeInput(client); 554f7df2e56Smrg case X_XTestGrabControl: 555f7df2e56Smrg return SProcXTestGrabControl(client); 556f7df2e56Smrg default: 557f7df2e56Smrg return BadRequest; 55805b261ecSmrg } 55905b261ecSmrg} 5604202a189Smrg 5614202a189Smrg/** 5624202a189Smrg * Allocate an virtual slave device for xtest events, this 5634202a189Smrg * is a slave device to inputInfo master devices 5644202a189Smrg */ 565f7df2e56Smrgvoid 566f7df2e56SmrgInitXTestDevices(void) 5674202a189Smrg{ 568f7df2e56Smrg if (AllocXTestDevice(serverClient, "Virtual core", 569f7df2e56Smrg &xtestpointer, &xtestkeyboard, 570f7df2e56Smrg inputInfo.pointer, inputInfo.keyboard) != Success) 571f7df2e56Smrg FatalError("Failed to allocate XTest devices"); 5724202a189Smrg 5734202a189Smrg if (ActivateDevice(xtestpointer, TRUE) != Success || 5744202a189Smrg ActivateDevice(xtestkeyboard, TRUE) != Success) 5754202a189Smrg FatalError("Failed to activate XTest core devices."); 576f7df2e56Smrg if (!EnableDevice(xtestpointer, TRUE) || !EnableDevice(xtestkeyboard, TRUE)) 5774202a189Smrg FatalError("Failed to enable XTest core devices."); 5784202a189Smrg 5794202a189Smrg AttachDevice(NULL, xtestpointer, inputInfo.pointer); 580f7df2e56Smrg 5814202a189Smrg AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard); 5824202a189Smrg} 5834202a189Smrg 5844202a189Smrg/** 5854202a189Smrg * Don't allow changing the XTest property. 5864202a189Smrg */ 5874202a189Smrgstatic int 5884202a189SmrgDeviceSetXTestProperty(DeviceIntPtr dev, Atom property, 589f7df2e56Smrg XIPropertyValuePtr prop, BOOL checkonly) 5904202a189Smrg{ 5914202a189Smrg if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE)) 5924202a189Smrg return BadAccess; 5934202a189Smrg 5944202a189Smrg return Success; 5954202a189Smrg} 5964202a189Smrg 5974202a189Smrg/** 5984202a189Smrg * Allocate a device pair that is initialised as a slave 5994202a189Smrg * device with properties that identify the devices as belonging 6004202a189Smrg * to XTest subsystem. 6014202a189Smrg * This only creates the pair, Activate/Enable Device 6024202a189Smrg * still need to be called. 6034202a189Smrg */ 604f7df2e56Smrgint 605f7df2e56SmrgAllocXTestDevice(ClientPtr client, const char *name, 606f7df2e56Smrg DeviceIntPtr *ptr, DeviceIntPtr *keybd, 607f7df2e56Smrg DeviceIntPtr master_ptr, DeviceIntPtr master_keybd) 6084202a189Smrg{ 6094202a189Smrg int retval; 610f7df2e56Smrg char *xtestname; 6114202a189Smrg char dummy = 1; 6124202a189Smrg 613f7df2e56Smrg if (asprintf(&xtestname, "%s XTEST", name) == -1) 614f7df2e56Smrg return BadAlloc; 6154202a189Smrg 616f7df2e56Smrg retval = 617f7df2e56Smrg AllocDevicePair(client, xtestname, ptr, keybd, CorePointerProc, 618f7df2e56Smrg CoreKeyboardProc, FALSE); 619f7df2e56Smrg if (retval == Success) { 620f7df2e56Smrg (*ptr)->xtest_master_id = master_ptr->id; 621f7df2e56Smrg (*keybd)->xtest_master_id = master_keybd->id; 6224202a189Smrg 6234202a189Smrg XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 624f7df2e56Smrg XA_INTEGER, 8, PropModeReplace, 1, &dummy, 625f7df2e56Smrg FALSE); 626f7df2e56Smrg XISetDevicePropertyDeletable(*ptr, 627f7df2e56Smrg XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 628f7df2e56Smrg FALSE); 6294202a189Smrg XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL); 6304202a189Smrg XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 631f7df2e56Smrg XA_INTEGER, 8, PropModeReplace, 1, &dummy, 632f7df2e56Smrg FALSE); 633f7df2e56Smrg XISetDevicePropertyDeletable(*keybd, 634f7df2e56Smrg XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 635f7df2e56Smrg FALSE); 6364202a189Smrg XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL); 6374202a189Smrg } 6384202a189Smrg 639f7df2e56Smrg free(xtestname); 6404202a189Smrg 6414202a189Smrg return retval; 6424202a189Smrg} 6434202a189Smrg 6444202a189Smrg/** 6454202a189Smrg * If master is NULL, return TRUE if the given device is an xtest device or 6464202a189Smrg * FALSE otherwise. 6474202a189Smrg * If master is not NULL, return TRUE if the given device is this master's 6484202a189Smrg * xtest device. 6494202a189Smrg */ 6504202a189SmrgBOOL 6514202a189SmrgIsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master) 6524202a189Smrg{ 6534202a189Smrg if (IsMaster(dev)) 6544202a189Smrg return FALSE; 6554202a189Smrg 6564202a189Smrg /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest 6574202a189Smrg * device */ 6584202a189Smrg if (master) 659f7df2e56Smrg return dev->xtest_master_id == master->id; 6604202a189Smrg 6614202a189Smrg return dev->xtest_master_id != 0; 6624202a189Smrg} 6634202a189Smrg 6644202a189Smrg/** 6654202a189Smrg * @return The X Test virtual device for the given master. 6664202a189Smrg */ 6674202a189SmrgDeviceIntPtr 6684202a189SmrgGetXTestDevice(DeviceIntPtr master) 6694202a189Smrg{ 6704202a189Smrg DeviceIntPtr it; 6714202a189Smrg 672f7df2e56Smrg for (it = inputInfo.devices; it; it = it->next) { 6734202a189Smrg if (IsXTestDevice(it, master)) 6744202a189Smrg return it; 6754202a189Smrg } 6764202a189Smrg 6774202a189Smrg /* This only happens if master is a slave device. don't do that */ 6784202a189Smrg return NULL; 6794202a189Smrg} 6804202a189Smrg 681f7df2e56Smrgstatic void 682f7df2e56SmrgXTestExtensionTearDown(ExtensionEntry * e) 683f7df2e56Smrg{ 684f7df2e56Smrg FreeEventList(xtest_evlist, GetMaximumEventsNum()); 685f7df2e56Smrg xtest_evlist = NULL; 686f7df2e56Smrg} 687f7df2e56Smrg 68865b04b38Smrgvoid 689f7df2e56SmrgXTestExtensionInit(void) 69065b04b38Smrg{ 69165b04b38Smrg AddExtension(XTestExtensionName, 0, 0, 692f7df2e56Smrg ProcXTestDispatch, SProcXTestDispatch, 693f7df2e56Smrg XTestExtensionTearDown, StandardMinorOpcode); 69465b04b38Smrg 69565b04b38Smrg xtest_evlist = InitEventList(GetMaximumEventsNum()); 69665b04b38Smrg} 697