Imported Upstream version 1.15.1
[deb_xorg-server.git] / Xext / xtest.c
... / ...
CommitLineData
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 */
63static 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 */
75DeviceIntPtr xtestpointer, xtestkeyboard;
76
77#ifdef PANORAMIX
78#include "panoramiX.h"
79#include "panoramiXsrv.h"
80#endif
81
82static int XTestSwapFakeInput(ClientPtr /* client */ ,
83 xReq * /* req */
84 );
85
86static int
87ProcXTestGetVersion(ClientPtr client)
88{
89 xXTestGetVersionReply rep = {
90 .type = X_Reply,
91 .sequenceNumber = client->sequence,
92 .length = 0,
93 .majorVersion = XTestMajorVersion,
94 .minorVersion = XTestMinorVersion
95 };
96
97 REQUEST_SIZE_MATCH(xXTestGetVersionReq);
98
99 if (client->swapped) {
100 swaps(&rep.sequenceNumber);
101 swaps(&rep.minorVersion);
102 }
103 WriteToClient(client, sizeof(xXTestGetVersionReply), &rep);
104 return Success;
105}
106
107static int
108ProcXTestCompareCursor(ClientPtr client)
109{
110 REQUEST(xXTestCompareCursorReq);
111 xXTestCompareCursorReply rep;
112 WindowPtr pWin;
113 CursorPtr pCursor;
114 int rc;
115 DeviceIntPtr ptr = PickPointer(client);
116
117 REQUEST_SIZE_MATCH(xXTestCompareCursorReq);
118 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
119 if (rc != Success)
120 return rc;
121
122 if (!ptr)
123 return BadAccess;
124
125 if (stuff->cursor == None)
126 pCursor = NullCursor;
127 else if (stuff->cursor == XTestCurrentCursor)
128 pCursor = GetSpriteCursor(ptr);
129 else {
130 rc = dixLookupResourceByType((pointer *) &pCursor, stuff->cursor,
131 RT_CURSOR, client, DixReadAccess);
132 if (rc != Success) {
133 client->errorValue = stuff->cursor;
134 return rc;
135 }
136 }
137 rep = (xXTestCompareCursorReply) {
138 .type = X_Reply,
139 .sequenceNumber = client->sequence,
140 .length = 0,
141 .same = (wCursor(pWin) == pCursor)
142 };
143 if (client->swapped) {
144 swaps(&rep.sequenceNumber);
145 }
146 WriteToClient(client, sizeof(xXTestCompareCursorReply), &rep);
147 return Success;
148}
149
150static int
151ProcXTestFakeInput(ClientPtr client)
152{
153 REQUEST(xXTestFakeInputReq);
154 int nev, n, type, rc;
155 xEvent *ev;
156 DeviceIntPtr dev = NULL;
157 WindowPtr root;
158 Bool extension = FALSE;
159 ValuatorMask mask;
160 int valuators[MAX_VALUATORS] = { 0 };
161 int numValuators = 0;
162 int firstValuator = 0;
163 int nevents = 0;
164 int i;
165 int base = 0;
166 int flags = 0;
167 int need_ptr_update = 1;
168
169 nev = (stuff->length << 2) - sizeof(xReq);
170 if ((nev % sizeof(xEvent)) || !nev)
171 return BadLength;
172 nev /= sizeof(xEvent);
173 UpdateCurrentTime();
174 ev = (xEvent *) &((xReq *) stuff)[1];
175 type = ev->u.u.type & 0177;
176
177 if (type >= EXTENSION_EVENT_BASE) {
178 extension = TRUE;
179
180 /* check device */
181 rc = dixLookupDevice(&dev, stuff->deviceid & 0177, client,
182 DixWriteAccess);
183 if (rc != Success) {
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 client->errorValue = ev->u.u.type;
195 return BadValue;
196 }
197 break;
198 case XI_DeviceButtonPress:
199 case XI_DeviceButtonRelease:
200 if (!dev->button) {
201 client->errorValue = ev->u.u.type;
202 return BadValue;
203 }
204 break;
205 case XI_DeviceMotionNotify:
206 if (!dev->valuator) {
207 client->errorValue = ev->u.u.type;
208 return BadValue;
209 }
210 break;
211 case XI_ProximityIn:
212 case XI_ProximityOut:
213 if (!dev->proximity) {
214 client->errorValue = ev->u.u.type;
215 return BadValue;
216 }
217 break;
218 default:
219 client->errorValue = ev->u.u.type;
220 return BadValue;
221 }
222
223 /* check validity */
224 if (nev == 1 && type == XI_DeviceMotionNotify)
225 return BadLength; /* DevMotion must be followed by DevValuator */
226
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;
231 return BadValue;
232 }
233
234 if (ev->u.u.detail == xFalse)
235 flags |= POINTER_ABSOLUTE;
236 }
237 else {
238 firstValuator = 0;
239 flags |= POINTER_ABSOLUTE;
240 }
241
242 if (nev > 1 && !dev->valuator) {
243 client->errorValue = firstValuator;
244 return BadValue;
245 }
246
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;
253 return BadValue;
254 }
255 if (dv->first_valuator != base) {
256 client->errorValue = dv->first_valuator;
257 return BadValue;
258 }
259 switch (dv->num_valuators) {
260 case 6:
261 valuators[base + 5] = dv->valuator5;
262 case 5:
263 valuators[base + 4] = dv->valuator4;
264 case 4:
265 valuators[base + 3] = dv->valuator3;
266 case 3:
267 valuators[base + 2] = dv->valuator2;
268 case 2:
269 valuators[base + 1] = dv->valuator1;
270 case 1:
271 valuators[base] = dv->valuator0;
272 break;
273 default:
274 client->errorValue = dv->num_valuators;
275 return BadValue;
276 }
277
278 base += dv->num_valuators;
279 numValuators += dv->num_valuators;
280
281 if (firstValuator + numValuators > dev->valuator->numAxes) {
282 client->errorValue = dv->num_valuators;
283 return BadValue;
284 }
285 }
286 type = type - XI_DeviceKeyPress + KeyPress;
287
288 }
289 else {
290 if (nev != 1)
291 return BadLength;
292 switch (type) {
293 case KeyPress:
294 case KeyRelease:
295 dev = PickKeyboard(client);
296 break;
297 case ButtonPress:
298 case ButtonRelease:
299 dev = PickPointer(client);
300 break;
301 case MotionNotify:
302 dev = PickPointer(client);
303 valuators[0] = ev->u.keyButtonPointer.rootX;
304 valuators[1] = ev->u.keyButtonPointer.rootY;
305 numValuators = 2;
306 firstValuator = 0;
307 if (ev->u.u.detail == xFalse)
308 flags = POINTER_ABSOLUTE | POINTER_DESKTOP;
309 break;
310 default:
311 client->errorValue = ev->u.u.type;
312 return BadValue;
313 }
314
315 /* Technically the protocol doesn't allow for BadAccess here but
316 * this can only happen when all MDs are disabled. */
317 if (!dev)
318 return BadAccess;
319
320 dev = GetXTestDevice(dev);
321 }
322
323
324 /* If the event has a time set, wait for it to pass */
325 if (ev->u.keyButtonPointer.time) {
326 TimeStamp activateTime;
327 CARD32 ms;
328
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;
335
336 /* see mbuf.c:QueueDisplayRequest (from the deprecated Multibuffer
337 * extension) for code similar to this */
338
339 if (!ClientSleepUntil(client, &activateTime, NULL, NULL)) {
340 return BadAlloc;
341 }
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);
346 }
347 ResetCurrentRequest(client);
348 client->sequence--;
349 return Success;
350 }
351
352 switch (type) {
353 case KeyPress:
354 case KeyRelease:
355 if (!dev->key)
356 return BadDevice;
357
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;
361 return BadValue;
362 }
363
364 need_ptr_update = 0;
365 break;
366 case MotionNotify:
367 if (!dev->valuator)
368 return BadDevice;
369
370 if (!(extension || ev->u.keyButtonPointer.root == None)) {
371 rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root,
372 client, DixGetAttrAccess);
373 if (rc != Success)
374 return rc;
375 if (root->parent) {
376 client->errorValue = ev->u.keyButtonPointer.root;
377 return BadValue;
378 }
379
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;
386 }
387 }
388 if (ev->u.u.detail != xTrue && ev->u.u.detail != xFalse) {
389 client->errorValue = ev->u.u.detail;
390 return BadValue;
391 }
392
393 /* FIXME: Xinerama! */
394
395 break;
396 case ButtonPress:
397 case ButtonRelease:
398 if (!dev->button)
399 return BadDevice;
400
401 if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons) {
402 client->errorValue = ev->u.u.detail;
403 return BadValue;
404 }
405 break;
406 }
407 if (screenIsSaved == SCREEN_SAVER_ON)
408 dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset);
409
410 switch (type) {
411 case MotionNotify:
412 valuator_mask_set_range(&mask, firstValuator, numValuators, valuators);
413 nevents = GetPointerEvents(xtest_evlist, dev, type, 0, flags, &mask);
414 break;
415 case ButtonPress:
416 case ButtonRelease:
417 valuator_mask_set_range(&mask, firstValuator, numValuators, valuators);
418 nevents = GetPointerEvents(xtest_evlist, dev, type, ev->u.u.detail,
419 flags, &mask);
420 break;
421 case KeyPress:
422 case KeyRelease:
423 nevents =
424 GetKeyboardEvents(xtest_evlist, dev, type, ev->u.u.detail, NULL);
425 break;
426 }
427
428 for (i = 0; i < nevents; i++)
429 mieqProcessDeviceEvent(dev, &xtest_evlist[i], miPointerGetScreen(inputInfo.pointer));
430
431 if (need_ptr_update)
432 miPointerUpdateSprite(dev);
433 return Success;
434}
435
436static int
437ProcXTestGrabControl(ClientPtr client)
438{
439 REQUEST(xXTestGrabControlReq);
440
441 REQUEST_SIZE_MATCH(xXTestGrabControlReq);
442 if ((stuff->impervious != xTrue) && (stuff->impervious != xFalse)) {
443 client->errorValue = stuff->impervious;
444 return BadValue;
445 }
446 if (stuff->impervious)
447 MakeClientGrabImpervious(client);
448 else
449 MakeClientGrabPervious(client);
450 return Success;
451}
452
453static int
454ProcXTestDispatch(ClientPtr client)
455{
456 REQUEST(xReq);
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);
466 default:
467 return BadRequest;
468 }
469}
470
471static int
472SProcXTestGetVersion(ClientPtr client)
473{
474 REQUEST(xXTestGetVersionReq);
475
476 swaps(&stuff->length);
477 REQUEST_SIZE_MATCH(xXTestGetVersionReq);
478 swaps(&stuff->minorVersion);
479 return ProcXTestGetVersion(client);
480}
481
482static int
483SProcXTestCompareCursor(ClientPtr client)
484{
485 REQUEST(xXTestCompareCursorReq);
486
487 swaps(&stuff->length);
488 REQUEST_SIZE_MATCH(xXTestCompareCursorReq);
489 swapl(&stuff->window);
490 swapl(&stuff->cursor);
491 return ProcXTestCompareCursor(client);
492}
493
494static int
495XTestSwapFakeInput(ClientPtr client, xReq * req)
496{
497 int nev;
498 xEvent *ev;
499 xEvent sev;
500 EventSwapPtr proc;
501
502 nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent);
503 for (ev = (xEvent *) &req[1]; --nev >= 0; ev++) {
504 /* Swap event */
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;
509 return BadValue;
510 }
511 (*proc) (ev, &sev);
512 *ev = sev;
513 }
514 return Success;
515}
516
517static int
518SProcXTestFakeInput(ClientPtr client)
519{
520 int n;
521
522 REQUEST(xReq);
523
524 swaps(&stuff->length);
525 n = XTestSwapFakeInput(client, stuff);
526 if (n != Success)
527 return n;
528 return ProcXTestFakeInput(client);
529}
530
531static int
532SProcXTestGrabControl(ClientPtr client)
533{
534 REQUEST(xXTestGrabControlReq);
535
536 swaps(&stuff->length);
537 REQUEST_SIZE_MATCH(xXTestGrabControlReq);
538 return ProcXTestGrabControl(client);
539}
540
541static int
542SProcXTestDispatch(ClientPtr client)
543{
544 REQUEST(xReq);
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);
554 default:
555 return BadRequest;
556 }
557}
558
559/**
560 * Allocate an virtual slave device for xtest events, this
561 * is a slave device to inputInfo master devices
562 */
563void
564InitXTestDevices(void)
565{
566 if (AllocXTestDevice(serverClient, "Virtual core",
567 &xtestpointer, &xtestkeyboard,
568 inputInfo.pointer, inputInfo.keyboard) != Success)
569 FatalError("Failed to allocate XTest devices");
570
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.");
576
577 AttachDevice(NULL, xtestpointer, inputInfo.pointer);
578
579 AttachDevice(NULL, xtestkeyboard, inputInfo.keyboard);
580}
581
582/**
583 * Don't allow changing the XTest property.
584 */
585static int
586DeviceSetXTestProperty(DeviceIntPtr dev, Atom property,
587 XIPropertyValuePtr prop, BOOL checkonly)
588{
589 if (property == XIGetKnownProperty(XI_PROP_XTEST_DEVICE))
590 return BadAccess;
591
592 return Success;
593}
594
595/**
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.
601 */
602int
603AllocXTestDevice(ClientPtr client, const char *name,
604 DeviceIntPtr *ptr, DeviceIntPtr *keybd,
605 DeviceIntPtr master_ptr, DeviceIntPtr master_keybd)
606{
607 int retval;
608 char *xtestname;
609 char dummy = 1;
610
611 if (asprintf(&xtestname, "%s XTEST", name) == -1)
612 return BadAlloc;
613
614 retval =
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;
620
621 XIChangeDeviceProperty(*ptr, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
622 XA_INTEGER, 8, PropModeReplace, 1, &dummy,
623 FALSE);
624 XISetDevicePropertyDeletable(*ptr,
625 XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
626 FALSE);
627 XIRegisterPropertyHandler(*ptr, DeviceSetXTestProperty, NULL, NULL);
628 XIChangeDeviceProperty(*keybd, XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
629 XA_INTEGER, 8, PropModeReplace, 1, &dummy,
630 FALSE);
631 XISetDevicePropertyDeletable(*keybd,
632 XIGetKnownProperty(XI_PROP_XTEST_DEVICE),
633 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 if (IsXTestDevice(it, master))
672 return it;
673 }
674
675 /* This only happens if master is a slave device. don't do that */
676 return NULL;
677}
678
679static void
680XTestExtensionTearDown(ExtensionEntry * e)
681{
682 FreeEventList(xtest_evlist, GetMaximumEventsNum());
683 xtest_evlist = NULL;
684}
685
686void
687XTestExtensionInit(void)
688{
689 AddExtension(XTestExtensionName, 0, 0,
690 ProcXTestDispatch, SProcXTestDispatch,
691 XTestExtensionTearDown, StandardMinorOpcode);
692
693 xtest_evlist = InitEventList(GetMaximumEventsNum());
694}