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 */
64 static 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 */
76 DeviceIntPtr xtestpointer, xtestkeyboard;
77
78 #ifdef PANORAMIX
79 #include "panoramiX.h"
80 #include "panoramiXsrv.h"
81 #endif
82
83 static int XTestSwapFakeInput(ClientPtr /* client */ ,
84 xReq * /* req */
85 );
86
87 static int
ProcXTestGetVersion(ClientPtr client)88 ProcXTestGetVersion(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
108 static int
ProcXTestCompareCursor(ClientPtr client)109 ProcXTestCompareCursor(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
151 static int
ProcXTestFakeInput(ClientPtr client)152 ProcXTestFakeInput(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
437 static int
ProcXTestGrabControl(ClientPtr client)438 ProcXTestGrabControl(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
454 static int
ProcXTestDispatch(ClientPtr client)455 ProcXTestDispatch(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
472 static int _X_COLD
SProcXTestGetVersion(ClientPtr client)473 SProcXTestGetVersion(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
483 static int _X_COLD
SProcXTestCompareCursor(ClientPtr client)484 SProcXTestCompareCursor(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
495 static int _X_COLD
XTestSwapFakeInput(ClientPtr client,xReq * req)496 XTestSwapFakeInput(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 /* Swap event */
506 proc = EventSwapVector[ev->u.u.type & 0177];
507 /* no swapping proc; invalid event type? */
508 if (!proc || proc == NotImplemented) {
509 client->errorValue = ev->u.u.type;
510 return BadValue;
511 }
512 (*proc) (ev, &sev);
513 *ev = sev;
514 }
515 return Success;
516 }
517
518 static int _X_COLD
SProcXTestFakeInput(ClientPtr client)519 SProcXTestFakeInput(ClientPtr client)
520 {
521 int n;
522
523 REQUEST(xReq);
524
525 swaps(&stuff->length);
526 n = XTestSwapFakeInput(client, stuff);
527 if (n != Success)
528 return n;
529 return ProcXTestFakeInput(client);
530 }
531
532 static int _X_COLD
SProcXTestGrabControl(ClientPtr client)533 SProcXTestGrabControl(ClientPtr client)
534 {
535 REQUEST(xXTestGrabControlReq);
536
537 swaps(&stuff->length);
538 REQUEST_SIZE_MATCH(xXTestGrabControlReq);
539 return ProcXTestGrabControl(client);
540 }
541
542 static int _X_COLD
SProcXTestDispatch(ClientPtr client)543 SProcXTestDispatch(ClientPtr client)
544 {
545 REQUEST(xReq);
546 switch (stuff->data) {
547 case X_XTestGetVersion:
548 return SProcXTestGetVersion(client);
549 case X_XTestCompareCursor:
550 return SProcXTestCompareCursor(client);
551 case X_XTestFakeInput:
552 return SProcXTestFakeInput(client);
553 case X_XTestGrabControl:
554 return SProcXTestGrabControl(client);
555 default:
556 return BadRequest;
557 }
558 }
559
560 /**
561 * Allocate an virtual slave device for xtest events, this
562 * is a slave device to inputInfo master devices
563 */
564 void
InitXTestDevices(void)565 InitXTestDevices(void)
566 {
567 if (AllocXTestDevice(serverClient, "Virtual core",
568 &xtestpointer, &xtestkeyboard,
569 inputInfo.pointer, inputInfo.keyboard) != Success)
570 FatalError("Failed to allocate XTest devices");
571
572 if (ActivateDevice(xtestpointer, TRUE) != Success ||
573 ActivateDevice(xtestkeyboard, TRUE) != Success)
574 FatalError("Failed to activate XTest core devices.");
575 if (!EnableDevice(xtestpointer, TRUE) || !EnableDevice(xtestkeyboard, TRUE))
576 FatalError("Failed to enable XTest core devices.");
577
578 AttachDevice(NULL, xtestpointer, inputInfo.pointer);
579
580 AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard);
581 }
582
583 /**
584 * Don't allow changing the XTest property.
585 */
586 static int
DeviceSetXTestProperty(DeviceIntPtr dev,Atom property,XIPropertyValuePtr prop,BOOL checkonly)587 DeviceSetXTestProperty(DeviceIntPtr dev, Atom property,
588 XIPropertyValuePtr prop, BOOL checkonly)
589 {
590 if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE))
591 return BadAccess;
592
593 return Success;
594 }
595
596 /**
597 * Allocate a device pair that is initialised as a slave
598 * device with properties that identify the devices as belonging
599 * to XTest subsystem.
600 * This only creates the pair, Activate/Enable Device
601 * still need to be called.
602 */
603 int
AllocXTestDevice(ClientPtr client,const char * name,DeviceIntPtr * ptr,DeviceIntPtr * keybd,DeviceIntPtr master_ptr,DeviceIntPtr master_keybd)604 AllocXTestDevice(ClientPtr client, const char *name,
605 DeviceIntPtr *ptr, DeviceIntPtr *keybd,
606 DeviceIntPtr master_ptr, DeviceIntPtr master_keybd)
607 {
608 int retval;
609 char *xtestname;
610 char dummy = 1;
611
612 if (asprintf(&xtestname, "%s XTEST", name) == -1)
613 return BadAlloc;
614
615 retval =
616 AllocDevicePair(client, xtestname, ptr, keybd, CorePointerProc,
617 CoreKeyboardProc, FALSE);
618 if (retval == Success) {
619 (*ptr)->xtest_master_id = master_ptr->id;
620 (*keybd)->xtest_master_id = master_keybd->id;
621
622 XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
623 XA_INTEGER, 8, PropModeReplace, 1, &dummy,
624 FALSE);
625 XISetDevicePropertyDeletable(*ptr,
626 XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
627 FALSE);
628 XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL);
629 XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
630 XA_INTEGER, 8, PropModeReplace, 1, &dummy,
631 FALSE);
632 XISetDevicePropertyDeletable(*keybd,
633 XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
634 FALSE);
635 XIRegisterPropertyHandler(*keybd, DeviceSetXTestProperty, NULL, NULL);
636 }
637
638 free(xtestname);
639
640 return retval;
641 }
642
643 /**
644 * If master is NULL, return TRUE if the given device is an xtest device or
645 * FALSE otherwise.
646 * If master is not NULL, return TRUE if the given device is this master's
647 * xtest device.
648 */
649 BOOL
IsXTestDevice(DeviceIntPtr dev,DeviceIntPtr master)650 IsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master)
651 {
652 if (IsMaster(dev))
653 return FALSE;
654
655 /* deviceid 0 is reserved for XIAllDevices, non-zero mid means XTest
656 * device */
657 if (master)
658 return dev->xtest_master_id == master->id;
659
660 return dev->xtest_master_id != 0;
661 }
662
663 /**
664 * @return The X Test virtual device for the given master.
665 */
666 DeviceIntPtr
GetXTestDevice(DeviceIntPtr master)667 GetXTestDevice(DeviceIntPtr master)
668 {
669 DeviceIntPtr it;
670
671 for (it = inputInfo.devices; it; it = it->next) {
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
680 static void
XTestExtensionTearDown(ExtensionEntry * e)681 XTestExtensionTearDown(ExtensionEntry * e)
682 {
683 FreeEventList(xtest_evlist, GetMaximumEventsNum());
684 xtest_evlist = NULL;
685 }
686
687 void
XTestExtensionInit(void)688 XTestExtensionInit(void)
689 {
690 AddExtension(XTestExtensionName, 0, 0,
691 ProcXTestDispatch, SProcXTestDispatch,
692 XTestExtensionTearDown, StandardMinorOpcode);
693
694 xtest_evlist = InitEventList(GetMaximumEventsNum());
695 }
696