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