xtest.c revision 7e31ba66
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 604202a189Smrg/* XTest events are sent during request processing and may be interruped by 614202a189Smrg * a SIGIO. We need a separate event list to avoid events overwriting each 624202a189Smrg * other's memory */ 63f7df2e56Smrgstatic InternalEvent *xtest_evlist; 644202a189Smrg 654202a189Smrg/** 664202a189Smrg * xtestpointer 674202a189Smrg * is the virtual pointer for XTest. It is the first slave 684202a189Smrg * device of the VCP. 694202a189Smrg * xtestkeyboard 704202a189Smrg * is the virtual keyboard for XTest. It is the first slave 714202a189Smrg * device of the VCK 724202a189Smrg * 734202a189Smrg * Neither of these devices can be deleted. 744202a189Smrg */ 754202a189SmrgDeviceIntPtr xtestpointer, xtestkeyboard; 7605b261ecSmrg 7705b261ecSmrg#ifdef PANORAMIX 7805b261ecSmrg#include "panoramiX.h" 7905b261ecSmrg#include "panoramiXsrv.h" 8005b261ecSmrg#endif 8105b261ecSmrg 82f7df2e56Smrgstatic int XTestSwapFakeInput(ClientPtr /* client */ , 83f7df2e56Smrg xReq * /* req */ 84f7df2e56Smrg ); 8505b261ecSmrg 8605b261ecSmrgstatic int 874202a189SmrgProcXTestGetVersion(ClientPtr client) 8805b261ecSmrg{ 89f7df2e56Smrg xXTestGetVersionReply rep = { 90f7df2e56Smrg .type = X_Reply, 91f7df2e56Smrg .sequenceNumber = client->sequence, 92f7df2e56Smrg .length = 0, 93f7df2e56Smrg .majorVersion = XTestMajorVersion, 94f7df2e56Smrg .minorVersion = XTestMinorVersion 95f7df2e56Smrg }; 9605b261ecSmrg 9705b261ecSmrg REQUEST_SIZE_MATCH(xXTestGetVersionReq); 98f7df2e56Smrg 9905b261ecSmrg if (client->swapped) { 100f7df2e56Smrg swaps(&rep.sequenceNumber); 101f7df2e56Smrg swaps(&rep.minorVersion); 10205b261ecSmrg } 103f7df2e56Smrg WriteToClient(client, sizeof(xXTestGetVersionReply), &rep); 1044202a189Smrg return Success; 10505b261ecSmrg} 10605b261ecSmrg 10705b261ecSmrgstatic int 1084202a189SmrgProcXTestCompareCursor(ClientPtr client) 10905b261ecSmrg{ 11005b261ecSmrg REQUEST(xXTestCompareCursorReq); 11105b261ecSmrg xXTestCompareCursorReply rep; 11205b261ecSmrg WindowPtr pWin; 11305b261ecSmrg CursorPtr pCursor; 114f7df2e56Smrg int rc; 1154642e01fSmrg DeviceIntPtr ptr = PickPointer(client); 11605b261ecSmrg 11705b261ecSmrg REQUEST_SIZE_MATCH(xXTestCompareCursorReq); 1184642e01fSmrg rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 11905b261ecSmrg if (rc != Success) 12005b261ecSmrg return rc; 121f7df2e56Smrg 122f7df2e56Smrg if (!ptr) 123f7df2e56Smrg return BadAccess; 124f7df2e56Smrg 12505b261ecSmrg if (stuff->cursor == None) 1264642e01fSmrg pCursor = NullCursor; 12705b261ecSmrg else if (stuff->cursor == XTestCurrentCursor) 1284642e01fSmrg pCursor = GetSpriteCursor(ptr); 12905b261ecSmrg else { 130f7df2e56Smrg rc = dixLookupResourceByType((void **) &pCursor, stuff->cursor, 131f7df2e56Smrg RT_CURSOR, client, DixReadAccess); 132f7df2e56Smrg if (rc != Success) { 1334642e01fSmrg client->errorValue = stuff->cursor; 1344202a189Smrg return rc; 1354642e01fSmrg } 13605b261ecSmrg } 137f7df2e56Smrg rep = (xXTestCompareCursorReply) { 138f7df2e56Smrg .type = X_Reply, 139f7df2e56Smrg .sequenceNumber = client->sequence, 140f7df2e56Smrg .length = 0, 141f7df2e56Smrg .same = (wCursor(pWin) == pCursor) 142f7df2e56Smrg }; 14305b261ecSmrg if (client->swapped) { 144f7df2e56Smrg swaps(&rep.sequenceNumber); 14505b261ecSmrg } 146f7df2e56Smrg WriteToClient(client, sizeof(xXTestCompareCursorReply), &rep); 1474202a189Smrg return Success; 14805b261ecSmrg} 14905b261ecSmrg 15005b261ecSmrgstatic int 1514202a189SmrgProcXTestFakeInput(ClientPtr client) 15205b261ecSmrg{ 15305b261ecSmrg REQUEST(xXTestFakeInputReq); 15405b261ecSmrg int nev, n, type, rc; 15505b261ecSmrg xEvent *ev; 15605b261ecSmrg DeviceIntPtr dev = NULL; 15705b261ecSmrg WindowPtr root; 15805b261ecSmrg Bool extension = FALSE; 15965b04b38Smrg ValuatorMask mask; 160f7df2e56Smrg int valuators[MAX_VALUATORS] = { 0 }; 1614642e01fSmrg int numValuators = 0; 1624642e01fSmrg int firstValuator = 0; 163b86d567bSmrg int nevents = 0; 1644642e01fSmrg int i; 1654642e01fSmrg int base = 0; 1664642e01fSmrg int flags = 0; 1674202a189Smrg int need_ptr_update = 1; 16805b261ecSmrg 16905b261ecSmrg nev = (stuff->length << 2) - sizeof(xReq); 17005b261ecSmrg if ((nev % sizeof(xEvent)) || !nev) 1714642e01fSmrg return BadLength; 17205b261ecSmrg nev /= sizeof(xEvent); 17305b261ecSmrg UpdateCurrentTime(); 174f7df2e56Smrg ev = (xEvent *) &((xReq *) stuff)[1]; 17505b261ecSmrg type = ev->u.u.type & 0177; 1764642e01fSmrg 177f7df2e56Smrg if (type >= EXTENSION_EVENT_BASE) { 1784642e01fSmrg extension = TRUE; 1794642e01fSmrg 1804642e01fSmrg /* check device */ 1814642e01fSmrg rc = dixLookupDevice(&dev, stuff->deviceid & 0177, client, 182f7df2e56Smrg DixWriteAccess); 183f7df2e56Smrg if (rc != Success) { 1844642e01fSmrg client->errorValue = stuff->deviceid & 0177; 1854642e01fSmrg return rc; 1864642e01fSmrg } 1874642e01fSmrg 1884642e01fSmrg /* check type */ 1894642e01fSmrg type -= DeviceValuator; 1904642e01fSmrg switch (type) { 191f7df2e56Smrg case XI_DeviceKeyPress: 192f7df2e56Smrg case XI_DeviceKeyRelease: 193f7df2e56Smrg if (!dev->key) { 1944642e01fSmrg client->errorValue = ev->u.u.type; 1954642e01fSmrg return BadValue; 196f7df2e56Smrg } 197f7df2e56Smrg break; 198f7df2e56Smrg case XI_DeviceButtonPress: 199f7df2e56Smrg case XI_DeviceButtonRelease: 200f7df2e56Smrg if (!dev->button) { 201f7df2e56Smrg client->errorValue = ev->u.u.type; 202f7df2e56Smrg return BadValue; 203f7df2e56Smrg } 204f7df2e56Smrg break; 205f7df2e56Smrg case XI_DeviceMotionNotify: 206f7df2e56Smrg if (!dev->valuator) { 207f7df2e56Smrg client->errorValue = ev->u.u.type; 208f7df2e56Smrg return BadValue; 209f7df2e56Smrg } 210f7df2e56Smrg break; 211f7df2e56Smrg case XI_ProximityIn: 212f7df2e56Smrg case XI_ProximityOut: 213f7df2e56Smrg if (!dev->proximity) { 214f7df2e56Smrg client->errorValue = ev->u.u.type; 215f7df2e56Smrg return BadValue; 216f7df2e56Smrg } 217f7df2e56Smrg break; 218f7df2e56Smrg default: 219f7df2e56Smrg client->errorValue = ev->u.u.type; 220f7df2e56Smrg return BadValue; 2214642e01fSmrg } 2224642e01fSmrg 2234642e01fSmrg /* check validity */ 2244642e01fSmrg if (nev == 1 && type == XI_DeviceMotionNotify) 225f7df2e56Smrg return BadLength; /* DevMotion must be followed by DevValuator */ 2264642e01fSmrg 227f7df2e56Smrg if (type == XI_DeviceMotionNotify) { 228f7df2e56Smrg firstValuator = ((deviceValuator *) (ev + 1))->first_valuator; 229f7df2e56Smrg if (firstValuator > dev->valuator->numAxes) { 2304642e01fSmrg client->errorValue = ev->u.u.type; 2314642e01fSmrg return BadValue; 2324642e01fSmrg } 2334642e01fSmrg 2344642e01fSmrg if (ev->u.u.detail == xFalse) 2354642e01fSmrg flags |= POINTER_ABSOLUTE; 236f7df2e56Smrg } 237f7df2e56Smrg else { 2384642e01fSmrg firstValuator = 0; 2394642e01fSmrg flags |= POINTER_ABSOLUTE; 2404642e01fSmrg } 2414642e01fSmrg 242f7df2e56Smrg if (nev > 1 && !dev->valuator) { 243f7df2e56Smrg client->errorValue = firstValuator; 2444642e01fSmrg return BadValue; 2454642e01fSmrg } 2464642e01fSmrg 2474642e01fSmrg /* check validity of valuator events */ 2484642e01fSmrg base = firstValuator; 249f7df2e56Smrg for (n = 1; n < nev; n++) { 250f7df2e56Smrg deviceValuator *dv = (deviceValuator *) (ev + n); 251f7df2e56Smrg if (dv->type != DeviceValuator) { 2524642e01fSmrg client->errorValue = dv->type; 2534642e01fSmrg return BadValue; 2544642e01fSmrg } 255f7df2e56Smrg if (dv->first_valuator != base) { 2564642e01fSmrg client->errorValue = dv->first_valuator; 2574642e01fSmrg return BadValue; 2584642e01fSmrg } 259f7df2e56Smrg switch (dv->num_valuators) { 260f7df2e56Smrg case 6: 261f7df2e56Smrg valuators[base + 5] = dv->valuator5; 262f7df2e56Smrg case 5: 263f7df2e56Smrg valuators[base + 4] = dv->valuator4; 264f7df2e56Smrg case 4: 265f7df2e56Smrg valuators[base + 3] = dv->valuator3; 266f7df2e56Smrg case 3: 267f7df2e56Smrg valuators[base + 2] = dv->valuator2; 268f7df2e56Smrg case 2: 269f7df2e56Smrg valuators[base + 1] = dv->valuator1; 270f7df2e56Smrg case 1: 271f7df2e56Smrg valuators[base] = dv->valuator0; 272f7df2e56Smrg break; 273f7df2e56Smrg default: 274f7df2e56Smrg client->errorValue = dv->num_valuators; 275f7df2e56Smrg return BadValue; 2764642e01fSmrg } 2774642e01fSmrg 2784642e01fSmrg base += dv->num_valuators; 2794642e01fSmrg numValuators += dv->num_valuators; 2804642e01fSmrg 281f7df2e56Smrg if (firstValuator + numValuators > dev->valuator->numAxes) { 2824642e01fSmrg client->errorValue = dv->num_valuators; 2834642e01fSmrg return BadValue; 2844642e01fSmrg } 2854642e01fSmrg } 2864642e01fSmrg type = type - XI_DeviceKeyPress + KeyPress; 2874642e01fSmrg 288f7df2e56Smrg } 289f7df2e56Smrg else { 2904642e01fSmrg if (nev != 1) 2914642e01fSmrg return BadLength; 292f7df2e56Smrg switch (type) { 293f7df2e56Smrg case KeyPress: 294f7df2e56Smrg case KeyRelease: 295f7df2e56Smrg dev = PickKeyboard(client); 296f7df2e56Smrg break; 297f7df2e56Smrg case ButtonPress: 298f7df2e56Smrg case ButtonRelease: 299f7df2e56Smrg dev = PickPointer(client); 300f7df2e56Smrg break; 301f7df2e56Smrg case MotionNotify: 302f7df2e56Smrg dev = PickPointer(client); 303f7df2e56Smrg valuators[0] = ev->u.keyButtonPointer.rootX; 304f7df2e56Smrg valuators[1] = ev->u.keyButtonPointer.rootY; 305f7df2e56Smrg numValuators = 2; 306f7df2e56Smrg firstValuator = 0; 307f7df2e56Smrg if (ev->u.u.detail == xFalse) 308f7df2e56Smrg flags = POINTER_ABSOLUTE | POINTER_DESKTOP; 309f7df2e56Smrg break; 310f7df2e56Smrg default: 311f7df2e56Smrg client->errorValue = ev->u.u.type; 312f7df2e56Smrg return BadValue; 3134642e01fSmrg } 3144642e01fSmrg 315f7df2e56Smrg /* Technically the protocol doesn't allow for BadAccess here but 316f7df2e56Smrg * this can only happen when all MDs are disabled. */ 317f7df2e56Smrg if (!dev) 318f7df2e56Smrg return BadAccess; 319f7df2e56Smrg 3204202a189Smrg dev = GetXTestDevice(dev); 32105b261ecSmrg } 3224642e01fSmrg 323f7df2e56Smrg 3244642e01fSmrg /* If the event has a time set, wait for it to pass */ 325f7df2e56Smrg if (ev->u.keyButtonPointer.time) { 3264642e01fSmrg TimeStamp activateTime; 3274642e01fSmrg CARD32 ms; 3284642e01fSmrg 3294642e01fSmrg activateTime = currentTime; 3304642e01fSmrg ms = activateTime.milliseconds + ev->u.keyButtonPointer.time; 3314642e01fSmrg if (ms < activateTime.milliseconds) 3324642e01fSmrg activateTime.months++; 3334642e01fSmrg activateTime.milliseconds = ms; 3344642e01fSmrg ev->u.keyButtonPointer.time = 0; 3354642e01fSmrg 3364202a189Smrg /* see mbuf.c:QueueDisplayRequest (from the deprecated Multibuffer 3374202a189Smrg * extension) for code similar to this */ 3384642e01fSmrg 339f7df2e56Smrg if (!ClientSleepUntil(client, &activateTime, NULL, NULL)) { 3404642e01fSmrg return BadAlloc; 3414642e01fSmrg } 3424642e01fSmrg /* swap the request back so we can simply re-execute it */ 343f7df2e56Smrg if (client->swapped) { 344f7df2e56Smrg (void) XTestSwapFakeInput(client, (xReq *) stuff); 345f7df2e56Smrg swaps(&stuff->length); 3464642e01fSmrg } 347f7df2e56Smrg ResetCurrentRequest(client); 3484642e01fSmrg client->sequence--; 3494642e01fSmrg return Success; 35005b261ecSmrg } 3514642e01fSmrg 352f7df2e56Smrg switch (type) { 353f7df2e56Smrg case KeyPress: 354f7df2e56Smrg case KeyRelease: 355f7df2e56Smrg if (!dev->key) 356f7df2e56Smrg return BadDevice; 3574202a189Smrg 358f7df2e56Smrg if (ev->u.u.detail < dev->key->xkbInfo->desc->min_key_code || 359f7df2e56Smrg ev->u.u.detail > dev->key->xkbInfo->desc->max_key_code) { 360f7df2e56Smrg client->errorValue = ev->u.u.detail; 361f7df2e56Smrg return BadValue; 362f7df2e56Smrg } 363f7df2e56Smrg 364f7df2e56Smrg need_ptr_update = 0; 365f7df2e56Smrg break; 366f7df2e56Smrg case MotionNotify: 367f7df2e56Smrg if (!dev->valuator) 368f7df2e56Smrg return BadDevice; 369f7df2e56Smrg 370f7df2e56Smrg if (!(extension || ev->u.keyButtonPointer.root == None)) { 371f7df2e56Smrg rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root, 372f7df2e56Smrg client, DixGetAttrAccess); 373f7df2e56Smrg if (rc != Success) 374f7df2e56Smrg return rc; 375f7df2e56Smrg if (root->parent) { 376f7df2e56Smrg client->errorValue = ev->u.keyButtonPointer.root; 3774642e01fSmrg return BadValue; 3784642e01fSmrg } 3794202a189Smrg 380f7df2e56Smrg /* Add the root window's offset to the valuators */ 381f7df2e56Smrg if ((flags & POINTER_ABSOLUTE) && firstValuator <= 1 && numValuators > 0) { 382f7df2e56Smrg if (firstValuator == 0) 383f7df2e56Smrg valuators[0] += root->drawable.pScreen->x; 384f7df2e56Smrg if (firstValuator < 2 && firstValuator + numValuators > 1) 385f7df2e56Smrg valuators[1 - firstValuator] += root->drawable.pScreen->y; 3864642e01fSmrg } 387f7df2e56Smrg } 388f7df2e56Smrg if (ev->u.u.detail != xTrue && ev->u.u.detail != xFalse) { 389f7df2e56Smrg client->errorValue = ev->u.u.detail; 390f7df2e56Smrg return BadValue; 391f7df2e56Smrg } 3924642e01fSmrg 393f7df2e56Smrg /* FIXME: Xinerama! */ 3944642e01fSmrg 395f7df2e56Smrg break; 396f7df2e56Smrg case ButtonPress: 397f7df2e56Smrg case ButtonRelease: 398f7df2e56Smrg if (!dev->button) 399f7df2e56Smrg return BadDevice; 4004202a189Smrg 401f7df2e56Smrg if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons) { 402f7df2e56Smrg client->errorValue = ev->u.u.detail; 403f7df2e56Smrg return BadValue; 404f7df2e56Smrg } 405f7df2e56Smrg break; 40605b261ecSmrg } 40705b261ecSmrg if (screenIsSaved == SCREEN_SAVER_ON) 4084642e01fSmrg dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); 4094642e01fSmrg 410f7df2e56Smrg switch (type) { 411f7df2e56Smrg case MotionNotify: 412f7df2e56Smrg valuator_mask_set_range(&mask, firstValuator, numValuators, valuators); 413f7df2e56Smrg nevents = GetPointerEvents(xtest_evlist, dev, type, 0, flags, &mask); 414f7df2e56Smrg break; 415f7df2e56Smrg case ButtonPress: 416f7df2e56Smrg case ButtonRelease: 417f7df2e56Smrg valuator_mask_set_range(&mask, firstValuator, numValuators, valuators); 418f7df2e56Smrg nevents = GetPointerEvents(xtest_evlist, dev, type, ev->u.u.detail, 419f7df2e56Smrg flags, &mask); 420f7df2e56Smrg break; 421f7df2e56Smrg case KeyPress: 422f7df2e56Smrg case KeyRelease: 423f7df2e56Smrg nevents = 424f7df2e56Smrg GetKeyboardEvents(xtest_evlist, dev, type, ev->u.u.detail); 425f7df2e56Smrg break; 4264642e01fSmrg } 4274642e01fSmrg 4284642e01fSmrg for (i = 0; i < nevents; i++) 429f7df2e56Smrg mieqProcessDeviceEvent(dev, &xtest_evlist[i], miPointerGetScreen(inputInfo.pointer)); 4304642e01fSmrg 4314202a189Smrg if (need_ptr_update) 4324202a189Smrg miPointerUpdateSprite(dev); 4334202a189Smrg return Success; 43405b261ecSmrg} 43505b261ecSmrg 43605b261ecSmrgstatic int 4374202a189SmrgProcXTestGrabControl(ClientPtr client) 43805b261ecSmrg{ 43905b261ecSmrg REQUEST(xXTestGrabControlReq); 44005b261ecSmrg 44105b261ecSmrg REQUEST_SIZE_MATCH(xXTestGrabControlReq); 442f7df2e56Smrg if ((stuff->impervious != xTrue) && (stuff->impervious != xFalse)) { 4434642e01fSmrg client->errorValue = stuff->impervious; 4444202a189Smrg return BadValue; 44505b261ecSmrg } 44605b261ecSmrg if (stuff->impervious) 4474642e01fSmrg MakeClientGrabImpervious(client); 44805b261ecSmrg else 4494642e01fSmrg MakeClientGrabPervious(client); 4504202a189Smrg return Success; 45105b261ecSmrg} 45205b261ecSmrg 45305b261ecSmrgstatic int 454f7df2e56SmrgProcXTestDispatch(ClientPtr client) 45505b261ecSmrg{ 45605b261ecSmrg REQUEST(xReq); 457f7df2e56Smrg switch (stuff->data) { 458f7df2e56Smrg case X_XTestGetVersion: 459f7df2e56Smrg return ProcXTestGetVersion(client); 460f7df2e56Smrg case X_XTestCompareCursor: 461f7df2e56Smrg return ProcXTestCompareCursor(client); 462f7df2e56Smrg case X_XTestFakeInput: 463f7df2e56Smrg return ProcXTestFakeInput(client); 464f7df2e56Smrg case X_XTestGrabControl: 465f7df2e56Smrg return ProcXTestGrabControl(client); 466f7df2e56Smrg default: 467f7df2e56Smrg return BadRequest; 46805b261ecSmrg } 46905b261ecSmrg} 47005b261ecSmrg 4717e31ba66Smrgstatic int _X_COLD 4724202a189SmrgSProcXTestGetVersion(ClientPtr client) 47305b261ecSmrg{ 47405b261ecSmrg REQUEST(xXTestGetVersionReq); 47505b261ecSmrg 476f7df2e56Smrg swaps(&stuff->length); 47705b261ecSmrg REQUEST_SIZE_MATCH(xXTestGetVersionReq); 478f7df2e56Smrg swaps(&stuff->minorVersion); 47905b261ecSmrg return ProcXTestGetVersion(client); 48005b261ecSmrg} 48105b261ecSmrg 4827e31ba66Smrgstatic int _X_COLD 4834202a189SmrgSProcXTestCompareCursor(ClientPtr client) 48405b261ecSmrg{ 48505b261ecSmrg REQUEST(xXTestCompareCursorReq); 48605b261ecSmrg 487f7df2e56Smrg swaps(&stuff->length); 48805b261ecSmrg REQUEST_SIZE_MATCH(xXTestCompareCursorReq); 489f7df2e56Smrg swapl(&stuff->window); 490f7df2e56Smrg swapl(&stuff->cursor); 49105b261ecSmrg return ProcXTestCompareCursor(client); 49205b261ecSmrg} 49305b261ecSmrg 4947e31ba66Smrgstatic int _X_COLD 495f7df2e56SmrgXTestSwapFakeInput(ClientPtr client, xReq * req) 49605b261ecSmrg{ 4974642e01fSmrg int nev; 4984642e01fSmrg xEvent *ev; 49905b261ecSmrg xEvent sev; 50005b261ecSmrg EventSwapPtr proc; 50105b261ecSmrg 50205b261ecSmrg nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent); 503f7df2e56Smrg for (ev = (xEvent *) &req[1]; --nev >= 0; ev++) { 5044642e01fSmrg /* Swap event */ 5054642e01fSmrg proc = EventSwapVector[ev->u.u.type & 0177]; 5064642e01fSmrg /* no swapping proc; invalid event type? */ 507f7df2e56Smrg if (!proc || proc == NotImplemented) { 5084642e01fSmrg client->errorValue = ev->u.u.type; 5094642e01fSmrg return BadValue; 5104642e01fSmrg } 511f7df2e56Smrg (*proc) (ev, &sev); 5124642e01fSmrg *ev = sev; 51305b261ecSmrg } 51405b261ecSmrg return Success; 51505b261ecSmrg} 51605b261ecSmrg 5177e31ba66Smrgstatic int _X_COLD 5184202a189SmrgSProcXTestFakeInput(ClientPtr client) 51905b261ecSmrg{ 5204642e01fSmrg int n; 521f7df2e56Smrg 52205b261ecSmrg REQUEST(xReq); 52305b261ecSmrg 524f7df2e56Smrg swaps(&stuff->length); 52505b261ecSmrg n = XTestSwapFakeInput(client, stuff); 52605b261ecSmrg if (n != Success) 5274642e01fSmrg return n; 52805b261ecSmrg return ProcXTestFakeInput(client); 52905b261ecSmrg} 53005b261ecSmrg 5317e31ba66Smrgstatic int _X_COLD 5324202a189SmrgSProcXTestGrabControl(ClientPtr client) 53305b261ecSmrg{ 53405b261ecSmrg REQUEST(xXTestGrabControlReq); 53505b261ecSmrg 536f7df2e56Smrg swaps(&stuff->length); 53705b261ecSmrg REQUEST_SIZE_MATCH(xXTestGrabControlReq); 53805b261ecSmrg return ProcXTestGrabControl(client); 53905b261ecSmrg} 54005b261ecSmrg 5417e31ba66Smrgstatic int _X_COLD 542f7df2e56SmrgSProcXTestDispatch(ClientPtr client) 54305b261ecSmrg{ 54405b261ecSmrg REQUEST(xReq); 545f7df2e56Smrg switch (stuff->data) { 546f7df2e56Smrg case X_XTestGetVersion: 547f7df2e56Smrg return SProcXTestGetVersion(client); 548f7df2e56Smrg case X_XTestCompareCursor: 549f7df2e56Smrg return SProcXTestCompareCursor(client); 550f7df2e56Smrg case X_XTestFakeInput: 551f7df2e56Smrg return SProcXTestFakeInput(client); 552f7df2e56Smrg case X_XTestGrabControl: 553f7df2e56Smrg return SProcXTestGrabControl(client); 554f7df2e56Smrg default: 555f7df2e56Smrg return BadRequest; 55605b261ecSmrg } 55705b261ecSmrg} 5584202a189Smrg 5594202a189Smrg/** 5604202a189Smrg * Allocate an virtual slave device for xtest events, this 5614202a189Smrg * is a slave device to inputInfo master devices 5624202a189Smrg */ 563f7df2e56Smrgvoid 564f7df2e56SmrgInitXTestDevices(void) 5654202a189Smrg{ 566f7df2e56Smrg if (AllocXTestDevice(serverClient, "Virtual core", 567f7df2e56Smrg &xtestpointer, &xtestkeyboard, 568f7df2e56Smrg inputInfo.pointer, inputInfo.keyboard) != Success) 569f7df2e56Smrg FatalError("Failed to allocate XTest devices"); 5704202a189Smrg 5714202a189Smrg if (ActivateDevice(xtestpointer, TRUE) != Success || 5724202a189Smrg ActivateDevice(xtestkeyboard, TRUE) != Success) 5734202a189Smrg FatalError("Failed to activate XTest core devices."); 574f7df2e56Smrg if (!EnableDevice(xtestpointer, TRUE) || !EnableDevice(xtestkeyboard, TRUE)) 5754202a189Smrg FatalError("Failed to enable XTest core devices."); 5764202a189Smrg 5774202a189Smrg AttachDevice(NULL, xtestpointer, inputInfo.pointer); 578f7df2e56Smrg 5794202a189Smrg AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard); 5804202a189Smrg} 5814202a189Smrg 5824202a189Smrg/** 5834202a189Smrg * Don't allow changing the XTest property. 5844202a189Smrg */ 5854202a189Smrgstatic int 5864202a189SmrgDeviceSetXTestProperty(DeviceIntPtr dev, Atom property, 587f7df2e56Smrg XIPropertyValuePtr prop, BOOL checkonly) 5884202a189Smrg{ 5894202a189Smrg if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE)) 5904202a189Smrg return BadAccess; 5914202a189Smrg 5924202a189Smrg return Success; 5934202a189Smrg} 5944202a189Smrg 5954202a189Smrg/** 5964202a189Smrg * Allocate a device pair that is initialised as a slave 5974202a189Smrg * device with properties that identify the devices as belonging 5984202a189Smrg * to XTest subsystem. 5994202a189Smrg * This only creates the pair, Activate/Enable Device 6004202a189Smrg * still need to be called. 6014202a189Smrg */ 602f7df2e56Smrgint 603f7df2e56SmrgAllocXTestDevice(ClientPtr client, const char *name, 604f7df2e56Smrg DeviceIntPtr *ptr, DeviceIntPtr *keybd, 605f7df2e56Smrg DeviceIntPtr master_ptr, DeviceIntPtr master_keybd) 6064202a189Smrg{ 6074202a189Smrg int retval; 608f7df2e56Smrg char *xtestname; 6094202a189Smrg char dummy = 1; 6104202a189Smrg 611f7df2e56Smrg if (asprintf(&xtestname, "%s XTEST", name) == -1) 612f7df2e56Smrg return BadAlloc; 6134202a189Smrg 614f7df2e56Smrg retval = 615f7df2e56Smrg AllocDevicePair(client, xtestname, ptr, keybd, CorePointerProc, 616f7df2e56Smrg CoreKeyboardProc, FALSE); 617f7df2e56Smrg if (retval == Success) { 618f7df2e56Smrg (*ptr)->xtest_master_id = master_ptr->id; 619f7df2e56Smrg (*keybd)->xtest_master_id = master_keybd->id; 6204202a189Smrg 6214202a189Smrg XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 622f7df2e56Smrg XA_INTEGER, 8, PropModeReplace, 1, &dummy, 623f7df2e56Smrg FALSE); 624f7df2e56Smrg XISetDevicePropertyDeletable(*ptr, 625f7df2e56Smrg XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 626f7df2e56Smrg FALSE); 6274202a189Smrg XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL); 6284202a189Smrg XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 629f7df2e56Smrg XA_INTEGER, 8, PropModeReplace, 1, &dummy, 630f7df2e56Smrg FALSE); 631f7df2e56Smrg XISetDevicePropertyDeletable(*keybd, 632f7df2e56Smrg XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 633f7df2e56Smrg FALSE); 6344202a189Smrg XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL); 6354202a189Smrg } 6364202a189Smrg 637f7df2e56Smrg free(xtestname); 6384202a189Smrg 6394202a189Smrg return retval; 6404202a189Smrg} 6414202a189Smrg 6424202a189Smrg/** 6434202a189Smrg * If master is NULL, return TRUE if the given device is an xtest device or 6444202a189Smrg * FALSE otherwise. 6454202a189Smrg * If master is not NULL, return TRUE if the given device is this master's 6464202a189Smrg * xtest device. 6474202a189Smrg */ 6484202a189SmrgBOOL 6494202a189SmrgIsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master) 6504202a189Smrg{ 6514202a189Smrg if (IsMaster(dev)) 6524202a189Smrg return FALSE; 6534202a189Smrg 6544202a189Smrg /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest 6554202a189Smrg * device */ 6564202a189Smrg if (master) 657f7df2e56Smrg return dev->xtest_master_id == master->id; 6584202a189Smrg 6594202a189Smrg return dev->xtest_master_id != 0; 6604202a189Smrg} 6614202a189Smrg 6624202a189Smrg/** 6634202a189Smrg * @return The X Test virtual device for the given master. 6644202a189Smrg */ 6654202a189SmrgDeviceIntPtr 6664202a189SmrgGetXTestDevice(DeviceIntPtr master) 6674202a189Smrg{ 6684202a189Smrg DeviceIntPtr it; 6694202a189Smrg 670f7df2e56Smrg for (it = inputInfo.devices; it; it = it->next) { 6714202a189Smrg if (IsXTestDevice(it, master)) 6724202a189Smrg return it; 6734202a189Smrg } 6744202a189Smrg 6754202a189Smrg /* This only happens if master is a slave device. don't do that */ 6764202a189Smrg return NULL; 6774202a189Smrg} 6784202a189Smrg 679f7df2e56Smrgstatic void 680f7df2e56SmrgXTestExtensionTearDown(ExtensionEntry * e) 681f7df2e56Smrg{ 682f7df2e56Smrg FreeEventList(xtest_evlist, GetMaximumEventsNum()); 683f7df2e56Smrg xtest_evlist = NULL; 684f7df2e56Smrg} 685f7df2e56Smrg 68665b04b38Smrgvoid 687f7df2e56SmrgXTestExtensionInit(void) 68865b04b38Smrg{ 68965b04b38Smrg AddExtension(XTestExtensionName, 0, 0, 690f7df2e56Smrg ProcXTestDispatch, SProcXTestDispatch, 691f7df2e56Smrg XTestExtensionTearDown, StandardMinorOpcode); 69265b04b38Smrg 69365b04b38Smrg xtest_evlist = InitEventList(GetMaximumEventsNum()); 69465b04b38Smrg} 695