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