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