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