3 Copyright 1992, 1998 The Open Group
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
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
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.
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
29 #ifdef HAVE_DIX_CONFIG_H
30 #include <dix-config.h>
34 #include <X11/Xproto.h>
35 #include <X11/Xatom.h>
38 #include "dixstruct.h"
39 #include "extnsionst.h"
40 #include "windowstr.h"
42 #include "scrnintstr.h"
43 #include "dixevents.h"
44 #include "sleepuntil.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"
56 #include "inpututils.h"
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
63 static InternalEvent *xtest_evlist;
67 * is the virtual pointer for XTest. It is the first slave
70 * is the virtual keyboard for XTest. It is the first slave
73 * Neither of these devices can be deleted.
75 DeviceIntPtr xtestpointer, xtestkeyboard;
78 #include "panoramiX.h"
79 #include "panoramiXsrv.h"
82 #ifdef _F_SUPPORT_XTEST_TOUCH_EVENT_
84 #define XI_TouchBegin 18
86 #ifndef XI_TouchUpdate
87 #define XI_TouchUpdate 19
90 #define XI_TouchEnd 20
92 #endif //_F_SUPPORT_XTEST_TOUCH_EVENT_
94 static int XTestSwapFakeInput(ClientPtr /* client */ ,
99 ProcXTestGetVersion(ClientPtr client)
101 xXTestGetVersionReply rep = {
103 .sequenceNumber = client->sequence,
105 .majorVersion = XTestMajorVersion,
106 .minorVersion = XTestMinorVersion
109 REQUEST_SIZE_MATCH(xXTestGetVersionReq);
111 if (client->swapped) {
112 swaps(&rep.sequenceNumber);
113 swaps(&rep.minorVersion);
115 WriteToClient(client, sizeof(xXTestGetVersionReply), &rep);
120 ProcXTestCompareCursor(ClientPtr client)
122 REQUEST(xXTestCompareCursorReq);
123 xXTestCompareCursorReply rep;
127 DeviceIntPtr ptr = PickPointer(client);
129 REQUEST_SIZE_MATCH(xXTestCompareCursorReq);
130 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
137 if (stuff->cursor == None)
138 pCursor = NullCursor;
139 else if (stuff->cursor == XTestCurrentCursor)
140 pCursor = GetSpriteCursor(ptr);
142 rc = dixLookupResourceByType((void **) &pCursor, stuff->cursor,
143 RT_CURSOR, client, DixReadAccess);
145 client->errorValue = stuff->cursor;
149 rep = (xXTestCompareCursorReply) {
151 .sequenceNumber = client->sequence,
153 .same = (wCursor(pWin) == pCursor)
155 if (client->swapped) {
156 swaps(&rep.sequenceNumber);
158 WriteToClient(client, sizeof(xXTestCompareCursorReply), &rep);
163 ProcXTestFakeInput(ClientPtr client)
165 REQUEST(xXTestFakeInputReq);
166 int nev, n, type, rc;
168 DeviceIntPtr dev = NULL;
170 Bool extension = FALSE;
172 int valuators[MAX_VALUATORS] = { 0 };
173 int numValuators = 0;
174 int firstValuator = 0;
179 int need_ptr_update = 1;
180 #ifdef _ENABLE_PRIVILEGE_CHECK_ON_XTEST_DEVICE_API_
181 xXTestFakeInputReply rep;
183 #endif //_ENABLE_PRIVILEGE_CHECK_ON_XTEST_DEVICE_API_
185 nev = (stuff->length << 2) - sizeof(xReq);
186 if ((nev % sizeof(xEvent)) || !nev)
188 nev /= sizeof(xEvent);
190 ev = (xEvent *) &((xReq *) stuff)[1];
191 type = ev->u.u.type & 0177;
193 if (type >= EXTENSION_EVENT_BASE) {
197 rc = dixLookupDevice(&dev, stuff->deviceid & 0177, client,
200 client->errorValue = stuff->deviceid & 0177;
205 type -= DeviceValuator;
207 case XI_DeviceKeyPress:
208 case XI_DeviceKeyRelease:
210 client->errorValue = ev->u.u.type;
213 #ifdef _ENABLE_PRIVILEGE_CHECK_ON_XTEST_DEVICE_API_
214 res = SmackUtilHaveAuthority(client, "xorg::inputgen", DixReadAccess | DixWriteAccess);
215 rep = (xXTestFakeInputReply) {
218 .sequenceNumber = client->sequence,
222 if (res == Success) {
223 rep.accepted = xTrue;
225 rep.accepted = xFalse;
228 if (client->swapped) {
229 swaps(&rep.sequenceNumber);
232 WriteToClient(client, sizeof(xXTestFakeInputReply), &rep);
233 if (res != Success) return BadAccess;
234 #endif //_ENABLE_PRIVILEGE_CHECK_ON_XTEST_DEVICE_API_
236 case XI_DeviceButtonPress:
237 case XI_DeviceButtonRelease:
239 client->errorValue = ev->u.u.type;
243 case XI_DeviceMotionNotify:
244 if (!dev->valuator) {
245 client->errorValue = ev->u.u.type;
249 #ifdef _F_SUPPORT_XTEST_TOUCH_EVENT_
254 client->errorValue = ev->u.u.type;
257 #ifdef _ENABLE_PRIVILEGE_CHECK_ON_XTEST_DEVICE_API_
258 res = SmackUtilHaveAuthority(client, "xorg::inputgen", DixReadAccess | DixWriteAccess);
259 rep = (xXTestFakeInputReply) {
262 .sequenceNumber = client->sequence,
266 if (res == Success) {
267 rep.accepted = xTrue;
269 rep.accepted = xFalse;
272 if (client->swapped) {
273 swaps(&rep.sequenceNumber);
276 WriteToClient(client, sizeof(xXTestFakeInputReply), &rep);
277 if (res != Success) return BadAccess;
278 #endif //_ENABLE_PRIVILEGE_CHECK_ON_XTEST_DEVICE_API_
280 #endif //_F_SUPPORT_XTEST_TOUCH_EVENT_
282 case XI_ProximityOut:
283 if (!dev->proximity) {
284 client->errorValue = ev->u.u.type;
289 client->errorValue = ev->u.u.type;
294 if (nev == 1 && type == XI_DeviceMotionNotify)
295 return BadLength; /* DevMotion must be followed by DevValuator */
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_
302 firstValuator = ((deviceValuator *) (ev + 1))->first_valuator;
303 if (firstValuator > dev->valuator->numAxes) {
304 client->errorValue = ev->u.u.type;
308 if (ev->u.u.detail == xFalse)
309 flags |= POINTER_ABSOLUTE;
313 flags |= POINTER_ABSOLUTE;
316 if (nev > 1 && !dev->valuator) {
317 client->errorValue = firstValuator;
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;
329 if (dv->first_valuator != base) {
330 client->errorValue = dv->first_valuator;
333 switch (dv->num_valuators) {
335 valuators[base + 5] = dv->valuator5;
337 valuators[base + 4] = dv->valuator4;
339 valuators[base + 3] = dv->valuator3;
341 valuators[base + 2] = dv->valuator2;
343 valuators[base + 1] = dv->valuator1;
345 valuators[base] = dv->valuator0;
348 client->errorValue = dv->num_valuators;
352 base += dv->num_valuators;
353 numValuators += dv->num_valuators;
355 if (firstValuator + numValuators > dev->valuator->numAxes) {
356 client->errorValue = dv->num_valuators;
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;
371 dev = PickKeyboard(client);
375 dev = PickPointer(client);
378 dev = PickPointer(client);
379 valuators[0] = ev->u.keyButtonPointer.rootX;
380 valuators[1] = ev->u.keyButtonPointer.rootY;
383 if (ev->u.u.detail == xFalse)
384 flags = POINTER_ABSOLUTE | POINTER_DESKTOP;
387 client->errorValue = ev->u.u.type;
391 /* Technically the protocol doesn't allow for BadAccess here but
392 * this can only happen when all MDs are disabled. */
396 dev = GetXTestDevice(dev);
400 /* If the event has a time set, wait for it to pass */
401 if (ev->u.keyButtonPointer.time) {
402 TimeStamp activateTime;
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;
412 /* see mbuf.c:QueueDisplayRequest (from the deprecated Multibuffer
413 * extension) for code similar to this */
415 if (!ClientSleepUntil(client, &activateTime, NULL, NULL)) {
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);
423 ResetCurrentRequest(client);
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;
448 if (!(extension || ev->u.keyButtonPointer.root == None)) {
449 rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root,
450 client, DixGetAttrAccess);
454 client->errorValue = ev->u.keyButtonPointer.root;
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;
466 if (ev->u.u.detail != xTrue && ev->u.u.detail != xFalse) {
467 client->errorValue = ev->u.u.detail;
471 /* FIXME: Xinerama! */
479 if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons) {
480 client->errorValue = ev->u.u.detail;
484 #ifdef _F_SUPPORT_XTEST_TOUCH_EVENT_
491 if (ev->u.u.detail < 0) {
492 client->errorValue = ev->u.u.detail;
496 #endif //_F_SUPPORT_XTEST_TOUCH_EVENT_
498 if (screenIsSaved == SCREEN_SAVER_ON)
499 dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
503 valuator_mask_set_range(&mask, firstValuator, numValuators, valuators);
504 nevents = GetPointerEvents(xtest_evlist, dev, type, 0, flags, &mask);
508 valuator_mask_set_range(&mask, firstValuator, numValuators, valuators);
509 nevents = GetPointerEvents(xtest_evlist, dev, type, ev->u.u.detail,
515 GetKeyboardEvents(xtest_evlist, dev, type, ev->u.u.detail, NULL);
517 #ifdef _F_SUPPORT_XTEST_TOUCH_EVENT_
521 valuator_mask_set_range(&mask, firstValuator, numValuators, valuators);
523 GetTouchEvents(xtest_evlist, dev, ev->u.u.detail, type, 0, &mask);
525 #endif //_F_SUPPORT_XTEST_TOUCH_EVENT_
528 for (i = 0; i < nevents; i++)
529 mieqProcessDeviceEvent(dev, &xtest_evlist[i], miPointerGetScreen(inputInfo.pointer));
532 miPointerUpdateSprite(dev);
537 ProcXTestGrabControl(ClientPtr client)
539 REQUEST(xXTestGrabControlReq);
541 REQUEST_SIZE_MATCH(xXTestGrabControlReq);
542 if ((stuff->impervious != xTrue) && (stuff->impervious != xFalse)) {
543 client->errorValue = stuff->impervious;
546 if (stuff->impervious)
547 MakeClientGrabImpervious(client);
549 MakeClientGrabPervious(client);
554 ProcXTestDispatch(ClientPtr client)
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);
572 SProcXTestGetVersion(ClientPtr client)
574 REQUEST(xXTestGetVersionReq);
576 swaps(&stuff->length);
577 REQUEST_SIZE_MATCH(xXTestGetVersionReq);
578 swaps(&stuff->minorVersion);
579 return ProcXTestGetVersion(client);
583 SProcXTestCompareCursor(ClientPtr client)
585 REQUEST(xXTestCompareCursorReq);
587 swaps(&stuff->length);
588 REQUEST_SIZE_MATCH(xXTestCompareCursorReq);
589 swapl(&stuff->window);
590 swapl(&stuff->cursor);
591 return ProcXTestCompareCursor(client);
595 XTestSwapFakeInput(ClientPtr client, xReq * req)
602 nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent);
603 for (ev = (xEvent *) &req[1]; --nev >= 0; ev++) {
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;
618 SProcXTestFakeInput(ClientPtr client)
624 swaps(&stuff->length);
625 n = XTestSwapFakeInput(client, stuff);
628 return ProcXTestFakeInput(client);
632 SProcXTestGrabControl(ClientPtr client)
634 REQUEST(xXTestGrabControlReq);
636 swaps(&stuff->length);
637 REQUEST_SIZE_MATCH(xXTestGrabControlReq);
638 return ProcXTestGrabControl(client);
642 SProcXTestDispatch(ClientPtr client)
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);
660 * Allocate an virtual slave device for xtest events, this
661 * is a slave device to inputInfo master devices
664 InitXTestDevices(void)
666 if (AllocXTestDevice(serverClient, "Virtual core",
667 &xtestpointer, &xtestkeyboard,
668 inputInfo.pointer, inputInfo.keyboard) != Success)
669 FatalError("Failed to allocate XTest devices");
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.");
677 AttachDevice(NULL, xtestpointer, inputInfo.pointer);
679 AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard);
682 #ifdef _F_SUPPORT_XTEST_TOUCH_EVENT_
684 InitXTestHWKeyTouchDevices(void)
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");
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.");
698 AttachDevice(NULL, xtestTouch, inputInfo.pointer);
700 AttachDevice(NULL, xtestHWKey, inputInfo.keyboard);
702 #endif //_F_SUPPORT_XTEST_TOUCH_EVENT_
705 * Don't allow changing the XTest property.
708 DeviceSetXTestProperty(DeviceIntPtr dev, Atom property,
709 XIPropertyValuePtr prop, BOOL checkonly)
711 if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE))
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.
725 AllocXTestDevice(ClientPtr client, const char *name,
726 DeviceIntPtr *ptr, DeviceIntPtr *keybd,
727 DeviceIntPtr master_ptr, DeviceIntPtr master_keybd)
733 if (asprintf(&xtestname, "%s XTEST", name) == -1)
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;
743 XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
744 XA_INTEGER, 8, PropModeReplace, 1, &dummy,
746 XISetDevicePropertyDeletable(*ptr,
747 XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
749 XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL);
750 XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
751 XA_INTEGER, 8, PropModeReplace, 1, &dummy,
753 XISetDevicePropertyDeletable(*keybd,
754 XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
756 XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL);
764 #ifdef _F_SUPPORT_XTEST_TOUCH_EVENT_
766 AllocXTestHWKeyTouchDevice(ClientPtr client, const char *name,
767 DeviceIntPtr *ptr, DeviceIntPtr *keybd,
768 DeviceIntPtr master_ptr, DeviceIntPtr master_keybd)
774 if (asprintf(&xtestname, "%s XTEST", name) == -1)
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;
784 XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
785 XA_INTEGER, 8, PropModeReplace, 1, &dummy,
787 XISetDevicePropertyDeletable(*ptr,
788 XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
790 XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL);
791 XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
792 XA_INTEGER, 8, PropModeReplace, 1, &dummy,
794 XISetDevicePropertyDeletable(*keybd,
795 XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
797 XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL);
804 #endif //_F_SUPPORT_XTEST_TOUCH_EVENT_
807 * If master is NULL, return TRUE if the given device is an xtest device or
809 * If master is not NULL, return TRUE if the given device is this master's
813 IsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master)
818 /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest
821 return dev->xtest_master_id == master->id;
823 return dev->xtest_master_id != 0;
827 * @return The X Test virtual device for the given master.
830 GetXTestDevice(DeviceIntPtr master)
834 for (it = inputInfo.devices; it; it = it->next) {
835 if (IsXTestDevice(it, master))
839 /* This only happens if master is a slave device. don't do that */
844 XTestExtensionTearDown(ExtensionEntry * e)
846 FreeEventList(xtest_evlist, GetMaximumEventsNum());
851 XTestExtensionInit(void)
853 AddExtension(XTestExtensionName, 0, 0,
854 ProcXTestDispatch, SProcXTestDispatch,
855 XTestExtensionTearDown, StandardMinorOpcode);
857 xtest_evlist = InitEventList(GetMaximumEventsNum());