xref: /OK3568_Linux_fs/external/xserver/Xext/xtest.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun    Copyright 1992, 1998  The Open Group
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun    Permission to use, copy, modify, distribute, and sell this software and its
6*4882a593Smuzhiyun    documentation for any purpose is hereby granted without fee, provided that
7*4882a593Smuzhiyun    the above copyright notice appear in all copies and that both that
8*4882a593Smuzhiyun    copyright notice and this permission notice appear in supporting
9*4882a593Smuzhiyun    documentation.
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun    The above copyright notice and this permission notice shall be included
12*4882a593Smuzhiyun    in all copies or substantial portions of the Software.
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15*4882a593Smuzhiyun    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16*4882a593Smuzhiyun    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17*4882a593Smuzhiyun    IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18*4882a593Smuzhiyun    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*4882a593Smuzhiyun    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20*4882a593Smuzhiyun    OTHER DEALINGS IN THE SOFTWARE.
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun    Except as contained in this notice, the name of The Open Group shall
23*4882a593Smuzhiyun    not be used in advertising or otherwise to promote the sale, use or
24*4882a593Smuzhiyun    other dealings in this Software without prior written authorization
25*4882a593Smuzhiyun    from The Open Group.
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun  */
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
30*4882a593Smuzhiyun #include <dix-config.h>
31*4882a593Smuzhiyun #endif
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #include <X11/X.h>
34*4882a593Smuzhiyun #include <X11/Xproto.h>
35*4882a593Smuzhiyun #include <X11/Xatom.h>
36*4882a593Smuzhiyun #include "misc.h"
37*4882a593Smuzhiyun #include "os.h"
38*4882a593Smuzhiyun #include "dixstruct.h"
39*4882a593Smuzhiyun #include "extnsionst.h"
40*4882a593Smuzhiyun #include "windowstr.h"
41*4882a593Smuzhiyun #include "inputstr.h"
42*4882a593Smuzhiyun #include "scrnintstr.h"
43*4882a593Smuzhiyun #include "dixevents.h"
44*4882a593Smuzhiyun #include "sleepuntil.h"
45*4882a593Smuzhiyun #include "mi.h"
46*4882a593Smuzhiyun #include "xkbsrv.h"
47*4882a593Smuzhiyun #include "xkbstr.h"
48*4882a593Smuzhiyun #include <X11/extensions/xtestproto.h>
49*4882a593Smuzhiyun #include <X11/extensions/XI.h>
50*4882a593Smuzhiyun #include <X11/extensions/XIproto.h>
51*4882a593Smuzhiyun #include "exglobals.h"
52*4882a593Smuzhiyun #include "mipointer.h"
53*4882a593Smuzhiyun #include "xserver-properties.h"
54*4882a593Smuzhiyun #include "exevents.h"
55*4882a593Smuzhiyun #include "eventstr.h"
56*4882a593Smuzhiyun #include "inpututils.h"
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #include "extinit.h"
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun /* XTest events are sent during request processing and may be interruped by
61*4882a593Smuzhiyun  * a SIGIO. We need a separate event list to avoid events overwriting each
62*4882a593Smuzhiyun  * other's memory */
63*4882a593Smuzhiyun static InternalEvent *xtest_evlist;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /**
66*4882a593Smuzhiyun  * xtestpointer
67*4882a593Smuzhiyun  * is the virtual pointer for XTest. It is the first slave
68*4882a593Smuzhiyun  * device of the VCP.
69*4882a593Smuzhiyun  * xtestkeyboard
70*4882a593Smuzhiyun  * is the virtual keyboard for XTest. It is the first slave
71*4882a593Smuzhiyun  * device of the VCK
72*4882a593Smuzhiyun  *
73*4882a593Smuzhiyun  * Neither of these devices can be deleted.
74*4882a593Smuzhiyun  */
75*4882a593Smuzhiyun DeviceIntPtr xtestpointer, xtestkeyboard;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun #ifdef PANORAMIX
78*4882a593Smuzhiyun #include "panoramiX.h"
79*4882a593Smuzhiyun #include "panoramiXsrv.h"
80*4882a593Smuzhiyun #endif
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun static int XTestSwapFakeInput(ClientPtr /* client */ ,
83*4882a593Smuzhiyun                               xReq *    /* req */
84*4882a593Smuzhiyun     );
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun static int
ProcXTestGetVersion(ClientPtr client)87*4882a593Smuzhiyun ProcXTestGetVersion(ClientPtr client)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun     xXTestGetVersionReply rep = {
90*4882a593Smuzhiyun         .type = X_Reply,
91*4882a593Smuzhiyun         .sequenceNumber = client->sequence,
92*4882a593Smuzhiyun         .length = 0,
93*4882a593Smuzhiyun         .majorVersion = XTestMajorVersion,
94*4882a593Smuzhiyun         .minorVersion = XTestMinorVersion
95*4882a593Smuzhiyun     };
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xXTestGetVersionReq);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun     if (client->swapped) {
100*4882a593Smuzhiyun         swaps(&rep.sequenceNumber);
101*4882a593Smuzhiyun         swaps(&rep.minorVersion);
102*4882a593Smuzhiyun     }
103*4882a593Smuzhiyun     WriteToClient(client, sizeof(xXTestGetVersionReply), &rep);
104*4882a593Smuzhiyun     return Success;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun static int
ProcXTestCompareCursor(ClientPtr client)108*4882a593Smuzhiyun ProcXTestCompareCursor(ClientPtr client)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun     REQUEST(xXTestCompareCursorReq);
111*4882a593Smuzhiyun     xXTestCompareCursorReply rep;
112*4882a593Smuzhiyun     WindowPtr pWin;
113*4882a593Smuzhiyun     CursorPtr pCursor;
114*4882a593Smuzhiyun     int rc;
115*4882a593Smuzhiyun     DeviceIntPtr ptr = PickPointer(client);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xXTestCompareCursorReq);
118*4882a593Smuzhiyun     rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
119*4882a593Smuzhiyun     if (rc != Success)
120*4882a593Smuzhiyun         return rc;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun     if (!ptr)
123*4882a593Smuzhiyun         return BadAccess;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun     if (stuff->cursor == None)
126*4882a593Smuzhiyun         pCursor = NullCursor;
127*4882a593Smuzhiyun     else if (stuff->cursor == XTestCurrentCursor)
128*4882a593Smuzhiyun         pCursor = GetSpriteCursor(ptr);
129*4882a593Smuzhiyun     else {
130*4882a593Smuzhiyun         rc = dixLookupResourceByType((void **) &pCursor, stuff->cursor,
131*4882a593Smuzhiyun                                      RT_CURSOR, client, DixReadAccess);
132*4882a593Smuzhiyun         if (rc != Success) {
133*4882a593Smuzhiyun             client->errorValue = stuff->cursor;
134*4882a593Smuzhiyun             return rc;
135*4882a593Smuzhiyun         }
136*4882a593Smuzhiyun     }
137*4882a593Smuzhiyun     rep = (xXTestCompareCursorReply) {
138*4882a593Smuzhiyun         .type = X_Reply,
139*4882a593Smuzhiyun         .sequenceNumber = client->sequence,
140*4882a593Smuzhiyun         .length = 0,
141*4882a593Smuzhiyun         .same = (wCursor(pWin) == pCursor)
142*4882a593Smuzhiyun     };
143*4882a593Smuzhiyun     if (client->swapped) {
144*4882a593Smuzhiyun         swaps(&rep.sequenceNumber);
145*4882a593Smuzhiyun     }
146*4882a593Smuzhiyun     WriteToClient(client, sizeof(xXTestCompareCursorReply), &rep);
147*4882a593Smuzhiyun     return Success;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun static int
ProcXTestFakeInput(ClientPtr client)151*4882a593Smuzhiyun ProcXTestFakeInput(ClientPtr client)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun     REQUEST(xXTestFakeInputReq);
154*4882a593Smuzhiyun     int nev, n, type, rc;
155*4882a593Smuzhiyun     xEvent *ev;
156*4882a593Smuzhiyun     DeviceIntPtr dev = NULL;
157*4882a593Smuzhiyun     WindowPtr root;
158*4882a593Smuzhiyun     Bool extension = FALSE;
159*4882a593Smuzhiyun     ValuatorMask mask;
160*4882a593Smuzhiyun     int valuators[MAX_VALUATORS] = { 0 };
161*4882a593Smuzhiyun     int numValuators = 0;
162*4882a593Smuzhiyun     int firstValuator = 0;
163*4882a593Smuzhiyun     int nevents = 0;
164*4882a593Smuzhiyun     int i;
165*4882a593Smuzhiyun     int base = 0;
166*4882a593Smuzhiyun     int flags = 0;
167*4882a593Smuzhiyun     int need_ptr_update = 1;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun     nev = (stuff->length << 2) - sizeof(xReq);
170*4882a593Smuzhiyun     if ((nev % sizeof(xEvent)) || !nev)
171*4882a593Smuzhiyun         return BadLength;
172*4882a593Smuzhiyun     nev /= sizeof(xEvent);
173*4882a593Smuzhiyun     UpdateCurrentTime();
174*4882a593Smuzhiyun     ev = (xEvent *) &((xReq *) stuff)[1];
175*4882a593Smuzhiyun     type = ev->u.u.type & 0177;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun     if (type >= EXTENSION_EVENT_BASE) {
178*4882a593Smuzhiyun         extension = TRUE;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun         /* check device */
181*4882a593Smuzhiyun         rc = dixLookupDevice(&dev, stuff->deviceid & 0177, client,
182*4882a593Smuzhiyun                              DixWriteAccess);
183*4882a593Smuzhiyun         if (rc != Success) {
184*4882a593Smuzhiyun             client->errorValue = stuff->deviceid & 0177;
185*4882a593Smuzhiyun             return rc;
186*4882a593Smuzhiyun         }
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun         /* check type */
189*4882a593Smuzhiyun         type -= DeviceValuator;
190*4882a593Smuzhiyun         switch (type) {
191*4882a593Smuzhiyun         case XI_DeviceKeyPress:
192*4882a593Smuzhiyun         case XI_DeviceKeyRelease:
193*4882a593Smuzhiyun             if (!dev->key) {
194*4882a593Smuzhiyun                 client->errorValue = ev->u.u.type;
195*4882a593Smuzhiyun                 return BadValue;
196*4882a593Smuzhiyun             }
197*4882a593Smuzhiyun             break;
198*4882a593Smuzhiyun         case XI_DeviceButtonPress:
199*4882a593Smuzhiyun         case XI_DeviceButtonRelease:
200*4882a593Smuzhiyun             if (!dev->button) {
201*4882a593Smuzhiyun                 client->errorValue = ev->u.u.type;
202*4882a593Smuzhiyun                 return BadValue;
203*4882a593Smuzhiyun             }
204*4882a593Smuzhiyun             break;
205*4882a593Smuzhiyun         case XI_DeviceMotionNotify:
206*4882a593Smuzhiyun             if (!dev->valuator) {
207*4882a593Smuzhiyun                 client->errorValue = ev->u.u.type;
208*4882a593Smuzhiyun                 return BadValue;
209*4882a593Smuzhiyun             }
210*4882a593Smuzhiyun             break;
211*4882a593Smuzhiyun         case XI_ProximityIn:
212*4882a593Smuzhiyun         case XI_ProximityOut:
213*4882a593Smuzhiyun             if (!dev->proximity) {
214*4882a593Smuzhiyun                 client->errorValue = ev->u.u.type;
215*4882a593Smuzhiyun                 return BadValue;
216*4882a593Smuzhiyun             }
217*4882a593Smuzhiyun             break;
218*4882a593Smuzhiyun         default:
219*4882a593Smuzhiyun             client->errorValue = ev->u.u.type;
220*4882a593Smuzhiyun             return BadValue;
221*4882a593Smuzhiyun         }
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun         /* check validity */
224*4882a593Smuzhiyun         if (nev == 1 && type == XI_DeviceMotionNotify)
225*4882a593Smuzhiyun             return BadLength;   /* DevMotion must be followed by DevValuator */
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun         if (type == XI_DeviceMotionNotify) {
228*4882a593Smuzhiyun             firstValuator = ((deviceValuator *) (ev + 1))->first_valuator;
229*4882a593Smuzhiyun             if (firstValuator > dev->valuator->numAxes) {
230*4882a593Smuzhiyun                 client->errorValue = ev->u.u.type;
231*4882a593Smuzhiyun                 return BadValue;
232*4882a593Smuzhiyun             }
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun             if (ev->u.u.detail == xFalse)
235*4882a593Smuzhiyun                 flags |= POINTER_ABSOLUTE;
236*4882a593Smuzhiyun         }
237*4882a593Smuzhiyun         else {
238*4882a593Smuzhiyun             firstValuator = 0;
239*4882a593Smuzhiyun             flags |= POINTER_ABSOLUTE;
240*4882a593Smuzhiyun         }
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun         if (nev > 1 && !dev->valuator) {
243*4882a593Smuzhiyun             client->errorValue = firstValuator;
244*4882a593Smuzhiyun             return BadValue;
245*4882a593Smuzhiyun         }
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun         /* check validity of valuator events */
248*4882a593Smuzhiyun         base = firstValuator;
249*4882a593Smuzhiyun         for (n = 1; n < nev; n++) {
250*4882a593Smuzhiyun             deviceValuator *dv = (deviceValuator *) (ev + n);
251*4882a593Smuzhiyun             if (dv->type != DeviceValuator) {
252*4882a593Smuzhiyun                 client->errorValue = dv->type;
253*4882a593Smuzhiyun                 return BadValue;
254*4882a593Smuzhiyun             }
255*4882a593Smuzhiyun             if (dv->first_valuator != base) {
256*4882a593Smuzhiyun                 client->errorValue = dv->first_valuator;
257*4882a593Smuzhiyun                 return BadValue;
258*4882a593Smuzhiyun             }
259*4882a593Smuzhiyun             switch (dv->num_valuators) {
260*4882a593Smuzhiyun             case 6:
261*4882a593Smuzhiyun                 valuators[base + 5] = dv->valuator5;
262*4882a593Smuzhiyun             case 5:
263*4882a593Smuzhiyun                 valuators[base + 4] = dv->valuator4;
264*4882a593Smuzhiyun             case 4:
265*4882a593Smuzhiyun                 valuators[base + 3] = dv->valuator3;
266*4882a593Smuzhiyun             case 3:
267*4882a593Smuzhiyun                 valuators[base + 2] = dv->valuator2;
268*4882a593Smuzhiyun             case 2:
269*4882a593Smuzhiyun                 valuators[base + 1] = dv->valuator1;
270*4882a593Smuzhiyun             case 1:
271*4882a593Smuzhiyun                 valuators[base] = dv->valuator0;
272*4882a593Smuzhiyun                 break;
273*4882a593Smuzhiyun             default:
274*4882a593Smuzhiyun                 client->errorValue = dv->num_valuators;
275*4882a593Smuzhiyun                 return BadValue;
276*4882a593Smuzhiyun             }
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun             base += dv->num_valuators;
279*4882a593Smuzhiyun             numValuators += dv->num_valuators;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun             if (firstValuator + numValuators > dev->valuator->numAxes) {
282*4882a593Smuzhiyun                 client->errorValue = dv->num_valuators;
283*4882a593Smuzhiyun                 return BadValue;
284*4882a593Smuzhiyun             }
285*4882a593Smuzhiyun         }
286*4882a593Smuzhiyun         type = type - XI_DeviceKeyPress + KeyPress;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun     }
289*4882a593Smuzhiyun     else {
290*4882a593Smuzhiyun         if (nev != 1)
291*4882a593Smuzhiyun             return BadLength;
292*4882a593Smuzhiyun         switch (type) {
293*4882a593Smuzhiyun         case KeyPress:
294*4882a593Smuzhiyun         case KeyRelease:
295*4882a593Smuzhiyun             dev = PickKeyboard(client);
296*4882a593Smuzhiyun             break;
297*4882a593Smuzhiyun         case ButtonPress:
298*4882a593Smuzhiyun         case ButtonRelease:
299*4882a593Smuzhiyun             dev = PickPointer(client);
300*4882a593Smuzhiyun             break;
301*4882a593Smuzhiyun         case MotionNotify:
302*4882a593Smuzhiyun             dev = PickPointer(client);
303*4882a593Smuzhiyun             valuators[0] = ev->u.keyButtonPointer.rootX;
304*4882a593Smuzhiyun             valuators[1] = ev->u.keyButtonPointer.rootY;
305*4882a593Smuzhiyun             numValuators = 2;
306*4882a593Smuzhiyun             firstValuator = 0;
307*4882a593Smuzhiyun             if (ev->u.u.detail == xFalse)
308*4882a593Smuzhiyun                 flags = POINTER_ABSOLUTE | POINTER_DESKTOP;
309*4882a593Smuzhiyun             break;
310*4882a593Smuzhiyun         default:
311*4882a593Smuzhiyun             client->errorValue = ev->u.u.type;
312*4882a593Smuzhiyun             return BadValue;
313*4882a593Smuzhiyun         }
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun         /* Technically the protocol doesn't allow for BadAccess here but
316*4882a593Smuzhiyun          * this can only happen when all MDs are disabled.  */
317*4882a593Smuzhiyun         if (!dev)
318*4882a593Smuzhiyun             return BadAccess;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun         dev = GetXTestDevice(dev);
321*4882a593Smuzhiyun     }
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun     /* If the event has a time set, wait for it to pass */
325*4882a593Smuzhiyun     if (ev->u.keyButtonPointer.time) {
326*4882a593Smuzhiyun         TimeStamp activateTime;
327*4882a593Smuzhiyun         CARD32 ms;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun         activateTime = currentTime;
330*4882a593Smuzhiyun         ms = activateTime.milliseconds + ev->u.keyButtonPointer.time;
331*4882a593Smuzhiyun         if (ms < activateTime.milliseconds)
332*4882a593Smuzhiyun             activateTime.months++;
333*4882a593Smuzhiyun         activateTime.milliseconds = ms;
334*4882a593Smuzhiyun         ev->u.keyButtonPointer.time = 0;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun         /* see mbuf.c:QueueDisplayRequest (from the deprecated Multibuffer
337*4882a593Smuzhiyun          * extension) for code similar to this */
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun         if (!ClientSleepUntil(client, &activateTime, NULL, NULL)) {
340*4882a593Smuzhiyun             return BadAlloc;
341*4882a593Smuzhiyun         }
342*4882a593Smuzhiyun         /* swap the request back so we can simply re-execute it */
343*4882a593Smuzhiyun         if (client->swapped) {
344*4882a593Smuzhiyun             (void) XTestSwapFakeInput(client, (xReq *) stuff);
345*4882a593Smuzhiyun             swaps(&stuff->length);
346*4882a593Smuzhiyun         }
347*4882a593Smuzhiyun         ResetCurrentRequest(client);
348*4882a593Smuzhiyun         client->sequence--;
349*4882a593Smuzhiyun         return Success;
350*4882a593Smuzhiyun     }
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun     switch (type) {
353*4882a593Smuzhiyun     case KeyPress:
354*4882a593Smuzhiyun     case KeyRelease:
355*4882a593Smuzhiyun         if (!dev->key)
356*4882a593Smuzhiyun             return BadDevice;
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun         if (ev->u.u.detail < dev->key->xkbInfo->desc->min_key_code ||
359*4882a593Smuzhiyun             ev->u.u.detail > dev->key->xkbInfo->desc->max_key_code) {
360*4882a593Smuzhiyun             client->errorValue = ev->u.u.detail;
361*4882a593Smuzhiyun             return BadValue;
362*4882a593Smuzhiyun         }
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun         need_ptr_update = 0;
365*4882a593Smuzhiyun         break;
366*4882a593Smuzhiyun     case MotionNotify:
367*4882a593Smuzhiyun         if (!dev->valuator)
368*4882a593Smuzhiyun             return BadDevice;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun         if (!(extension || ev->u.keyButtonPointer.root == None)) {
371*4882a593Smuzhiyun             rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root,
372*4882a593Smuzhiyun                                  client, DixGetAttrAccess);
373*4882a593Smuzhiyun             if (rc != Success)
374*4882a593Smuzhiyun                 return rc;
375*4882a593Smuzhiyun             if (root->parent) {
376*4882a593Smuzhiyun                 client->errorValue = ev->u.keyButtonPointer.root;
377*4882a593Smuzhiyun                 return BadValue;
378*4882a593Smuzhiyun             }
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun             /* Add the root window's offset to the valuators */
381*4882a593Smuzhiyun             if ((flags & POINTER_ABSOLUTE) && firstValuator <= 1 && numValuators > 0) {
382*4882a593Smuzhiyun                 if (firstValuator == 0)
383*4882a593Smuzhiyun                     valuators[0] += root->drawable.pScreen->x;
384*4882a593Smuzhiyun                 if (firstValuator < 2 && firstValuator + numValuators > 1)
385*4882a593Smuzhiyun                     valuators[1 - firstValuator] += root->drawable.pScreen->y;
386*4882a593Smuzhiyun             }
387*4882a593Smuzhiyun         }
388*4882a593Smuzhiyun         if (ev->u.u.detail != xTrue && ev->u.u.detail != xFalse) {
389*4882a593Smuzhiyun             client->errorValue = ev->u.u.detail;
390*4882a593Smuzhiyun             return BadValue;
391*4882a593Smuzhiyun         }
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun         /* FIXME: Xinerama! */
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun         break;
396*4882a593Smuzhiyun     case ButtonPress:
397*4882a593Smuzhiyun     case ButtonRelease:
398*4882a593Smuzhiyun         if (!dev->button)
399*4882a593Smuzhiyun             return BadDevice;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun         if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons) {
402*4882a593Smuzhiyun             client->errorValue = ev->u.u.detail;
403*4882a593Smuzhiyun             return BadValue;
404*4882a593Smuzhiyun         }
405*4882a593Smuzhiyun         break;
406*4882a593Smuzhiyun     }
407*4882a593Smuzhiyun     if (screenIsSaved == SCREEN_SAVER_ON)
408*4882a593Smuzhiyun         dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun     switch (type) {
411*4882a593Smuzhiyun     case MotionNotify:
412*4882a593Smuzhiyun         valuator_mask_set_range(&mask, firstValuator, numValuators, valuators);
413*4882a593Smuzhiyun         nevents = GetPointerEvents(xtest_evlist, dev, type, 0, flags, &mask);
414*4882a593Smuzhiyun         break;
415*4882a593Smuzhiyun     case ButtonPress:
416*4882a593Smuzhiyun     case ButtonRelease:
417*4882a593Smuzhiyun         valuator_mask_set_range(&mask, firstValuator, numValuators, valuators);
418*4882a593Smuzhiyun         nevents = GetPointerEvents(xtest_evlist, dev, type, ev->u.u.detail,
419*4882a593Smuzhiyun                                    flags, &mask);
420*4882a593Smuzhiyun         break;
421*4882a593Smuzhiyun     case KeyPress:
422*4882a593Smuzhiyun     case KeyRelease:
423*4882a593Smuzhiyun         nevents =
424*4882a593Smuzhiyun             GetKeyboardEvents(xtest_evlist, dev, type, ev->u.u.detail);
425*4882a593Smuzhiyun         break;
426*4882a593Smuzhiyun     }
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun     for (i = 0; i < nevents; i++)
429*4882a593Smuzhiyun         mieqProcessDeviceEvent(dev, &xtest_evlist[i], miPointerGetScreen(inputInfo.pointer));
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun     if (need_ptr_update)
432*4882a593Smuzhiyun         miPointerUpdateSprite(dev);
433*4882a593Smuzhiyun     return Success;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun static int
ProcXTestGrabControl(ClientPtr client)437*4882a593Smuzhiyun ProcXTestGrabControl(ClientPtr client)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun     REQUEST(xXTestGrabControlReq);
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xXTestGrabControlReq);
442*4882a593Smuzhiyun     if ((stuff->impervious != xTrue) && (stuff->impervious != xFalse)) {
443*4882a593Smuzhiyun         client->errorValue = stuff->impervious;
444*4882a593Smuzhiyun         return BadValue;
445*4882a593Smuzhiyun     }
446*4882a593Smuzhiyun     if (stuff->impervious)
447*4882a593Smuzhiyun         MakeClientGrabImpervious(client);
448*4882a593Smuzhiyun     else
449*4882a593Smuzhiyun         MakeClientGrabPervious(client);
450*4882a593Smuzhiyun     return Success;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun static int
ProcXTestDispatch(ClientPtr client)454*4882a593Smuzhiyun ProcXTestDispatch(ClientPtr client)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun     REQUEST(xReq);
457*4882a593Smuzhiyun     switch (stuff->data) {
458*4882a593Smuzhiyun     case X_XTestGetVersion:
459*4882a593Smuzhiyun         return ProcXTestGetVersion(client);
460*4882a593Smuzhiyun     case X_XTestCompareCursor:
461*4882a593Smuzhiyun         return ProcXTestCompareCursor(client);
462*4882a593Smuzhiyun     case X_XTestFakeInput:
463*4882a593Smuzhiyun         return ProcXTestFakeInput(client);
464*4882a593Smuzhiyun     case X_XTestGrabControl:
465*4882a593Smuzhiyun         return ProcXTestGrabControl(client);
466*4882a593Smuzhiyun     default:
467*4882a593Smuzhiyun         return BadRequest;
468*4882a593Smuzhiyun     }
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun static int _X_COLD
SProcXTestGetVersion(ClientPtr client)472*4882a593Smuzhiyun SProcXTestGetVersion(ClientPtr client)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun     REQUEST(xXTestGetVersionReq);
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun     swaps(&stuff->length);
477*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xXTestGetVersionReq);
478*4882a593Smuzhiyun     swaps(&stuff->minorVersion);
479*4882a593Smuzhiyun     return ProcXTestGetVersion(client);
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun static int _X_COLD
SProcXTestCompareCursor(ClientPtr client)483*4882a593Smuzhiyun SProcXTestCompareCursor(ClientPtr client)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun     REQUEST(xXTestCompareCursorReq);
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun     swaps(&stuff->length);
488*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xXTestCompareCursorReq);
489*4882a593Smuzhiyun     swapl(&stuff->window);
490*4882a593Smuzhiyun     swapl(&stuff->cursor);
491*4882a593Smuzhiyun     return ProcXTestCompareCursor(client);
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun static int _X_COLD
XTestSwapFakeInput(ClientPtr client,xReq * req)495*4882a593Smuzhiyun XTestSwapFakeInput(ClientPtr client, xReq * req)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun     int nev;
498*4882a593Smuzhiyun     xEvent *ev;
499*4882a593Smuzhiyun     xEvent sev;
500*4882a593Smuzhiyun     EventSwapPtr proc;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun     nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent);
503*4882a593Smuzhiyun     for (ev = (xEvent *) &req[1]; --nev >= 0; ev++) {
504*4882a593Smuzhiyun         /* Swap event */
505*4882a593Smuzhiyun         proc = EventSwapVector[ev->u.u.type & 0177];
506*4882a593Smuzhiyun         /* no swapping proc; invalid event type? */
507*4882a593Smuzhiyun         if (!proc || proc == NotImplemented) {
508*4882a593Smuzhiyun             client->errorValue = ev->u.u.type;
509*4882a593Smuzhiyun             return BadValue;
510*4882a593Smuzhiyun         }
511*4882a593Smuzhiyun         (*proc) (ev, &sev);
512*4882a593Smuzhiyun         *ev = sev;
513*4882a593Smuzhiyun     }
514*4882a593Smuzhiyun     return Success;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun static int _X_COLD
SProcXTestFakeInput(ClientPtr client)518*4882a593Smuzhiyun SProcXTestFakeInput(ClientPtr client)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun     int n;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun     REQUEST(xReq);
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun     swaps(&stuff->length);
525*4882a593Smuzhiyun     n = XTestSwapFakeInput(client, stuff);
526*4882a593Smuzhiyun     if (n != Success)
527*4882a593Smuzhiyun         return n;
528*4882a593Smuzhiyun     return ProcXTestFakeInput(client);
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun static int _X_COLD
SProcXTestGrabControl(ClientPtr client)532*4882a593Smuzhiyun SProcXTestGrabControl(ClientPtr client)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun     REQUEST(xXTestGrabControlReq);
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun     swaps(&stuff->length);
537*4882a593Smuzhiyun     REQUEST_SIZE_MATCH(xXTestGrabControlReq);
538*4882a593Smuzhiyun     return ProcXTestGrabControl(client);
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun static int _X_COLD
SProcXTestDispatch(ClientPtr client)542*4882a593Smuzhiyun SProcXTestDispatch(ClientPtr client)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun     REQUEST(xReq);
545*4882a593Smuzhiyun     switch (stuff->data) {
546*4882a593Smuzhiyun     case X_XTestGetVersion:
547*4882a593Smuzhiyun         return SProcXTestGetVersion(client);
548*4882a593Smuzhiyun     case X_XTestCompareCursor:
549*4882a593Smuzhiyun         return SProcXTestCompareCursor(client);
550*4882a593Smuzhiyun     case X_XTestFakeInput:
551*4882a593Smuzhiyun         return SProcXTestFakeInput(client);
552*4882a593Smuzhiyun     case X_XTestGrabControl:
553*4882a593Smuzhiyun         return SProcXTestGrabControl(client);
554*4882a593Smuzhiyun     default:
555*4882a593Smuzhiyun         return BadRequest;
556*4882a593Smuzhiyun     }
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun /**
560*4882a593Smuzhiyun  * Allocate an virtual slave device for xtest events, this
561*4882a593Smuzhiyun  * is a slave device to inputInfo master devices
562*4882a593Smuzhiyun  */
563*4882a593Smuzhiyun void
InitXTestDevices(void)564*4882a593Smuzhiyun InitXTestDevices(void)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun     if (AllocXTestDevice(serverClient, "Virtual core",
567*4882a593Smuzhiyun                          &xtestpointer, &xtestkeyboard,
568*4882a593Smuzhiyun                          inputInfo.pointer, inputInfo.keyboard) != Success)
569*4882a593Smuzhiyun          FatalError("Failed to allocate XTest devices");
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun     if (ActivateDevice(xtestpointer, TRUE) != Success ||
572*4882a593Smuzhiyun         ActivateDevice(xtestkeyboard, TRUE) != Success)
573*4882a593Smuzhiyun         FatalError("Failed to activate XTest core devices.");
574*4882a593Smuzhiyun     if (!EnableDevice(xtestpointer, TRUE) || !EnableDevice(xtestkeyboard, TRUE))
575*4882a593Smuzhiyun         FatalError("Failed to enable XTest core devices.");
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun     AttachDevice(NULL, xtestpointer, inputInfo.pointer);
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun     AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard);
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun /**
583*4882a593Smuzhiyun  * Don't allow changing the XTest property.
584*4882a593Smuzhiyun  */
585*4882a593Smuzhiyun static int
DeviceSetXTestProperty(DeviceIntPtr dev,Atom property,XIPropertyValuePtr prop,BOOL checkonly)586*4882a593Smuzhiyun DeviceSetXTestProperty(DeviceIntPtr dev, Atom property,
587*4882a593Smuzhiyun                        XIPropertyValuePtr prop, BOOL checkonly)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun     if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE))
590*4882a593Smuzhiyun         return BadAccess;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun     return Success;
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun /**
596*4882a593Smuzhiyun  * Allocate a device pair that is initialised as a slave
597*4882a593Smuzhiyun  * device with properties that identify the devices as belonging
598*4882a593Smuzhiyun  * to XTest subsystem.
599*4882a593Smuzhiyun  * This only creates the pair, Activate/Enable Device
600*4882a593Smuzhiyun  * still need to be called.
601*4882a593Smuzhiyun  */
602*4882a593Smuzhiyun int
AllocXTestDevice(ClientPtr client,const char * name,DeviceIntPtr * ptr,DeviceIntPtr * keybd,DeviceIntPtr master_ptr,DeviceIntPtr master_keybd)603*4882a593Smuzhiyun AllocXTestDevice(ClientPtr client, const char *name,
604*4882a593Smuzhiyun                  DeviceIntPtr *ptr, DeviceIntPtr *keybd,
605*4882a593Smuzhiyun                  DeviceIntPtr master_ptr, DeviceIntPtr master_keybd)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun     int retval;
608*4882a593Smuzhiyun     char *xtestname;
609*4882a593Smuzhiyun     char dummy = 1;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun     if (asprintf(&xtestname, "%s XTEST", name) == -1)
612*4882a593Smuzhiyun         return BadAlloc;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun     retval =
615*4882a593Smuzhiyun         AllocDevicePair(client, xtestname, ptr, keybd, CorePointerProc,
616*4882a593Smuzhiyun                         CoreKeyboardProc, FALSE);
617*4882a593Smuzhiyun     if (retval == Success) {
618*4882a593Smuzhiyun         (*ptr)->xtest_master_id = master_ptr->id;
619*4882a593Smuzhiyun         (*keybd)->xtest_master_id = master_keybd->id;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun         XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
622*4882a593Smuzhiyun                                XA_INTEGER, 8, PropModeReplace, 1, &dummy,
623*4882a593Smuzhiyun                                FALSE);
624*4882a593Smuzhiyun         XISetDevicePropertyDeletable(*ptr,
625*4882a593Smuzhiyun                                      XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
626*4882a593Smuzhiyun                                      FALSE);
627*4882a593Smuzhiyun         XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL);
628*4882a593Smuzhiyun         XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
629*4882a593Smuzhiyun                                XA_INTEGER, 8, PropModeReplace, 1, &dummy,
630*4882a593Smuzhiyun                                FALSE);
631*4882a593Smuzhiyun         XISetDevicePropertyDeletable(*keybd,
632*4882a593Smuzhiyun                                      XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
633*4882a593Smuzhiyun                                      FALSE);
634*4882a593Smuzhiyun         XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL);
635*4882a593Smuzhiyun     }
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun     free(xtestname);
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun     return retval;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun /**
643*4882a593Smuzhiyun  * If master is NULL, return TRUE if the given device is an xtest device or
644*4882a593Smuzhiyun  * FALSE otherwise.
645*4882a593Smuzhiyun  * If master is not NULL, return TRUE if the given device is this master's
646*4882a593Smuzhiyun  * xtest device.
647*4882a593Smuzhiyun  */
648*4882a593Smuzhiyun BOOL
IsXTestDevice(DeviceIntPtr dev,DeviceIntPtr master)649*4882a593Smuzhiyun IsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun     if (IsMaster(dev))
652*4882a593Smuzhiyun         return FALSE;
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun     /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest
655*4882a593Smuzhiyun      * device */
656*4882a593Smuzhiyun     if (master)
657*4882a593Smuzhiyun         return dev->xtest_master_id == master->id;
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun     return dev->xtest_master_id != 0;
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun /**
663*4882a593Smuzhiyun  * @return The X Test virtual device for the given master.
664*4882a593Smuzhiyun  */
665*4882a593Smuzhiyun DeviceIntPtr
GetXTestDevice(DeviceIntPtr master)666*4882a593Smuzhiyun GetXTestDevice(DeviceIntPtr master)
667*4882a593Smuzhiyun {
668*4882a593Smuzhiyun     DeviceIntPtr it;
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun     for (it = inputInfo.devices; it; it = it->next) {
671*4882a593Smuzhiyun         if (IsXTestDevice(it, master))
672*4882a593Smuzhiyun             return it;
673*4882a593Smuzhiyun     }
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun     /* This only happens if master is a slave device. don't do that */
676*4882a593Smuzhiyun     return NULL;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun static void
XTestExtensionTearDown(ExtensionEntry * e)680*4882a593Smuzhiyun XTestExtensionTearDown(ExtensionEntry * e)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun     FreeEventList(xtest_evlist, GetMaximumEventsNum());
683*4882a593Smuzhiyun     xtest_evlist = NULL;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun void
XTestExtensionInit(void)687*4882a593Smuzhiyun XTestExtensionInit(void)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun     AddExtension(XTestExtensionName, 0, 0,
690*4882a593Smuzhiyun                  ProcXTestDispatch, SProcXTestDispatch,
691*4882a593Smuzhiyun                  XTestExtensionTearDown, StandardMinorOpcode);
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun     xtest_evlist = InitEventList(GetMaximumEventsNum());
694*4882a593Smuzhiyun }
695