1706f2543Smrg/* 2706f2543Smrg 3706f2543Smrg Copyright 1992, 1998 The Open Group 4706f2543Smrg 5706f2543Smrg Permission to use, copy, modify, distribute, and sell this software and its 6706f2543Smrg documentation for any purpose is hereby granted without fee, provided that 7706f2543Smrg the above copyright notice appear in all copies and that both that 8706f2543Smrg copyright notice and this permission notice appear in supporting 9706f2543Smrg documentation. 10706f2543Smrg 11706f2543Smrg The above copyright notice and this permission notice shall be included 12706f2543Smrg in all copies or substantial portions of the Software. 13706f2543Smrg 14706f2543Smrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15706f2543Smrg OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16706f2543Smrg MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17706f2543Smrg IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18706f2543Smrg OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19706f2543Smrg ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20706f2543Smrg OTHER DEALINGS IN THE SOFTWARE. 21706f2543Smrg 22706f2543Smrg Except as contained in this notice, the name of The Open Group shall 23706f2543Smrg not be used in advertising or otherwise to promote the sale, use or 24706f2543Smrg other dealings in this Software without prior written authorization 25706f2543Smrg from The Open Group. 26706f2543Smrg 27706f2543Smrg */ 28706f2543Smrg 29706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 30706f2543Smrg#include <dix-config.h> 31706f2543Smrg#endif 32706f2543Smrg 33706f2543Smrg#include <X11/X.h> 34706f2543Smrg#include <X11/Xproto.h> 35706f2543Smrg#include <X11/Xatom.h> 36706f2543Smrg#include "misc.h" 37706f2543Smrg#include "os.h" 38706f2543Smrg#include "dixstruct.h" 39706f2543Smrg#include "extnsionst.h" 40706f2543Smrg#include "windowstr.h" 41706f2543Smrg#include "inputstr.h" 42706f2543Smrg#include "scrnintstr.h" 43706f2543Smrg#include "dixevents.h" 44706f2543Smrg#include "sleepuntil.h" 45706f2543Smrg#include "mi.h" 46706f2543Smrg#include "xkbsrv.h" 47706f2543Smrg#include "xkbstr.h" 48706f2543Smrg#include <X11/extensions/xtestproto.h> 49706f2543Smrg#include <X11/extensions/XI.h> 50706f2543Smrg#include <X11/extensions/XIproto.h> 51706f2543Smrg#include "exglobals.h" 52706f2543Smrg#include "mipointer.h" 53706f2543Smrg#include "xserver-properties.h" 54706f2543Smrg#include "exevents.h" 55706f2543Smrg#include "inpututils.h" 56706f2543Smrg 57706f2543Smrg#include "modinit.h" 58706f2543Smrg 59706f2543Smrgextern int DeviceValuator; 60706f2543Smrg 61706f2543Smrg/* XTest events are sent during request processing and may be interruped by 62706f2543Smrg * a SIGIO. We need a separate event list to avoid events overwriting each 63706f2543Smrg * other's memory */ 64706f2543Smrgstatic EventListPtr xtest_evlist; 65706f2543Smrg 66706f2543Smrg/** 67706f2543Smrg * xtestpointer 68706f2543Smrg * is the virtual pointer for XTest. It is the first slave 69706f2543Smrg * device of the VCP. 70706f2543Smrg * xtestkeyboard 71706f2543Smrg * is the virtual keyboard for XTest. It is the first slave 72706f2543Smrg * device of the VCK 73706f2543Smrg * 74706f2543Smrg * Neither of these devices can be deleted. 75706f2543Smrg */ 76706f2543SmrgDeviceIntPtr xtestpointer, xtestkeyboard; 77706f2543Smrg 78706f2543Smrg#ifdef PANORAMIX 79706f2543Smrg#include "panoramiX.h" 80706f2543Smrg#include "panoramiXsrv.h" 81706f2543Smrg#endif 82706f2543Smrg 83706f2543Smrgstatic int XTestSwapFakeInput( 84706f2543Smrg ClientPtr /* client */, 85706f2543Smrg xReq * /* req */ 86706f2543Smrg ); 87706f2543Smrg 88706f2543Smrg 89706f2543Smrgstatic int 90706f2543SmrgProcXTestGetVersion(ClientPtr client) 91706f2543Smrg{ 92706f2543Smrg xXTestGetVersionReply rep; 93706f2543Smrg int n; 94706f2543Smrg 95706f2543Smrg REQUEST_SIZE_MATCH(xXTestGetVersionReq); 96706f2543Smrg rep.type = X_Reply; 97706f2543Smrg rep.length = 0; 98706f2543Smrg rep.sequenceNumber = client->sequence; 99706f2543Smrg rep.majorVersion = XTestMajorVersion; 100706f2543Smrg rep.minorVersion = XTestMinorVersion; 101706f2543Smrg if (client->swapped) { 102706f2543Smrg swaps(&rep.sequenceNumber, n); 103706f2543Smrg swaps(&rep.minorVersion, n); 104706f2543Smrg } 105706f2543Smrg WriteToClient(client, sizeof(xXTestGetVersionReply), (char *)&rep); 106706f2543Smrg return Success; 107706f2543Smrg} 108706f2543Smrg 109706f2543Smrgstatic int 110706f2543SmrgProcXTestCompareCursor(ClientPtr client) 111706f2543Smrg{ 112706f2543Smrg REQUEST(xXTestCompareCursorReq); 113706f2543Smrg xXTestCompareCursorReply rep; 114706f2543Smrg WindowPtr pWin; 115706f2543Smrg CursorPtr pCursor; 116706f2543Smrg int n, rc; 117706f2543Smrg DeviceIntPtr ptr = PickPointer(client); 118706f2543Smrg 119706f2543Smrg REQUEST_SIZE_MATCH(xXTestCompareCursorReq); 120706f2543Smrg rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 121706f2543Smrg if (rc != Success) 122706f2543Smrg return rc; 123706f2543Smrg if (stuff->cursor == None) 124706f2543Smrg pCursor = NullCursor; 125706f2543Smrg else if (stuff->cursor == XTestCurrentCursor) 126706f2543Smrg pCursor = GetSpriteCursor(ptr); 127706f2543Smrg else { 128706f2543Smrg rc = dixLookupResourceByType((pointer *)&pCursor, stuff->cursor, RT_CURSOR, 129706f2543Smrg client, DixReadAccess); 130706f2543Smrg if (rc != Success) 131706f2543Smrg { 132706f2543Smrg client->errorValue = stuff->cursor; 133706f2543Smrg return rc; 134706f2543Smrg } 135706f2543Smrg } 136706f2543Smrg rep.type = X_Reply; 137706f2543Smrg rep.length = 0; 138706f2543Smrg rep.sequenceNumber = client->sequence; 139706f2543Smrg rep.same = (wCursor(pWin) == pCursor); 140706f2543Smrg if (client->swapped) { 141706f2543Smrg swaps(&rep.sequenceNumber, n); 142706f2543Smrg } 143706f2543Smrg WriteToClient(client, sizeof(xXTestCompareCursorReply), (char *)&rep); 144706f2543Smrg return Success; 145706f2543Smrg} 146706f2543Smrg 147706f2543Smrgstatic int 148706f2543SmrgProcXTestFakeInput(ClientPtr client) 149706f2543Smrg{ 150706f2543Smrg REQUEST(xXTestFakeInputReq); 151706f2543Smrg int nev, n, type, rc; 152706f2543Smrg xEvent *ev; 153706f2543Smrg DeviceIntPtr dev = NULL; 154706f2543Smrg WindowPtr root; 155706f2543Smrg Bool extension = FALSE; 156706f2543Smrg deviceValuator *dv = NULL; 157706f2543Smrg ValuatorMask mask; 158706f2543Smrg int valuators[MAX_VALUATORS] = {0}; 159706f2543Smrg int numValuators = 0; 160706f2543Smrg int firstValuator = 0; 161706f2543Smrg int nevents = 0; 162706f2543Smrg int i; 163706f2543Smrg int base = 0; 164706f2543Smrg int flags = 0; 165706f2543Smrg int need_ptr_update = 1; 166706f2543Smrg 167706f2543Smrg nev = (stuff->length << 2) - sizeof(xReq); 168706f2543Smrg if ((nev % sizeof(xEvent)) || !nev) 169706f2543Smrg return BadLength; 170706f2543Smrg nev /= sizeof(xEvent); 171706f2543Smrg UpdateCurrentTime(); 172706f2543Smrg ev = (xEvent *)&((xReq *)stuff)[1]; 173706f2543Smrg type = ev->u.u.type & 0177; 174706f2543Smrg 175706f2543Smrg if (type >= EXTENSION_EVENT_BASE) 176706f2543Smrg { 177706f2543Smrg extension = TRUE; 178706f2543Smrg 179706f2543Smrg /* check device */ 180706f2543Smrg rc = dixLookupDevice(&dev, stuff->deviceid & 0177, client, 181706f2543Smrg DixWriteAccess); 182706f2543Smrg if (rc != Success) 183706f2543Smrg { 184706f2543Smrg client->errorValue = stuff->deviceid & 0177; 185706f2543Smrg return rc; 186706f2543Smrg } 187706f2543Smrg 188706f2543Smrg /* check type */ 189706f2543Smrg type -= DeviceValuator; 190706f2543Smrg switch (type) { 191706f2543Smrg case XI_DeviceKeyPress: 192706f2543Smrg case XI_DeviceKeyRelease: 193706f2543Smrg if (!dev->key) 194706f2543Smrg { 195706f2543Smrg client->errorValue = ev->u.u.type; 196706f2543Smrg return BadValue; 197706f2543Smrg } 198706f2543Smrg break; 199706f2543Smrg case XI_DeviceButtonPress: 200706f2543Smrg case XI_DeviceButtonRelease: 201706f2543Smrg if (!dev->button) 202706f2543Smrg { 203706f2543Smrg client->errorValue = ev->u.u.type; 204706f2543Smrg return BadValue; 205706f2543Smrg } 206706f2543Smrg break; 207706f2543Smrg case XI_DeviceMotionNotify: 208706f2543Smrg if (!dev->valuator) 209706f2543Smrg { 210706f2543Smrg client->errorValue = ev->u.u.type; 211706f2543Smrg return BadValue; 212706f2543Smrg } 213706f2543Smrg break; 214706f2543Smrg case XI_ProximityIn: 215706f2543Smrg case XI_ProximityOut: 216706f2543Smrg if (!dev->proximity) 217706f2543Smrg { 218706f2543Smrg client->errorValue = ev->u.u.type; 219706f2543Smrg return BadValue; 220706f2543Smrg } 221706f2543Smrg break; 222706f2543Smrg default: 223706f2543Smrg client->errorValue = ev->u.u.type; 224706f2543Smrg return BadValue; 225706f2543Smrg } 226706f2543Smrg 227706f2543Smrg /* check validity */ 228706f2543Smrg if (nev == 1 && type == XI_DeviceMotionNotify) 229706f2543Smrg return BadLength; /* DevMotion must be followed by DevValuator */ 230706f2543Smrg 231706f2543Smrg if (type == XI_DeviceMotionNotify) 232706f2543Smrg { 233706f2543Smrg firstValuator = ((deviceValuator *)(ev+1))->first_valuator; 234706f2543Smrg if (firstValuator > dev->valuator->numAxes) 235706f2543Smrg { 236706f2543Smrg client->errorValue = ev->u.u.type; 237706f2543Smrg return BadValue; 238706f2543Smrg } 239706f2543Smrg 240706f2543Smrg if (ev->u.u.detail == xFalse) 241706f2543Smrg flags |= POINTER_ABSOLUTE; 242706f2543Smrg } else 243706f2543Smrg { 244706f2543Smrg firstValuator = 0; 245706f2543Smrg flags |= POINTER_ABSOLUTE; 246706f2543Smrg } 247706f2543Smrg 248706f2543Smrg if (nev > 1 && !dev->valuator) 249706f2543Smrg { 250706f2543Smrg client->errorValue = dv->first_valuator; 251706f2543Smrg return BadValue; 252706f2543Smrg } 253706f2543Smrg 254706f2543Smrg 255706f2543Smrg /* check validity of valuator events */ 256706f2543Smrg base = firstValuator; 257706f2543Smrg for (n = 1; n < nev; n++) 258706f2543Smrg { 259706f2543Smrg dv = (deviceValuator *)(ev + n); 260706f2543Smrg if (dv->type != DeviceValuator) 261706f2543Smrg { 262706f2543Smrg client->errorValue = dv->type; 263706f2543Smrg return BadValue; 264706f2543Smrg } 265706f2543Smrg if (dv->first_valuator != base) 266706f2543Smrg { 267706f2543Smrg client->errorValue = dv->first_valuator; 268706f2543Smrg return BadValue; 269706f2543Smrg } 270706f2543Smrg switch(dv->num_valuators) 271706f2543Smrg { 272706f2543Smrg case 6: valuators[base + 5] = dv->valuator5; 273706f2543Smrg case 5: valuators[base + 4] = dv->valuator4; 274706f2543Smrg case 4: valuators[base + 3] = dv->valuator3; 275706f2543Smrg case 3: valuators[base + 2] = dv->valuator2; 276706f2543Smrg case 2: valuators[base + 1] = dv->valuator1; 277706f2543Smrg case 1: valuators[base] = dv->valuator0; 278706f2543Smrg break; 279706f2543Smrg default: 280706f2543Smrg client->errorValue = dv->num_valuators; 281706f2543Smrg return BadValue; 282706f2543Smrg } 283706f2543Smrg 284706f2543Smrg base += dv->num_valuators; 285706f2543Smrg numValuators += dv->num_valuators; 286706f2543Smrg 287706f2543Smrg if (firstValuator + numValuators > dev->valuator->numAxes) 288706f2543Smrg { 289706f2543Smrg client->errorValue = dv->num_valuators; 290706f2543Smrg return BadValue; 291706f2543Smrg } 292706f2543Smrg } 293706f2543Smrg type = type - XI_DeviceKeyPress + KeyPress; 294706f2543Smrg 295706f2543Smrg } else 296706f2543Smrg { 297706f2543Smrg if (nev != 1) 298706f2543Smrg return BadLength; 299706f2543Smrg switch (type) 300706f2543Smrg { 301706f2543Smrg case KeyPress: 302706f2543Smrg case KeyRelease: 303706f2543Smrg dev = PickKeyboard(client); 304706f2543Smrg break; 305706f2543Smrg case ButtonPress: 306706f2543Smrg case ButtonRelease: 307706f2543Smrg dev = PickPointer(client); 308706f2543Smrg break; 309706f2543Smrg case MotionNotify: 310706f2543Smrg dev = PickPointer(client); 311706f2543Smrg valuators[0] = ev->u.keyButtonPointer.rootX; 312706f2543Smrg valuators[1] = ev->u.keyButtonPointer.rootY; 313706f2543Smrg numValuators = 2; 314706f2543Smrg firstValuator = 0; 315706f2543Smrg if (ev->u.u.detail == xFalse) 316706f2543Smrg flags = POINTER_ABSOLUTE | POINTER_SCREEN; 317706f2543Smrg break; 318706f2543Smrg default: 319706f2543Smrg client->errorValue = ev->u.u.type; 320706f2543Smrg return BadValue; 321706f2543Smrg } 322706f2543Smrg 323706f2543Smrg dev = GetXTestDevice(dev); 324706f2543Smrg } 325706f2543Smrg 326706f2543Smrg /* If the event has a time set, wait for it to pass */ 327706f2543Smrg if (ev->u.keyButtonPointer.time) 328706f2543Smrg { 329706f2543Smrg TimeStamp activateTime; 330706f2543Smrg CARD32 ms; 331706f2543Smrg 332706f2543Smrg activateTime = currentTime; 333706f2543Smrg ms = activateTime.milliseconds + ev->u.keyButtonPointer.time; 334706f2543Smrg if (ms < activateTime.milliseconds) 335706f2543Smrg activateTime.months++; 336706f2543Smrg activateTime.milliseconds = ms; 337706f2543Smrg ev->u.keyButtonPointer.time = 0; 338706f2543Smrg 339706f2543Smrg /* see mbuf.c:QueueDisplayRequest (from the deprecated Multibuffer 340706f2543Smrg * extension) for code similar to this */ 341706f2543Smrg 342706f2543Smrg if (!ClientSleepUntil(client, &activateTime, NULL, NULL)) 343706f2543Smrg { 344706f2543Smrg return BadAlloc; 345706f2543Smrg } 346706f2543Smrg /* swap the request back so we can simply re-execute it */ 347706f2543Smrg if (client->swapped) 348706f2543Smrg { 349706f2543Smrg (void) XTestSwapFakeInput(client, (xReq *)stuff); 350706f2543Smrg swaps(&stuff->length, n); 351706f2543Smrg } 352706f2543Smrg ResetCurrentRequest (client); 353706f2543Smrg client->sequence--; 354706f2543Smrg return Success; 355706f2543Smrg } 356706f2543Smrg 357706f2543Smrg switch (type) 358706f2543Smrg { 359706f2543Smrg case KeyPress: 360706f2543Smrg case KeyRelease: 361706f2543Smrg if (!dev->key) 362706f2543Smrg return BadDevice; 363706f2543Smrg 364706f2543Smrg if (ev->u.u.detail < dev->key->xkbInfo->desc->min_key_code || 365706f2543Smrg ev->u.u.detail > dev->key->xkbInfo->desc->max_key_code) 366706f2543Smrg { 367706f2543Smrg client->errorValue = ev->u.u.detail; 368706f2543Smrg return BadValue; 369706f2543Smrg } 370706f2543Smrg 371706f2543Smrg need_ptr_update = 0; 372706f2543Smrg break; 373706f2543Smrg case MotionNotify: 374706f2543Smrg if (!dev->valuator) 375706f2543Smrg return BadDevice; 376706f2543Smrg 377706f2543Smrg if (!(extension || ev->u.keyButtonPointer.root == None)) 378706f2543Smrg { 379706f2543Smrg rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root, 380706f2543Smrg client, DixGetAttrAccess); 381706f2543Smrg if (rc != Success) 382706f2543Smrg return rc; 383706f2543Smrg if (root->parent) 384706f2543Smrg { 385706f2543Smrg client->errorValue = ev->u.keyButtonPointer.root; 386706f2543Smrg return BadValue; 387706f2543Smrg } 388706f2543Smrg } 389706f2543Smrg if (ev->u.u.detail != xTrue && ev->u.u.detail != xFalse) 390706f2543Smrg { 391706f2543Smrg client->errorValue = ev->u.u.detail; 392706f2543Smrg return BadValue; 393706f2543Smrg } 394706f2543Smrg 395706f2543Smrg /* FIXME: Xinerama! */ 396706f2543Smrg 397706f2543Smrg break; 398706f2543Smrg case ButtonPress: 399706f2543Smrg case ButtonRelease: 400706f2543Smrg if (!dev->button) 401706f2543Smrg return BadDevice; 402706f2543Smrg 403706f2543Smrg if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons) 404706f2543Smrg { 405706f2543Smrg client->errorValue = ev->u.u.detail; 406706f2543Smrg return BadValue; 407706f2543Smrg } 408706f2543Smrg break; 409706f2543Smrg } 410706f2543Smrg if (screenIsSaved == SCREEN_SAVER_ON) 411706f2543Smrg dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); 412706f2543Smrg 413706f2543Smrg switch(type) { 414706f2543Smrg case MotionNotify: 415706f2543Smrg valuator_mask_set_range(&mask, firstValuator, numValuators, valuators); 416706f2543Smrg nevents = GetPointerEvents(xtest_evlist, dev, type, 0, flags, &mask); 417706f2543Smrg break; 418706f2543Smrg case ButtonPress: 419706f2543Smrg case ButtonRelease: 420706f2543Smrg valuator_mask_set_range(&mask, firstValuator, numValuators, valuators); 421706f2543Smrg nevents = GetPointerEvents(xtest_evlist, dev, type, ev->u.u.detail, 422706f2543Smrg flags, &mask); 423706f2543Smrg break; 424706f2543Smrg case KeyPress: 425706f2543Smrg case KeyRelease: 426706f2543Smrg nevents = GetKeyboardEvents(xtest_evlist, dev, type, ev->u.u.detail); 427706f2543Smrg break; 428706f2543Smrg } 429706f2543Smrg 430706f2543Smrg for (i = 0; i < nevents; i++) 431706f2543Smrg mieqProcessDeviceEvent(dev, (InternalEvent*)(xtest_evlist+i)->event, NULL); 432706f2543Smrg 433706f2543Smrg if (need_ptr_update) 434706f2543Smrg miPointerUpdateSprite(dev); 435706f2543Smrg return Success; 436706f2543Smrg} 437706f2543Smrg 438706f2543Smrgstatic int 439706f2543SmrgProcXTestGrabControl(ClientPtr client) 440706f2543Smrg{ 441706f2543Smrg REQUEST(xXTestGrabControlReq); 442706f2543Smrg 443706f2543Smrg REQUEST_SIZE_MATCH(xXTestGrabControlReq); 444706f2543Smrg if ((stuff->impervious != xTrue) && (stuff->impervious != xFalse)) 445706f2543Smrg { 446706f2543Smrg client->errorValue = stuff->impervious; 447706f2543Smrg return BadValue; 448706f2543Smrg } 449706f2543Smrg if (stuff->impervious) 450706f2543Smrg MakeClientGrabImpervious(client); 451706f2543Smrg else 452706f2543Smrg MakeClientGrabPervious(client); 453706f2543Smrg return Success; 454706f2543Smrg} 455706f2543Smrg 456706f2543Smrgstatic int 457706f2543SmrgProcXTestDispatch (ClientPtr client) 458706f2543Smrg{ 459706f2543Smrg REQUEST(xReq); 460706f2543Smrg switch (stuff->data) 461706f2543Smrg { 462706f2543Smrg case X_XTestGetVersion: 463706f2543Smrg return ProcXTestGetVersion(client); 464706f2543Smrg case X_XTestCompareCursor: 465706f2543Smrg return ProcXTestCompareCursor(client); 466706f2543Smrg case X_XTestFakeInput: 467706f2543Smrg return ProcXTestFakeInput(client); 468706f2543Smrg case X_XTestGrabControl: 469706f2543Smrg return ProcXTestGrabControl(client); 470706f2543Smrg default: 471706f2543Smrg return BadRequest; 472706f2543Smrg } 473706f2543Smrg} 474706f2543Smrg 475706f2543Smrgstatic int 476706f2543SmrgSProcXTestGetVersion(ClientPtr client) 477706f2543Smrg{ 478706f2543Smrg int n; 479706f2543Smrg REQUEST(xXTestGetVersionReq); 480706f2543Smrg 481706f2543Smrg swaps(&stuff->length, n); 482706f2543Smrg REQUEST_SIZE_MATCH(xXTestGetVersionReq); 483706f2543Smrg swaps(&stuff->minorVersion, n); 484706f2543Smrg return ProcXTestGetVersion(client); 485706f2543Smrg} 486706f2543Smrg 487706f2543Smrgstatic int 488706f2543SmrgSProcXTestCompareCursor(ClientPtr client) 489706f2543Smrg{ 490706f2543Smrg int n; 491706f2543Smrg REQUEST(xXTestCompareCursorReq); 492706f2543Smrg 493706f2543Smrg swaps(&stuff->length, n); 494706f2543Smrg REQUEST_SIZE_MATCH(xXTestCompareCursorReq); 495706f2543Smrg swapl(&stuff->window, n); 496706f2543Smrg swapl(&stuff->cursor, n); 497706f2543Smrg return ProcXTestCompareCursor(client); 498706f2543Smrg} 499706f2543Smrg 500706f2543Smrgstatic int 501706f2543SmrgXTestSwapFakeInput(ClientPtr client, xReq *req) 502706f2543Smrg{ 503706f2543Smrg int nev; 504706f2543Smrg xEvent *ev; 505706f2543Smrg xEvent sev; 506706f2543Smrg EventSwapPtr proc; 507706f2543Smrg 508706f2543Smrg nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent); 509706f2543Smrg for (ev = (xEvent *)&req[1]; --nev >= 0; ev++) 510706f2543Smrg { 511706f2543Smrg /* Swap event */ 512706f2543Smrg proc = EventSwapVector[ev->u.u.type & 0177]; 513706f2543Smrg /* no swapping proc; invalid event type? */ 514706f2543Smrg if (!proc || proc == NotImplemented) { 515706f2543Smrg client->errorValue = ev->u.u.type; 516706f2543Smrg return BadValue; 517706f2543Smrg } 518706f2543Smrg (*proc)(ev, &sev); 519706f2543Smrg *ev = sev; 520706f2543Smrg } 521706f2543Smrg return Success; 522706f2543Smrg} 523706f2543Smrg 524706f2543Smrgstatic int 525706f2543SmrgSProcXTestFakeInput(ClientPtr client) 526706f2543Smrg{ 527706f2543Smrg int n; 528706f2543Smrg REQUEST(xReq); 529706f2543Smrg 530706f2543Smrg swaps(&stuff->length, n); 531706f2543Smrg n = XTestSwapFakeInput(client, stuff); 532706f2543Smrg if (n != Success) 533706f2543Smrg return n; 534706f2543Smrg return ProcXTestFakeInput(client); 535706f2543Smrg} 536706f2543Smrg 537706f2543Smrgstatic int 538706f2543SmrgSProcXTestGrabControl(ClientPtr client) 539706f2543Smrg{ 540706f2543Smrg int n; 541706f2543Smrg REQUEST(xXTestGrabControlReq); 542706f2543Smrg 543706f2543Smrg swaps(&stuff->length, n); 544706f2543Smrg REQUEST_SIZE_MATCH(xXTestGrabControlReq); 545706f2543Smrg return ProcXTestGrabControl(client); 546706f2543Smrg} 547706f2543Smrg 548706f2543Smrgstatic int 549706f2543SmrgSProcXTestDispatch (ClientPtr client) 550706f2543Smrg{ 551706f2543Smrg REQUEST(xReq); 552706f2543Smrg switch (stuff->data) 553706f2543Smrg { 554706f2543Smrg case X_XTestGetVersion: 555706f2543Smrg return SProcXTestGetVersion(client); 556706f2543Smrg case X_XTestCompareCursor: 557706f2543Smrg return SProcXTestCompareCursor(client); 558706f2543Smrg case X_XTestFakeInput: 559706f2543Smrg return SProcXTestFakeInput(client); 560706f2543Smrg case X_XTestGrabControl: 561706f2543Smrg return SProcXTestGrabControl(client); 562706f2543Smrg default: 563706f2543Smrg return BadRequest; 564706f2543Smrg } 565706f2543Smrg} 566706f2543Smrg 567706f2543Smrg/** 568706f2543Smrg * Allocate an virtual slave device for xtest events, this 569706f2543Smrg * is a slave device to inputInfo master devices 570706f2543Smrg */ 571706f2543Smrgvoid InitXTestDevices(void) 572706f2543Smrg{ 573706f2543Smrg if(AllocXTestDevice(serverClient, "Virtual core", 574706f2543Smrg &xtestpointer, &xtestkeyboard, 575706f2543Smrg inputInfo.pointer, inputInfo.keyboard) != Success) 576706f2543Smrg FatalError("Failed to allocate XTest devices"); 577706f2543Smrg 578706f2543Smrg if (ActivateDevice(xtestpointer, TRUE) != Success || 579706f2543Smrg ActivateDevice(xtestkeyboard, TRUE) != Success) 580706f2543Smrg FatalError("Failed to activate XTest core devices."); 581706f2543Smrg if (!EnableDevice(xtestpointer, TRUE) || 582706f2543Smrg !EnableDevice(xtestkeyboard, TRUE)) 583706f2543Smrg FatalError("Failed to enable XTest core devices."); 584706f2543Smrg 585706f2543Smrg AttachDevice(NULL, xtestpointer, inputInfo.pointer); 586706f2543Smrg AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard); 587706f2543Smrg} 588706f2543Smrg 589706f2543Smrg/** 590706f2543Smrg * Don't allow changing the XTest property. 591706f2543Smrg */ 592706f2543Smrgstatic int 593706f2543SmrgDeviceSetXTestProperty(DeviceIntPtr dev, Atom property, 594706f2543Smrg XIPropertyValuePtr prop, BOOL checkonly) 595706f2543Smrg{ 596706f2543Smrg if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE)) 597706f2543Smrg return BadAccess; 598706f2543Smrg 599706f2543Smrg return Success; 600706f2543Smrg} 601706f2543Smrg 602706f2543Smrg/** 603706f2543Smrg * Allocate a device pair that is initialised as a slave 604706f2543Smrg * device with properties that identify the devices as belonging 605706f2543Smrg * to XTest subsystem. 606706f2543Smrg * This only creates the pair, Activate/Enable Device 607706f2543Smrg * still need to be called. 608706f2543Smrg */ 609706f2543Smrgint AllocXTestDevice (ClientPtr client, char* name, 610706f2543Smrg DeviceIntPtr* ptr, DeviceIntPtr* keybd, 611706f2543Smrg DeviceIntPtr master_ptr, DeviceIntPtr master_keybd) 612706f2543Smrg{ 613706f2543Smrg int retval; 614005535d2Schristos char *xtestname; 615706f2543Smrg char dummy = 1; 616706f2543Smrg 617005535d2Schristos if (asprintf(&xtestname, "%s XTEST", name) == -1) 618005535d2Schristos return BadAlloc; 619706f2543Smrg 620706f2543Smrg retval = AllocDevicePair( client, xtestname, ptr, keybd, CorePointerProc, CoreKeyboardProc, FALSE); 621706f2543Smrg if ( retval == Success ){ 622706f2543Smrg (*ptr)->xtest_master_id = master_ptr->id; 623706f2543Smrg (*keybd)->xtest_master_id = master_keybd->id; 624706f2543Smrg 625706f2543Smrg XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 626706f2543Smrg XA_INTEGER, 8, PropModeReplace, 1, &dummy, 627706f2543Smrg FALSE); 628706f2543Smrg XISetDevicePropertyDeletable(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), FALSE); 629706f2543Smrg XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL); 630706f2543Smrg XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), 631706f2543Smrg XA_INTEGER, 8, PropModeReplace, 1, &dummy, 632706f2543Smrg FALSE); 633706f2543Smrg XISetDevicePropertyDeletable(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE), FALSE); 634706f2543Smrg XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL); 635706f2543Smrg } 636706f2543Smrg 637706f2543Smrg free( xtestname ); 638706f2543Smrg 639706f2543Smrg return retval; 640706f2543Smrg} 641706f2543Smrg 642706f2543Smrg/** 643706f2543Smrg * If master is NULL, return TRUE if the given device is an xtest device or 644706f2543Smrg * FALSE otherwise. 645706f2543Smrg * If master is not NULL, return TRUE if the given device is this master's 646706f2543Smrg * xtest device. 647706f2543Smrg */ 648706f2543SmrgBOOL 649706f2543SmrgIsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master) 650706f2543Smrg{ 651706f2543Smrg if (IsMaster(dev)) 652706f2543Smrg return FALSE; 653706f2543Smrg 654706f2543Smrg /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest 655706f2543Smrg * device */ 656706f2543Smrg if (master) 657706f2543Smrg return dev->xtest_master_id == master->id; 658706f2543Smrg 659706f2543Smrg return dev->xtest_master_id != 0; 660706f2543Smrg} 661706f2543Smrg 662706f2543Smrg/** 663706f2543Smrg * @return The X Test virtual device for the given master. 664706f2543Smrg */ 665706f2543SmrgDeviceIntPtr 666706f2543SmrgGetXTestDevice(DeviceIntPtr master) 667706f2543Smrg{ 668706f2543Smrg DeviceIntPtr it; 669706f2543Smrg 670706f2543Smrg for (it = inputInfo.devices; it; it = it->next) 671706f2543Smrg { 672706f2543Smrg if (IsXTestDevice(it, master)) 673706f2543Smrg return it; 674706f2543Smrg } 675706f2543Smrg 676706f2543Smrg /* This only happens if master is a slave device. don't do that */ 677706f2543Smrg return NULL; 678706f2543Smrg} 679706f2543Smrg 680706f2543Smrgvoid 681706f2543SmrgXTestExtensionInit(INITARGS) 682706f2543Smrg{ 683706f2543Smrg AddExtension(XTestExtensionName, 0, 0, 684706f2543Smrg ProcXTestDispatch, SProcXTestDispatch, 685706f2543Smrg NULL, StandardMinorOpcode); 686706f2543Smrg 687706f2543Smrg xtest_evlist = InitEventList(GetMaximumEventsNum()); 688706f2543Smrg} 689