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