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