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
605a112b11Smrg/* XTest events are sent during request processing and may be interrupted by
614202a189Smrg * a SIGIO. We need a separate event list to avoid events overwriting each
625a112b11Smrg * other's memory.
635a112b11Smrg */
64f7df2e56Smrgstatic InternalEvent *xtest_evlist;
654202a189Smrg
664202a189Smrg/**
674202a189Smrg * xtestpointer
684202a189Smrg * is the virtual pointer for XTest. It is the first slave
694202a189Smrg * device of the VCP.
704202a189Smrg * xtestkeyboard
714202a189Smrg * is the virtual keyboard for XTest. It is the first slave
724202a189Smrg * device of the VCK
734202a189Smrg *
744202a189Smrg * Neither of these devices can be deleted.
754202a189Smrg */
764202a189SmrgDeviceIntPtr xtestpointer, xtestkeyboard;
7705b261ecSmrg
7805b261ecSmrg#ifdef PANORAMIX
7905b261ecSmrg#include "panoramiX.h"
8005b261ecSmrg#include "panoramiXsrv.h"
8105b261ecSmrg#endif
8205b261ecSmrg
83f7df2e56Smrgstatic int XTestSwapFakeInput(ClientPtr /* client */ ,
84f7df2e56Smrg                              xReq *    /* req */
85f7df2e56Smrg    );
8605b261ecSmrg
8705b261ecSmrgstatic int
884202a189SmrgProcXTestGetVersion(ClientPtr client)
8905b261ecSmrg{
90f7df2e56Smrg    xXTestGetVersionReply rep = {
91f7df2e56Smrg        .type = X_Reply,
92f7df2e56Smrg        .sequenceNumber = client->sequence,
93f7df2e56Smrg        .length = 0,
94f7df2e56Smrg        .majorVersion = XTestMajorVersion,
95f7df2e56Smrg        .minorVersion = XTestMinorVersion
96f7df2e56Smrg    };
9705b261ecSmrg
9805b261ecSmrg    REQUEST_SIZE_MATCH(xXTestGetVersionReq);
99f7df2e56Smrg
10005b261ecSmrg    if (client->swapped) {
101f7df2e56Smrg        swaps(&rep.sequenceNumber);
102f7df2e56Smrg        swaps(&rep.minorVersion);
10305b261ecSmrg    }
104f7df2e56Smrg    WriteToClient(client, sizeof(xXTestGetVersionReply), &rep);
1054202a189Smrg    return Success;
10605b261ecSmrg}
10705b261ecSmrg
10805b261ecSmrgstatic int
1094202a189SmrgProcXTestCompareCursor(ClientPtr client)
11005b261ecSmrg{
11105b261ecSmrg    REQUEST(xXTestCompareCursorReq);
11205b261ecSmrg    xXTestCompareCursorReply rep;
11305b261ecSmrg    WindowPtr pWin;
11405b261ecSmrg    CursorPtr pCursor;
115f7df2e56Smrg    int rc;
1164642e01fSmrg    DeviceIntPtr ptr = PickPointer(client);
11705b261ecSmrg
11805b261ecSmrg    REQUEST_SIZE_MATCH(xXTestCompareCursorReq);
1194642e01fSmrg    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
12005b261ecSmrg    if (rc != Success)
12105b261ecSmrg        return rc;
122f7df2e56Smrg
123f7df2e56Smrg    if (!ptr)
124f7df2e56Smrg        return BadAccess;
125f7df2e56Smrg
12605b261ecSmrg    if (stuff->cursor == None)
1274642e01fSmrg        pCursor = NullCursor;
12805b261ecSmrg    else if (stuff->cursor == XTestCurrentCursor)
1294642e01fSmrg        pCursor = GetSpriteCursor(ptr);
13005b261ecSmrg    else {
131f7df2e56Smrg        rc = dixLookupResourceByType((void **) &pCursor, stuff->cursor,
132f7df2e56Smrg                                     RT_CURSOR, client, DixReadAccess);
133f7df2e56Smrg        if (rc != Success) {
1344642e01fSmrg            client->errorValue = stuff->cursor;
1354202a189Smrg            return rc;
1364642e01fSmrg        }
13705b261ecSmrg    }
138f7df2e56Smrg    rep = (xXTestCompareCursorReply) {
139f7df2e56Smrg        .type = X_Reply,
140f7df2e56Smrg        .sequenceNumber = client->sequence,
141f7df2e56Smrg        .length = 0,
142f7df2e56Smrg        .same = (wCursor(pWin) == pCursor)
143f7df2e56Smrg    };
14405b261ecSmrg    if (client->swapped) {
145f7df2e56Smrg        swaps(&rep.sequenceNumber);
14605b261ecSmrg    }
147f7df2e56Smrg    WriteToClient(client, sizeof(xXTestCompareCursorReply), &rep);
1484202a189Smrg    return Success;
14905b261ecSmrg}
15005b261ecSmrg
15105b261ecSmrgstatic int
1524202a189SmrgProcXTestFakeInput(ClientPtr client)
15305b261ecSmrg{
15405b261ecSmrg    REQUEST(xXTestFakeInputReq);
15505b261ecSmrg    int nev, n, type, rc;
15605b261ecSmrg    xEvent *ev;
15705b261ecSmrg    DeviceIntPtr dev = NULL;
15805b261ecSmrg    WindowPtr root;
15905b261ecSmrg    Bool extension = FALSE;
16065b04b38Smrg    ValuatorMask mask;
161f7df2e56Smrg    int valuators[MAX_VALUATORS] = { 0 };
1624642e01fSmrg    int numValuators = 0;
1634642e01fSmrg    int firstValuator = 0;
164b86d567bSmrg    int nevents = 0;
1654642e01fSmrg    int i;
1664642e01fSmrg    int base = 0;
1674642e01fSmrg    int flags = 0;
1684202a189Smrg    int need_ptr_update = 1;
16905b261ecSmrg
17005b261ecSmrg    nev = (stuff->length << 2) - sizeof(xReq);
17105b261ecSmrg    if ((nev % sizeof(xEvent)) || !nev)
1724642e01fSmrg        return BadLength;
17305b261ecSmrg    nev /= sizeof(xEvent);
17405b261ecSmrg    UpdateCurrentTime();
175f7df2e56Smrg    ev = (xEvent *) &((xReq *) stuff)[1];
17605b261ecSmrg    type = ev->u.u.type & 0177;
1774642e01fSmrg
178f7df2e56Smrg    if (type >= EXTENSION_EVENT_BASE) {
1794642e01fSmrg        extension = TRUE;
1804642e01fSmrg
1814642e01fSmrg        /* check device */
1824642e01fSmrg        rc = dixLookupDevice(&dev, stuff->deviceid & 0177, client,
183f7df2e56Smrg                             DixWriteAccess);
184f7df2e56Smrg        if (rc != Success) {
1854642e01fSmrg            client->errorValue = stuff->deviceid & 0177;
1864642e01fSmrg            return rc;
1874642e01fSmrg        }
1884642e01fSmrg
1894642e01fSmrg        /* check type */
1904642e01fSmrg        type -= DeviceValuator;
1914642e01fSmrg        switch (type) {
192f7df2e56Smrg        case XI_DeviceKeyPress:
193f7df2e56Smrg        case XI_DeviceKeyRelease:
194f7df2e56Smrg            if (!dev->key) {
1954642e01fSmrg                client->errorValue = ev->u.u.type;
1964642e01fSmrg                return BadValue;
197f7df2e56Smrg            }
198f7df2e56Smrg            break;
199f7df2e56Smrg        case XI_DeviceButtonPress:
200f7df2e56Smrg        case XI_DeviceButtonRelease:
201f7df2e56Smrg            if (!dev->button) {
202f7df2e56Smrg                client->errorValue = ev->u.u.type;
203f7df2e56Smrg                return BadValue;
204f7df2e56Smrg            }
205f7df2e56Smrg            break;
206f7df2e56Smrg        case XI_DeviceMotionNotify:
207f7df2e56Smrg            if (!dev->valuator) {
208f7df2e56Smrg                client->errorValue = ev->u.u.type;
209f7df2e56Smrg                return BadValue;
210f7df2e56Smrg            }
211f7df2e56Smrg            break;
212f7df2e56Smrg        case XI_ProximityIn:
213f7df2e56Smrg        case XI_ProximityOut:
214f7df2e56Smrg            if (!dev->proximity) {
215f7df2e56Smrg                client->errorValue = ev->u.u.type;
216f7df2e56Smrg                return BadValue;
217f7df2e56Smrg            }
218f7df2e56Smrg            break;
219f7df2e56Smrg        default:
220f7df2e56Smrg            client->errorValue = ev->u.u.type;
221f7df2e56Smrg            return BadValue;
2224642e01fSmrg        }
2234642e01fSmrg
2244642e01fSmrg        /* check validity */
2254642e01fSmrg        if (nev == 1 && type == XI_DeviceMotionNotify)
226f7df2e56Smrg            return BadLength;   /* DevMotion must be followed by DevValuator */
2274642e01fSmrg
228f7df2e56Smrg        if (type == XI_DeviceMotionNotify) {
229f7df2e56Smrg            firstValuator = ((deviceValuator *) (ev + 1))->first_valuator;
230f7df2e56Smrg            if (firstValuator > dev->valuator->numAxes) {
2314642e01fSmrg                client->errorValue = ev->u.u.type;
2324642e01fSmrg                return BadValue;
2334642e01fSmrg            }
2344642e01fSmrg
2354642e01fSmrg            if (ev->u.u.detail == xFalse)
2364642e01fSmrg                flags |= POINTER_ABSOLUTE;
237f7df2e56Smrg        }
238f7df2e56Smrg        else {
2394642e01fSmrg            firstValuator = 0;
2404642e01fSmrg            flags |= POINTER_ABSOLUTE;
2414642e01fSmrg        }
2424642e01fSmrg
243f7df2e56Smrg        if (nev > 1 && !dev->valuator) {
244f7df2e56Smrg            client->errorValue = firstValuator;
2454642e01fSmrg            return BadValue;
2464642e01fSmrg        }
2474642e01fSmrg
2484642e01fSmrg        /* check validity of valuator events */
2494642e01fSmrg        base = firstValuator;
250f7df2e56Smrg        for (n = 1; n < nev; n++) {
251f7df2e56Smrg            deviceValuator *dv = (deviceValuator *) (ev + n);
252f7df2e56Smrg            if (dv->type != DeviceValuator) {
2534642e01fSmrg                client->errorValue = dv->type;
2544642e01fSmrg                return BadValue;
2554642e01fSmrg            }
256f7df2e56Smrg            if (dv->first_valuator != base) {
2574642e01fSmrg                client->errorValue = dv->first_valuator;
2584642e01fSmrg                return BadValue;
2594642e01fSmrg            }
260f7df2e56Smrg            switch (dv->num_valuators) {
261f7df2e56Smrg            case 6:
262f7df2e56Smrg                valuators[base + 5] = dv->valuator5;
263f7df2e56Smrg            case 5:
264f7df2e56Smrg                valuators[base + 4] = dv->valuator4;
265f7df2e56Smrg            case 4:
266f7df2e56Smrg                valuators[base + 3] = dv->valuator3;
267f7df2e56Smrg            case 3:
268f7df2e56Smrg                valuators[base + 2] = dv->valuator2;
269f7df2e56Smrg            case 2:
270f7df2e56Smrg                valuators[base + 1] = dv->valuator1;
271f7df2e56Smrg            case 1:
272f7df2e56Smrg                valuators[base] = dv->valuator0;
273f7df2e56Smrg                break;
274f7df2e56Smrg            default:
275f7df2e56Smrg                client->errorValue = dv->num_valuators;
276f7df2e56Smrg                return BadValue;
2774642e01fSmrg            }
2784642e01fSmrg
2794642e01fSmrg            base += dv->num_valuators;
2804642e01fSmrg            numValuators += dv->num_valuators;
2814642e01fSmrg
282f7df2e56Smrg            if (firstValuator + numValuators > dev->valuator->numAxes) {
2834642e01fSmrg                client->errorValue = dv->num_valuators;
2844642e01fSmrg                return BadValue;
2854642e01fSmrg            }
2864642e01fSmrg        }
2874642e01fSmrg        type = type - XI_DeviceKeyPress + KeyPress;
2884642e01fSmrg
289f7df2e56Smrg    }
290f7df2e56Smrg    else {
2914642e01fSmrg        if (nev != 1)
2924642e01fSmrg            return BadLength;
293f7df2e56Smrg        switch (type) {
294f7df2e56Smrg        case KeyPress:
295f7df2e56Smrg        case KeyRelease:
296f7df2e56Smrg            dev = PickKeyboard(client);
297f7df2e56Smrg            break;
298f7df2e56Smrg        case ButtonPress:
299f7df2e56Smrg        case ButtonRelease:
300f7df2e56Smrg            dev = PickPointer(client);
301f7df2e56Smrg            break;
302f7df2e56Smrg        case MotionNotify:
303f7df2e56Smrg            dev = PickPointer(client);
304f7df2e56Smrg            valuators[0] = ev->u.keyButtonPointer.rootX;
305f7df2e56Smrg            valuators[1] = ev->u.keyButtonPointer.rootY;
306f7df2e56Smrg            numValuators = 2;
307f7df2e56Smrg            firstValuator = 0;
308f7df2e56Smrg            if (ev->u.u.detail == xFalse)
309f7df2e56Smrg                flags = POINTER_ABSOLUTE | POINTER_DESKTOP;
310f7df2e56Smrg            break;
311f7df2e56Smrg        default:
312f7df2e56Smrg            client->errorValue = ev->u.u.type;
313f7df2e56Smrg            return BadValue;
3144642e01fSmrg        }
3154642e01fSmrg
316f7df2e56Smrg        /* Technically the protocol doesn't allow for BadAccess here but
317f7df2e56Smrg         * this can only happen when all MDs are disabled.  */
318f7df2e56Smrg        if (!dev)
319f7df2e56Smrg            return BadAccess;
320f7df2e56Smrg
3214202a189Smrg        dev = GetXTestDevice(dev);
32205b261ecSmrg    }
3234642e01fSmrg
324f7df2e56Smrg
3254642e01fSmrg    /* If the event has a time set, wait for it to pass */
326f7df2e56Smrg    if (ev->u.keyButtonPointer.time) {
3274642e01fSmrg        TimeStamp activateTime;
3284642e01fSmrg        CARD32 ms;
3294642e01fSmrg
3304642e01fSmrg        activateTime = currentTime;
3314642e01fSmrg        ms = activateTime.milliseconds + ev->u.keyButtonPointer.time;
3324642e01fSmrg        if (ms < activateTime.milliseconds)
3334642e01fSmrg            activateTime.months++;
3344642e01fSmrg        activateTime.milliseconds = ms;
3354642e01fSmrg        ev->u.keyButtonPointer.time = 0;
3364642e01fSmrg
3374202a189Smrg        /* see mbuf.c:QueueDisplayRequest (from the deprecated Multibuffer
3384202a189Smrg         * extension) for code similar to this */
3394642e01fSmrg
340f7df2e56Smrg        if (!ClientSleepUntil(client, &activateTime, NULL, NULL)) {
3414642e01fSmrg            return BadAlloc;
3424642e01fSmrg        }
3434642e01fSmrg        /* swap the request back so we can simply re-execute it */
344f7df2e56Smrg        if (client->swapped) {
345f7df2e56Smrg            (void) XTestSwapFakeInput(client, (xReq *) stuff);
346f7df2e56Smrg            swaps(&stuff->length);
3474642e01fSmrg        }
348f7df2e56Smrg        ResetCurrentRequest(client);
3494642e01fSmrg        client->sequence--;
3504642e01fSmrg        return Success;
35105b261ecSmrg    }
3524642e01fSmrg
353f7df2e56Smrg    switch (type) {
354f7df2e56Smrg    case KeyPress:
355f7df2e56Smrg    case KeyRelease:
356f7df2e56Smrg        if (!dev->key)
357f7df2e56Smrg            return BadDevice;
3584202a189Smrg
359f7df2e56Smrg        if (ev->u.u.detail < dev->key->xkbInfo->desc->min_key_code ||
360f7df2e56Smrg            ev->u.u.detail > dev->key->xkbInfo->desc->max_key_code) {
361f7df2e56Smrg            client->errorValue = ev->u.u.detail;
362f7df2e56Smrg            return BadValue;
363f7df2e56Smrg        }
364f7df2e56Smrg
365f7df2e56Smrg        need_ptr_update = 0;
366f7df2e56Smrg        break;
367f7df2e56Smrg    case MotionNotify:
368f7df2e56Smrg        if (!dev->valuator)
369f7df2e56Smrg            return BadDevice;
370f7df2e56Smrg
371f7df2e56Smrg        if (!(extension || ev->u.keyButtonPointer.root == None)) {
372f7df2e56Smrg            rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root,
373f7df2e56Smrg                                 client, DixGetAttrAccess);
374f7df2e56Smrg            if (rc != Success)
375f7df2e56Smrg                return rc;
376f7df2e56Smrg            if (root->parent) {
377f7df2e56Smrg                client->errorValue = ev->u.keyButtonPointer.root;
3784642e01fSmrg                return BadValue;
3794642e01fSmrg            }
3804202a189Smrg
381f7df2e56Smrg            /* Add the root window's offset to the valuators */
382f7df2e56Smrg            if ((flags & POINTER_ABSOLUTE) && firstValuator <= 1 && numValuators > 0) {
383f7df2e56Smrg                if (firstValuator == 0)
384f7df2e56Smrg                    valuators[0] += root->drawable.pScreen->x;
385f7df2e56Smrg                if (firstValuator < 2 && firstValuator + numValuators > 1)
386f7df2e56Smrg                    valuators[1 - firstValuator] += root->drawable.pScreen->y;
3874642e01fSmrg            }
388f7df2e56Smrg        }
389f7df2e56Smrg        if (ev->u.u.detail != xTrue && ev->u.u.detail != xFalse) {
390f7df2e56Smrg            client->errorValue = ev->u.u.detail;
391f7df2e56Smrg            return BadValue;
392f7df2e56Smrg        }
3934642e01fSmrg
394f7df2e56Smrg        /* FIXME: Xinerama! */
3954642e01fSmrg
396f7df2e56Smrg        break;
397f7df2e56Smrg    case ButtonPress:
398f7df2e56Smrg    case ButtonRelease:
399f7df2e56Smrg        if (!dev->button)
400f7df2e56Smrg            return BadDevice;
4014202a189Smrg
402f7df2e56Smrg        if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons) {
403f7df2e56Smrg            client->errorValue = ev->u.u.detail;
404f7df2e56Smrg            return BadValue;
405f7df2e56Smrg        }
406f7df2e56Smrg        break;
40705b261ecSmrg    }
40805b261ecSmrg    if (screenIsSaved == SCREEN_SAVER_ON)
4094642e01fSmrg        dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
4104642e01fSmrg
411f7df2e56Smrg    switch (type) {
412f7df2e56Smrg    case MotionNotify:
413f7df2e56Smrg        valuator_mask_set_range(&mask, firstValuator, numValuators, valuators);
414f7df2e56Smrg        nevents = GetPointerEvents(xtest_evlist, dev, type, 0, flags, &mask);
415f7df2e56Smrg        break;
416f7df2e56Smrg    case ButtonPress:
417f7df2e56Smrg    case ButtonRelease:
418f7df2e56Smrg        valuator_mask_set_range(&mask, firstValuator, numValuators, valuators);
419f7df2e56Smrg        nevents = GetPointerEvents(xtest_evlist, dev, type, ev->u.u.detail,
420f7df2e56Smrg                                   flags, &mask);
421f7df2e56Smrg        break;
422f7df2e56Smrg    case KeyPress:
423f7df2e56Smrg    case KeyRelease:
424f7df2e56Smrg        nevents =
425f7df2e56Smrg            GetKeyboardEvents(xtest_evlist, dev, type, ev->u.u.detail);
426f7df2e56Smrg        break;
4274642e01fSmrg    }
4284642e01fSmrg
4294642e01fSmrg    for (i = 0; i < nevents; i++)
430f7df2e56Smrg        mieqProcessDeviceEvent(dev, &xtest_evlist[i], miPointerGetScreen(inputInfo.pointer));
4314642e01fSmrg
4324202a189Smrg    if (need_ptr_update)
4334202a189Smrg        miPointerUpdateSprite(dev);
4344202a189Smrg    return Success;
43505b261ecSmrg}
43605b261ecSmrg
43705b261ecSmrgstatic int
4384202a189SmrgProcXTestGrabControl(ClientPtr client)
43905b261ecSmrg{
44005b261ecSmrg    REQUEST(xXTestGrabControlReq);
44105b261ecSmrg
44205b261ecSmrg    REQUEST_SIZE_MATCH(xXTestGrabControlReq);
443f7df2e56Smrg    if ((stuff->impervious != xTrue) && (stuff->impervious != xFalse)) {
4444642e01fSmrg        client->errorValue = stuff->impervious;
4454202a189Smrg        return BadValue;
44605b261ecSmrg    }
44705b261ecSmrg    if (stuff->impervious)
4484642e01fSmrg        MakeClientGrabImpervious(client);
44905b261ecSmrg    else
4504642e01fSmrg        MakeClientGrabPervious(client);
4514202a189Smrg    return Success;
45205b261ecSmrg}
45305b261ecSmrg
45405b261ecSmrgstatic int
455f7df2e56SmrgProcXTestDispatch(ClientPtr client)
45605b261ecSmrg{
45705b261ecSmrg    REQUEST(xReq);
458f7df2e56Smrg    switch (stuff->data) {
459f7df2e56Smrg    case X_XTestGetVersion:
460f7df2e56Smrg        return ProcXTestGetVersion(client);
461f7df2e56Smrg    case X_XTestCompareCursor:
462f7df2e56Smrg        return ProcXTestCompareCursor(client);
463f7df2e56Smrg    case X_XTestFakeInput:
464f7df2e56Smrg        return ProcXTestFakeInput(client);
465f7df2e56Smrg    case X_XTestGrabControl:
466f7df2e56Smrg        return ProcXTestGrabControl(client);
467f7df2e56Smrg    default:
468f7df2e56Smrg        return BadRequest;
46905b261ecSmrg    }
47005b261ecSmrg}
47105b261ecSmrg
4727e31ba66Smrgstatic int _X_COLD
4734202a189SmrgSProcXTestGetVersion(ClientPtr client)
47405b261ecSmrg{
47505b261ecSmrg    REQUEST(xXTestGetVersionReq);
47605b261ecSmrg
477f7df2e56Smrg    swaps(&stuff->length);
47805b261ecSmrg    REQUEST_SIZE_MATCH(xXTestGetVersionReq);
479f7df2e56Smrg    swaps(&stuff->minorVersion);
48005b261ecSmrg    return ProcXTestGetVersion(client);
48105b261ecSmrg}
48205b261ecSmrg
4837e31ba66Smrgstatic int _X_COLD
4844202a189SmrgSProcXTestCompareCursor(ClientPtr client)
48505b261ecSmrg{
48605b261ecSmrg    REQUEST(xXTestCompareCursorReq);
48705b261ecSmrg
488f7df2e56Smrg    swaps(&stuff->length);
48905b261ecSmrg    REQUEST_SIZE_MATCH(xXTestCompareCursorReq);
490f7df2e56Smrg    swapl(&stuff->window);
491f7df2e56Smrg    swapl(&stuff->cursor);
49205b261ecSmrg    return ProcXTestCompareCursor(client);
49305b261ecSmrg}
49405b261ecSmrg
4957e31ba66Smrgstatic int _X_COLD
496f7df2e56SmrgXTestSwapFakeInput(ClientPtr client, xReq * req)
49705b261ecSmrg{
4984642e01fSmrg    int nev;
4994642e01fSmrg    xEvent *ev;
50005b261ecSmrg    xEvent sev;
50105b261ecSmrg    EventSwapPtr proc;
50205b261ecSmrg
50305b261ecSmrg    nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent);
504f7df2e56Smrg    for (ev = (xEvent *) &req[1]; --nev >= 0; ev++) {
5052d19872aSmrg        int evtype = ev->u.u.type & 0177;
5064642e01fSmrg        /* Swap event */
507e383896cSmrg        proc = EventSwapVector[evtype];
5084642e01fSmrg        /* no swapping proc; invalid event type? */
509e383896cSmrg        if (!proc || proc == NotImplemented || evtype == GenericEvent) {
5104642e01fSmrg            client->errorValue = ev->u.u.type;
5114642e01fSmrg            return BadValue;
5124642e01fSmrg        }
513f7df2e56Smrg        (*proc) (ev, &sev);
5144642e01fSmrg        *ev = sev;
51505b261ecSmrg    }
51605b261ecSmrg    return Success;
51705b261ecSmrg}
51805b261ecSmrg
5197e31ba66Smrgstatic int _X_COLD
5204202a189SmrgSProcXTestFakeInput(ClientPtr client)
52105b261ecSmrg{
5224642e01fSmrg    int n;
523f7df2e56Smrg
52405b261ecSmrg    REQUEST(xReq);
52505b261ecSmrg
526f7df2e56Smrg    swaps(&stuff->length);
52705b261ecSmrg    n = XTestSwapFakeInput(client, stuff);
52805b261ecSmrg    if (n != Success)
5294642e01fSmrg        return n;
53005b261ecSmrg    return ProcXTestFakeInput(client);
53105b261ecSmrg}
53205b261ecSmrg
5337e31ba66Smrgstatic int _X_COLD
5344202a189SmrgSProcXTestGrabControl(ClientPtr client)
53505b261ecSmrg{
53605b261ecSmrg    REQUEST(xXTestGrabControlReq);
53705b261ecSmrg
538f7df2e56Smrg    swaps(&stuff->length);
53905b261ecSmrg    REQUEST_SIZE_MATCH(xXTestGrabControlReq);
54005b261ecSmrg    return ProcXTestGrabControl(client);
54105b261ecSmrg}
54205b261ecSmrg
5437e31ba66Smrgstatic int _X_COLD
544f7df2e56SmrgSProcXTestDispatch(ClientPtr client)
54505b261ecSmrg{
54605b261ecSmrg    REQUEST(xReq);
547f7df2e56Smrg    switch (stuff->data) {
548f7df2e56Smrg    case X_XTestGetVersion:
549f7df2e56Smrg        return SProcXTestGetVersion(client);
550f7df2e56Smrg    case X_XTestCompareCursor:
551f7df2e56Smrg        return SProcXTestCompareCursor(client);
552f7df2e56Smrg    case X_XTestFakeInput:
553f7df2e56Smrg        return SProcXTestFakeInput(client);
554f7df2e56Smrg    case X_XTestGrabControl:
555f7df2e56Smrg        return SProcXTestGrabControl(client);
556f7df2e56Smrg    default:
557f7df2e56Smrg        return BadRequest;
55805b261ecSmrg    }
55905b261ecSmrg}
5604202a189Smrg
5614202a189Smrg/**
5624202a189Smrg * Allocate an virtual slave device for xtest events, this
5634202a189Smrg * is a slave device to inputInfo master devices
5644202a189Smrg */
565f7df2e56Smrgvoid
566f7df2e56SmrgInitXTestDevices(void)
5674202a189Smrg{
568f7df2e56Smrg    if (AllocXTestDevice(serverClient, "Virtual core",
569f7df2e56Smrg                         &xtestpointer, &xtestkeyboard,
570f7df2e56Smrg                         inputInfo.pointer, inputInfo.keyboard) != Success)
571f7df2e56Smrg         FatalError("Failed to allocate XTest devices");
5724202a189Smrg
5734202a189Smrg    if (ActivateDevice(xtestpointer, TRUE) != Success ||
5744202a189Smrg        ActivateDevice(xtestkeyboard, TRUE) != Success)
5754202a189Smrg        FatalError("Failed to activate XTest core devices.");
576f7df2e56Smrg    if (!EnableDevice(xtestpointer, TRUE) || !EnableDevice(xtestkeyboard, TRUE))
5774202a189Smrg        FatalError("Failed to enable XTest core devices.");
5784202a189Smrg
5794202a189Smrg    AttachDevice(NULL, xtestpointer, inputInfo.pointer);
580f7df2e56Smrg
5814202a189Smrg    AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard);
5824202a189Smrg}
5834202a189Smrg
5844202a189Smrg/**
5854202a189Smrg * Don't allow changing the XTest property.
5864202a189Smrg */
5874202a189Smrgstatic int
5884202a189SmrgDeviceSetXTestProperty(DeviceIntPtr dev, Atom property,
589f7df2e56Smrg                       XIPropertyValuePtr prop, BOOL checkonly)
5904202a189Smrg{
5914202a189Smrg    if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE))
5924202a189Smrg        return BadAccess;
5934202a189Smrg
5944202a189Smrg    return Success;
5954202a189Smrg}
5964202a189Smrg
5974202a189Smrg/**
5984202a189Smrg * Allocate a device pair that is initialised as a slave
5994202a189Smrg * device with properties that identify the devices as belonging
6004202a189Smrg * to XTest subsystem.
6014202a189Smrg * This only creates the pair, Activate/Enable Device
6024202a189Smrg * still need to be called.
6034202a189Smrg */
604f7df2e56Smrgint
605f7df2e56SmrgAllocXTestDevice(ClientPtr client, const char *name,
606f7df2e56Smrg                 DeviceIntPtr *ptr, DeviceIntPtr *keybd,
607f7df2e56Smrg                 DeviceIntPtr master_ptr, DeviceIntPtr master_keybd)
6084202a189Smrg{
6094202a189Smrg    int retval;
610f7df2e56Smrg    char *xtestname;
6114202a189Smrg    char dummy = 1;
6124202a189Smrg
613f7df2e56Smrg    if (asprintf(&xtestname, "%s XTEST", name) == -1)
614f7df2e56Smrg        return BadAlloc;
6154202a189Smrg
616f7df2e56Smrg    retval =
617f7df2e56Smrg        AllocDevicePair(client, xtestname, ptr, keybd, CorePointerProc,
618f7df2e56Smrg                        CoreKeyboardProc, FALSE);
619f7df2e56Smrg    if (retval == Success) {
620f7df2e56Smrg        (*ptr)->xtest_master_id = master_ptr->id;
621f7df2e56Smrg        (*keybd)->xtest_master_id = master_keybd->id;
6224202a189Smrg
6234202a189Smrg        XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
624f7df2e56Smrg                               XA_INTEGER, 8, PropModeReplace, 1, &dummy,
625f7df2e56Smrg                               FALSE);
626f7df2e56Smrg        XISetDevicePropertyDeletable(*ptr,
627f7df2e56Smrg                                     XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
628f7df2e56Smrg                                     FALSE);
6294202a189Smrg        XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL);
6304202a189Smrg        XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
631f7df2e56Smrg                               XA_INTEGER, 8, PropModeReplace, 1, &dummy,
632f7df2e56Smrg                               FALSE);
633f7df2e56Smrg        XISetDevicePropertyDeletable(*keybd,
634f7df2e56Smrg                                     XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
635f7df2e56Smrg                                     FALSE);
6364202a189Smrg        XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL);
6374202a189Smrg    }
6384202a189Smrg
639f7df2e56Smrg    free(xtestname);
6404202a189Smrg
6414202a189Smrg    return retval;
6424202a189Smrg}
6434202a189Smrg
6444202a189Smrg/**
6454202a189Smrg * If master is NULL, return TRUE if the given device is an xtest device or
6464202a189Smrg * FALSE otherwise.
6474202a189Smrg * If master is not NULL, return TRUE if the given device is this master's
6484202a189Smrg * xtest device.
6494202a189Smrg */
6504202a189SmrgBOOL
6514202a189SmrgIsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master)
6524202a189Smrg{
6534202a189Smrg    if (IsMaster(dev))
6544202a189Smrg        return FALSE;
6554202a189Smrg
6564202a189Smrg    /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest
6574202a189Smrg     * device */
6584202a189Smrg    if (master)
659f7df2e56Smrg        return dev->xtest_master_id == master->id;
6604202a189Smrg
6614202a189Smrg    return dev->xtest_master_id != 0;
6624202a189Smrg}
6634202a189Smrg
6644202a189Smrg/**
6654202a189Smrg * @return The X Test virtual device for the given master.
6664202a189Smrg */
6674202a189SmrgDeviceIntPtr
6684202a189SmrgGetXTestDevice(DeviceIntPtr master)
6694202a189Smrg{
6704202a189Smrg    DeviceIntPtr it;
6714202a189Smrg
672f7df2e56Smrg    for (it = inputInfo.devices; it; it = it->next) {
6734202a189Smrg        if (IsXTestDevice(it, master))
6744202a189Smrg            return it;
6754202a189Smrg    }
6764202a189Smrg
6774202a189Smrg    /* This only happens if master is a slave device. don't do that */
6784202a189Smrg    return NULL;
6794202a189Smrg}
6804202a189Smrg
681f7df2e56Smrgstatic void
682f7df2e56SmrgXTestExtensionTearDown(ExtensionEntry * e)
683f7df2e56Smrg{
684f7df2e56Smrg    FreeEventList(xtest_evlist, GetMaximumEventsNum());
685f7df2e56Smrg    xtest_evlist = NULL;
686f7df2e56Smrg}
687f7df2e56Smrg
68865b04b38Smrgvoid
689f7df2e56SmrgXTestExtensionInit(void)
69065b04b38Smrg{
69165b04b38Smrg    AddExtension(XTestExtensionName, 0, 0,
692f7df2e56Smrg                 ProcXTestDispatch, SProcXTestDispatch,
693f7df2e56Smrg                 XTestExtensionTearDown, StandardMinorOpcode);
69465b04b38Smrg
69565b04b38Smrg    xtest_evlist = InitEventList(GetMaximumEventsNum());
69665b04b38Smrg}
697