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 static int XTestSwapFakeInput(ClientPtr
/* client */ ,
87 ProcXTestGetVersion(ClientPtr client
)
89 xXTestGetVersionReply rep
= {
91 .sequenceNumber
= client
->sequence
,
93 .majorVersion
= XTestMajorVersion
,
94 .minorVersion
= XTestMinorVersion
97 REQUEST_SIZE_MATCH(xXTestGetVersionReq
);
99 if (client
->swapped
) {
100 swaps(&rep
.sequenceNumber
);
101 swaps(&rep
.minorVersion
);
103 WriteToClient(client
, sizeof(xXTestGetVersionReply
), &rep
);
108 ProcXTestCompareCursor(ClientPtr client
)
110 REQUEST(xXTestCompareCursorReq
);
111 xXTestCompareCursorReply rep
;
115 DeviceIntPtr ptr
= PickPointer(client
);
117 REQUEST_SIZE_MATCH(xXTestCompareCursorReq
);
118 rc
= dixLookupWindow(&pWin
, stuff
->window
, client
, DixGetAttrAccess
);
125 if (stuff
->cursor
== None
)
126 pCursor
= NullCursor
;
127 else if (stuff
->cursor
== XTestCurrentCursor
)
128 pCursor
= GetSpriteCursor(ptr
);
130 rc
= dixLookupResourceByType((pointer
*) &pCursor
, stuff
->cursor
,
131 RT_CURSOR
, client
, DixReadAccess
);
133 client
->errorValue
= stuff
->cursor
;
137 rep
= (xXTestCompareCursorReply
) {
139 .sequenceNumber
= client
->sequence
,
141 .same
= (wCursor(pWin
) == pCursor
)
143 if (client
->swapped
) {
144 swaps(&rep
.sequenceNumber
);
146 WriteToClient(client
, sizeof(xXTestCompareCursorReply
), &rep
);
151 ProcXTestFakeInput(ClientPtr client
)
153 REQUEST(xXTestFakeInputReq
);
154 int nev
, n
, type
, rc
;
156 DeviceIntPtr dev
= NULL
;
158 Bool extension
= FALSE
;
160 int valuators
[MAX_VALUATORS
] = { 0 };
161 int numValuators
= 0;
162 int firstValuator
= 0;
167 int need_ptr_update
= 1;
169 nev
= (stuff
->length
<< 2) - sizeof(xReq
);
170 if ((nev
% sizeof(xEvent
)) || !nev
)
172 nev
/= sizeof(xEvent
);
174 ev
= (xEvent
*) &((xReq
*) stuff
)[1];
175 type
= ev
->u
.u
.type
& 0177;
177 if (type
>= EXTENSION_EVENT_BASE
) {
181 rc
= dixLookupDevice(&dev
, stuff
->deviceid
& 0177, client
,
184 client
->errorValue
= stuff
->deviceid
& 0177;
189 type
-= DeviceValuator
;
191 case XI_DeviceKeyPress
:
192 case XI_DeviceKeyRelease
:
194 client
->errorValue
= ev
->u
.u
.type
;
198 case XI_DeviceButtonPress
:
199 case XI_DeviceButtonRelease
:
201 client
->errorValue
= ev
->u
.u
.type
;
205 case XI_DeviceMotionNotify
:
206 if (!dev
->valuator
) {
207 client
->errorValue
= ev
->u
.u
.type
;
212 case XI_ProximityOut
:
213 if (!dev
->proximity
) {
214 client
->errorValue
= ev
->u
.u
.type
;
219 client
->errorValue
= ev
->u
.u
.type
;
224 if (nev
== 1 && type
== XI_DeviceMotionNotify
)
225 return BadLength
; /* DevMotion must be followed by DevValuator */
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
;
234 if (ev
->u
.u
.detail
== xFalse
)
235 flags
|= POINTER_ABSOLUTE
;
239 flags
|= POINTER_ABSOLUTE
;
242 if (nev
> 1 && !dev
->valuator
) {
243 client
->errorValue
= firstValuator
;
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
;
255 if (dv
->first_valuator
!= base
) {
256 client
->errorValue
= dv
->first_valuator
;
259 switch (dv
->num_valuators
) {
261 valuators
[base
+ 5] = dv
->valuator5
;
263 valuators
[base
+ 4] = dv
->valuator4
;
265 valuators
[base
+ 3] = dv
->valuator3
;
267 valuators
[base
+ 2] = dv
->valuator2
;
269 valuators
[base
+ 1] = dv
->valuator1
;
271 valuators
[base
] = dv
->valuator0
;
274 client
->errorValue
= dv
->num_valuators
;
278 base
+= dv
->num_valuators
;
279 numValuators
+= dv
->num_valuators
;
281 if (firstValuator
+ numValuators
> dev
->valuator
->numAxes
) {
282 client
->errorValue
= dv
->num_valuators
;
286 type
= type
- XI_DeviceKeyPress
+ KeyPress
;
295 dev
= PickKeyboard(client
);
299 dev
= PickPointer(client
);
302 dev
= PickPointer(client
);
303 valuators
[0] = ev
->u
.keyButtonPointer
.rootX
;
304 valuators
[1] = ev
->u
.keyButtonPointer
.rootY
;
307 if (ev
->u
.u
.detail
== xFalse
)
308 flags
= POINTER_ABSOLUTE
| POINTER_DESKTOP
;
311 client
->errorValue
= ev
->u
.u
.type
;
315 /* Technically the protocol doesn't allow for BadAccess here but
316 * this can only happen when all MDs are disabled. */
320 dev
= GetXTestDevice(dev
);
324 /* If the event has a time set, wait for it to pass */
325 if (ev
->u
.keyButtonPointer
.time
) {
326 TimeStamp activateTime
;
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;
336 /* see mbuf.c:QueueDisplayRequest (from the deprecated Multibuffer
337 * extension) for code similar to this */
339 if (!ClientSleepUntil(client
, &activateTime
, NULL
, NULL
)) {
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
);
347 ResetCurrentRequest(client
);
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
;
370 if (!(extension
|| ev
->u
.keyButtonPointer
.root
== None
)) {
371 rc
= dixLookupWindow(&root
, ev
->u
.keyButtonPointer
.root
,
372 client
, DixGetAttrAccess
);
376 client
->errorValue
= ev
->u
.keyButtonPointer
.root
;
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
;
388 if (ev
->u
.u
.detail
!= xTrue
&& ev
->u
.u
.detail
!= xFalse
) {
389 client
->errorValue
= ev
->u
.u
.detail
;
393 /* FIXME: Xinerama! */
401 if (!ev
->u
.u
.detail
|| ev
->u
.u
.detail
> dev
->button
->numButtons
) {
402 client
->errorValue
= ev
->u
.u
.detail
;
407 if (screenIsSaved
== SCREEN_SAVER_ON
)
408 dixSaveScreens(serverClient
, SCREEN_SAVER_OFF
, ScreenSaverReset
);
412 valuator_mask_set_range(&mask
, firstValuator
, numValuators
, valuators
);
413 nevents
= GetPointerEvents(xtest_evlist
, dev
, type
, 0, flags
, &mask
);
417 valuator_mask_set_range(&mask
, firstValuator
, numValuators
, valuators
);
418 nevents
= GetPointerEvents(xtest_evlist
, dev
, type
, ev
->u
.u
.detail
,
424 GetKeyboardEvents(xtest_evlist
, dev
, type
, ev
->u
.u
.detail
, NULL
);
428 for (i
= 0; i
< nevents
; i
++)
429 mieqProcessDeviceEvent(dev
, &xtest_evlist
[i
], miPointerGetScreen(inputInfo
.pointer
));
432 miPointerUpdateSprite(dev
);
437 ProcXTestGrabControl(ClientPtr client
)
439 REQUEST(xXTestGrabControlReq
);
441 REQUEST_SIZE_MATCH(xXTestGrabControlReq
);
442 if ((stuff
->impervious
!= xTrue
) && (stuff
->impervious
!= xFalse
)) {
443 client
->errorValue
= stuff
->impervious
;
446 if (stuff
->impervious
)
447 MakeClientGrabImpervious(client
);
449 MakeClientGrabPervious(client
);
454 ProcXTestDispatch(ClientPtr client
)
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
);
472 SProcXTestGetVersion(ClientPtr client
)
474 REQUEST(xXTestGetVersionReq
);
476 swaps(&stuff
->length
);
477 REQUEST_SIZE_MATCH(xXTestGetVersionReq
);
478 swaps(&stuff
->minorVersion
);
479 return ProcXTestGetVersion(client
);
483 SProcXTestCompareCursor(ClientPtr client
)
485 REQUEST(xXTestCompareCursorReq
);
487 swaps(&stuff
->length
);
488 REQUEST_SIZE_MATCH(xXTestCompareCursorReq
);
489 swapl(&stuff
->window
);
490 swapl(&stuff
->cursor
);
491 return ProcXTestCompareCursor(client
);
495 XTestSwapFakeInput(ClientPtr client
, xReq
* req
)
502 nev
= ((req
->length
<< 2) - sizeof(xReq
)) / sizeof(xEvent
);
503 for (ev
= (xEvent
*) &req
[1]; --nev
>= 0; ev
++) {
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
;
518 SProcXTestFakeInput(ClientPtr client
)
524 swaps(&stuff
->length
);
525 n
= XTestSwapFakeInput(client
, stuff
);
528 return ProcXTestFakeInput(client
);
532 SProcXTestGrabControl(ClientPtr client
)
534 REQUEST(xXTestGrabControlReq
);
536 swaps(&stuff
->length
);
537 REQUEST_SIZE_MATCH(xXTestGrabControlReq
);
538 return ProcXTestGrabControl(client
);
542 SProcXTestDispatch(ClientPtr client
)
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
);
560 * Allocate an virtual slave device for xtest events, this
561 * is a slave device to inputInfo master devices
564 InitXTestDevices(void)
566 if (AllocXTestDevice(serverClient
, "Virtual core",
567 &xtestpointer
, &xtestkeyboard
,
568 inputInfo
.pointer
, inputInfo
.keyboard
) != Success
)
569 FatalError("Failed to allocate XTest devices");
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.");
577 AttachDevice(NULL
, xtestpointer
, inputInfo
.pointer
);
579 AttachDevice(NULL
, xtestkeyboard
, inputInfo
.keyboard
);
583 * Don't allow changing the XTest property.
586 DeviceSetXTestProperty(DeviceIntPtr dev
, Atom property
,
587 XIPropertyValuePtr prop
, BOOL checkonly
)
589 if (property
== XIGetKnownProperty(XI_PROP_XTEST_DEVICE
))
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.
603 AllocXTestDevice(ClientPtr client
, const char *name
,
604 DeviceIntPtr
*ptr
, DeviceIntPtr
*keybd
,
605 DeviceIntPtr master_ptr
, DeviceIntPtr master_keybd
)
611 if (asprintf(&xtestname
, "%s XTEST", name
) == -1)
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
;
621 XIChangeDeviceProperty(*ptr
, XIGetKnownProperty(XI_PROP_XTEST_DEVICE
),
622 XA_INTEGER
, 8, PropModeReplace
, 1, &dummy
,
624 XISetDevicePropertyDeletable(*ptr
,
625 XIGetKnownProperty(XI_PROP_XTEST_DEVICE
),
627 XIRegisterPropertyHandler(*ptr
, DeviceSetXTestProperty
, NULL
, NULL
);
628 XIChangeDeviceProperty(*keybd
, XIGetKnownProperty(XI_PROP_XTEST_DEVICE
),
629 XA_INTEGER
, 8, PropModeReplace
, 1, &dummy
,
631 XISetDevicePropertyDeletable(*keybd
,
632 XIGetKnownProperty(XI_PROP_XTEST_DEVICE
),
634 XIRegisterPropertyHandler(*keybd
, DeviceSetXTestProperty
, NULL
, NULL
);
643 * If master is NULL, return TRUE if the given device is an xtest device or
645 * If master is not NULL, return TRUE if the given device is this master's
649 IsXTestDevice(DeviceIntPtr dev
, DeviceIntPtr master
)
654 /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest
657 return dev
->xtest_master_id
== master
->id
;
659 return dev
->xtest_master_id
!= 0;
663 * @return The X Test virtual device for the given master.
666 GetXTestDevice(DeviceIntPtr master
)
670 for (it
= inputInfo
.devices
; it
; it
= it
->next
) {
671 if (IsXTestDevice(it
, master
))
675 /* This only happens if master is a slave device. don't do that */
680 XTestExtensionTearDown(ExtensionEntry
* e
)
682 FreeEventList(xtest_evlist
, GetMaximumEventsNum());
687 XTestExtensionInit(void)
689 AddExtension(XTestExtensionName
, 0, 0,
690 ProcXTestDispatch
, SProcXTestDispatch
,
691 XTestExtensionTearDown
, StandardMinorOpcode
);
693 xtest_evlist
= InitEventList(GetMaximumEventsNum());