xtest.c revision 05b261ec
1/*
2
3Copyright 1992, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from 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#define NEED_EVENTS
35#include <X11/Xproto.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#define _XTEST_SERVER_
46#include <X11/extensions/XTest.h>
47#include <X11/extensions/xteststr.h>
48#ifdef XINPUT
49#include <X11/extensions/XI.h>
50#include <X11/extensions/XIproto.h>
51#define EXTENSION_EVENT_BASE	64
52#include "extinit.h"		/* LookupDeviceIntRec */
53#endif /* XINPUT */
54
55#include "modinit.h"
56
57#if 0
58static unsigned char XTestReqCode;
59#endif
60
61#ifdef XINPUT
62extern int DeviceValuator;
63#endif /* XINPUT */
64
65#ifdef PANORAMIX
66#include "panoramiX.h"
67#include "panoramiXsrv.h"
68#endif
69
70static void XTestResetProc(
71    ExtensionEntry * /* extEntry */
72);
73static int XTestSwapFakeInput(
74    ClientPtr /* client */,
75    xReq * /* req */
76);
77
78static DISPATCH_PROC(ProcXTestCompareCursor);
79static DISPATCH_PROC(ProcXTestDispatch);
80static DISPATCH_PROC(ProcXTestFakeInput);
81static DISPATCH_PROC(ProcXTestGetVersion);
82static DISPATCH_PROC(ProcXTestGrabControl);
83static DISPATCH_PROC(SProcXTestCompareCursor);
84static DISPATCH_PROC(SProcXTestDispatch);
85static DISPATCH_PROC(SProcXTestFakeInput);
86static DISPATCH_PROC(SProcXTestGetVersion);
87static DISPATCH_PROC(SProcXTestGrabControl);
88
89void
90XTestExtensionInit(INITARGS)
91{
92#if 0
93    ExtensionEntry *extEntry;
94
95    if ((extEntry = AddExtension(XTestExtensionName, 0, 0,
96				 ProcXTestDispatch, SProcXTestDispatch,
97				 XTestResetProc, StandardMinorOpcode)) != 0)
98	XTestReqCode = (unsigned char)extEntry->base;
99#else
100    (void) AddExtension(XTestExtensionName, 0, 0,
101			ProcXTestDispatch, SProcXTestDispatch,
102			XTestResetProc, StandardMinorOpcode);
103#endif
104}
105
106/*ARGSUSED*/
107static void
108XTestResetProc (extEntry)
109ExtensionEntry	*extEntry;
110{
111}
112
113static int
114ProcXTestGetVersion(client)
115    register ClientPtr client;
116{
117    xXTestGetVersionReply rep;
118    register int n;
119
120    REQUEST_SIZE_MATCH(xXTestGetVersionReq);
121    rep.type = X_Reply;
122    rep.length = 0;
123    rep.sequenceNumber = client->sequence;
124    rep.majorVersion = XTestMajorVersion;
125    rep.minorVersion = XTestMinorVersion;
126    if (client->swapped) {
127    	swaps(&rep.sequenceNumber, n);
128	swaps(&rep.minorVersion, n);
129    }
130    WriteToClient(client, sizeof(xXTestGetVersionReply), (char *)&rep);
131    return(client->noClientException);
132}
133
134static int
135ProcXTestCompareCursor(client)
136    register ClientPtr client;
137{
138    REQUEST(xXTestCompareCursorReq);
139    xXTestCompareCursorReply rep;
140    WindowPtr pWin;
141    CursorPtr pCursor;
142    register int n, rc;
143
144    REQUEST_SIZE_MATCH(xXTestCompareCursorReq);
145    rc = dixLookupWindow(&pWin, stuff->window, client, DixUnknownAccess);
146    if (rc != Success)
147        return rc;
148    if (stuff->cursor == None)
149	pCursor = NullCursor;
150    else if (stuff->cursor == XTestCurrentCursor)
151	pCursor = GetSpriteCursor();
152    else {
153	pCursor = (CursorPtr)LookupIDByType(stuff->cursor, RT_CURSOR);
154	if (!pCursor)
155	{
156	    client->errorValue = stuff->cursor;
157	    return (BadCursor);
158	}
159    }
160    rep.type = X_Reply;
161    rep.length = 0;
162    rep.sequenceNumber = client->sequence;
163    rep.same = (wCursor(pWin) == pCursor);
164    if (client->swapped) {
165    	swaps(&rep.sequenceNumber, n);
166    }
167    WriteToClient(client, sizeof(xXTestCompareCursorReply), (char *)&rep);
168    return(client->noClientException);
169}
170
171static int
172ProcXTestFakeInput(client)
173    register ClientPtr client;
174{
175    REQUEST(xXTestFakeInputReq);
176    int nev, n, type, rc;
177    xEvent *ev;
178    DeviceIntPtr dev = NULL;
179    WindowPtr root;
180#ifdef XINPUT
181    Bool extension = FALSE;
182    deviceValuator *dv = NULL;
183    int base;
184    int *values;
185#endif /* XINPUT */
186
187    nev = (stuff->length << 2) - sizeof(xReq);
188    if ((nev % sizeof(xEvent)) || !nev)
189	return BadLength;
190    nev /= sizeof(xEvent);
191    UpdateCurrentTime();
192    ev = (xEvent *)&((xReq *)stuff)[1];
193    type = ev->u.u.type & 0177;
194#ifdef XINPUT
195    if (type >= EXTENSION_EVENT_BASE)
196    {
197	type -= DeviceValuator;
198	switch (type) {
199	case XI_DeviceKeyPress:
200	case XI_DeviceKeyRelease:
201	case XI_DeviceButtonPress:
202	case XI_DeviceButtonRelease:
203	case XI_DeviceMotionNotify:
204	case XI_ProximityIn:
205	case XI_ProximityOut:
206	    break;
207	default:
208	    client->errorValue = ev->u.u.type;
209	    return BadValue;
210	}
211	if (nev == 1 && type == XI_DeviceMotionNotify)
212	    return BadLength;
213	if (type == XI_DeviceMotionNotify)
214	    base = ((deviceValuator *)(ev+1))->first_valuator;
215	else
216	    base = 0;
217	for (n = 1; n < nev; n++)
218	{
219	    dv = (deviceValuator *)(ev + n);
220	    if (dv->type != DeviceValuator)
221	    {
222		client->errorValue = dv->type;
223		return BadValue;
224	    }
225	    if (dv->first_valuator != base)
226	    {
227		client->errorValue = dv->first_valuator;
228		return BadValue;
229	    }
230	    if (!dv->num_valuators || dv->num_valuators > 6)
231	    {
232		client->errorValue = dv->num_valuators;
233		return BadValue;
234	    }
235	    base += dv->num_valuators;
236	}
237	type = type - XI_DeviceKeyPress + KeyPress;
238	extension = TRUE;
239    }
240    else
241#endif /* XINPUT */
242    {
243	if (nev != 1)
244	    return BadLength;
245	switch (type)
246	{
247	case KeyPress:
248	case KeyRelease:
249	case MotionNotify:
250	case ButtonPress:
251	case ButtonRelease:
252	    break;
253	default:
254	    client->errorValue = ev->u.u.type;
255	    return BadValue;
256	}
257    }
258    if (ev->u.keyButtonPointer.time)
259    {
260	TimeStamp activateTime;
261	CARD32 ms;
262
263	activateTime = currentTime;
264	ms = activateTime.milliseconds + ev->u.keyButtonPointer.time;
265	if (ms < activateTime.milliseconds)
266	    activateTime.months++;
267	activateTime.milliseconds = ms;
268	ev->u.keyButtonPointer.time = 0;
269
270	/* see mbuf.c:QueueDisplayRequest for code similar to this */
271
272	if (!ClientSleepUntil(client, &activateTime, NULL, NULL))
273	{
274	    return BadAlloc;
275	}
276	/* swap the request back so we can simply re-execute it */
277	if (client->swapped)
278	{
279    	    (void) XTestSwapFakeInput(client, (xReq *)stuff);
280	    swaps(&stuff->length, n);
281	}
282	ResetCurrentRequest (client);
283	client->sequence--;
284	return Success;
285    }
286#ifdef XINPUT
287    if (extension)
288    {
289	dev = LookupDeviceIntRec(stuff->deviceid & 0177);
290	if (!dev)
291	{
292	    client->errorValue = stuff->deviceid & 0177;
293	    return BadValue;
294	}
295	if (nev > 1)
296	{
297	    dv = (deviceValuator *)(ev + 1);
298	    if (!dev->valuator || dv->first_valuator >= dev->valuator->numAxes)
299	    {
300		client->errorValue = dv->first_valuator;
301		return BadValue;
302	    }
303	    if (dv->first_valuator + dv->num_valuators >
304		dev->valuator->numAxes)
305	    {
306		client->errorValue = dv->num_valuators;
307		return BadValue;
308	    }
309	}
310    }
311#endif /* XINPUT */
312    switch (type)
313    {
314    case KeyPress:
315    case KeyRelease:
316#ifdef XINPUT
317	if (!extension)
318#endif /* XINPUT */
319	    dev = (DeviceIntPtr)LookupKeyboardDevice();
320	if (ev->u.u.detail < dev->key->curKeySyms.minKeyCode ||
321	    ev->u.u.detail > dev->key->curKeySyms.maxKeyCode)
322	{
323	    client->errorValue = ev->u.u.detail;
324	    return BadValue;
325	}
326	break;
327    case MotionNotify:
328#ifdef XINPUT
329	if (extension)
330	{
331	    if (ev->u.u.detail != xFalse && ev->u.u.detail != xTrue)
332	    {
333		client->errorValue = ev->u.u.detail;
334		return BadValue;
335	    }
336	    if (ev->u.u.detail == xTrue && dev->valuator->mode == Absolute)
337	    {
338		values = dev->valuator->axisVal + dv->first_valuator;
339		for (n = 1; n < nev; n++)
340		{
341		    dv = (deviceValuator *)(ev + n);
342		    switch (dv->num_valuators)
343		    {
344		    case 6:
345			dv->valuator5 += values[5];
346		    case 5:
347			dv->valuator4 += values[4];
348		    case 4:
349			dv->valuator3 += values[3];
350		    case 3:
351			dv->valuator2 += values[2];
352		    case 2:
353			dv->valuator1 += values[1];
354		    case 1:
355			dv->valuator0 += values[0];
356		    }
357		    values += 6;
358		}
359	    }
360	    break;
361	}
362#endif /* XINPUT */
363	dev = (DeviceIntPtr)LookupPointerDevice();
364	if (ev->u.keyButtonPointer.root == None)
365	    root = GetCurrentRootWindow();
366	else
367	{
368	    rc = dixLookupWindow(&root, ev->u.keyButtonPointer.root, client,
369				 DixUnknownAccess);
370	    if (rc != Success)
371		return rc;
372	    if (root->parent)
373	    {
374		client->errorValue = ev->u.keyButtonPointer.root;
375		return BadValue;
376	    }
377	}
378	if (ev->u.u.detail == xTrue)
379	{
380	    int x, y;
381	    GetSpritePosition(&x, &y);
382	    ev->u.keyButtonPointer.rootX += x;
383	    ev->u.keyButtonPointer.rootY += y;
384	}
385	else if (ev->u.u.detail != xFalse)
386	{
387	    client->errorValue = ev->u.u.detail;
388	    return BadValue;
389	}
390
391#ifdef PANORAMIX
392	if (!noPanoramiXExtension) {
393	    ScreenPtr pScreen = root->drawable.pScreen;
394	    BoxRec    box;
395	    int       i;
396	    int       x = ev->u.keyButtonPointer.rootX + panoramiXdataPtr[0].x;
397	    int       y = ev->u.keyButtonPointer.rootY + panoramiXdataPtr[0].y;
398	    if (!POINT_IN_REGION(pScreen, &XineramaScreenRegions[pScreen->myNum],
399				 x, y, &box)) {
400		FOR_NSCREENS(i) {
401		    if (i == pScreen->myNum) continue;
402		    if (POINT_IN_REGION(pScreen,
403					&XineramaScreenRegions[i],
404					x, y, &box)) {
405			root = WindowTable[i];
406			x   -= panoramiXdataPtr[i].x;
407			y   -= panoramiXdataPtr[i].y;
408			ev->u.keyButtonPointer.rootX = x;
409			ev->u.keyButtonPointer.rootY = y;
410			break;
411		    }
412		}
413	    }
414	}
415#endif
416
417	if (ev->u.keyButtonPointer.rootX < 0)
418	    ev->u.keyButtonPointer.rootX = 0;
419	else if (ev->u.keyButtonPointer.rootX >= root->drawable.width)
420	    ev->u.keyButtonPointer.rootX = root->drawable.width - 1;
421	if (ev->u.keyButtonPointer.rootY < 0)
422	    ev->u.keyButtonPointer.rootY = 0;
423	else if (ev->u.keyButtonPointer.rootY >= root->drawable.height)
424	    ev->u.keyButtonPointer.rootY = root->drawable.height - 1;
425
426#ifdef PANORAMIX
427	if ((!noPanoramiXExtension
428	     && root->drawable.pScreen->myNum != XineramaGetCursorScreen())
429	    || (noPanoramiXExtension && root != GetCurrentRootWindow()))
430
431#else
432	if (root != GetCurrentRootWindow())
433#endif
434	{
435	    NewCurrentScreen(root->drawable.pScreen,
436			     ev->u.keyButtonPointer.rootX,
437			     ev->u.keyButtonPointer.rootY);
438	    return client->noClientException;
439	}
440	(*root->drawable.pScreen->SetCursorPosition)
441	    (root->drawable.pScreen,
442	     ev->u.keyButtonPointer.rootX,
443	     ev->u.keyButtonPointer.rootY, FALSE);
444        dev->valuator->lastx = ev->u.keyButtonPointer.rootX;
445        dev->valuator->lasty = ev->u.keyButtonPointer.rootY;
446	break;
447    case ButtonPress:
448    case ButtonRelease:
449#ifdef XINPUT
450	if (!extension)
451#endif /* XINPUT */
452	    dev = (DeviceIntPtr)LookupPointerDevice();
453	if (!ev->u.u.detail || ev->u.u.detail > dev->button->numButtons)
454	{
455	    client->errorValue = ev->u.u.detail;
456	    return BadValue;
457	}
458	break;
459    }
460    if (screenIsSaved == SCREEN_SAVER_ON)
461	SaveScreens(SCREEN_SAVER_OFF, ScreenSaverReset);
462    ev->u.keyButtonPointer.time = currentTime.milliseconds;
463    (*dev->public.processInputProc)(ev, dev, nev);
464    return client->noClientException;
465}
466
467static int
468ProcXTestGrabControl(client)
469    register ClientPtr client;
470{
471    REQUEST(xXTestGrabControlReq);
472
473    REQUEST_SIZE_MATCH(xXTestGrabControlReq);
474    if ((stuff->impervious != xTrue) && (stuff->impervious != xFalse))
475    {
476	client->errorValue = stuff->impervious;
477        return(BadValue);
478    }
479    if (stuff->impervious)
480	MakeClientGrabImpervious(client);
481    else
482	MakeClientGrabPervious(client);
483    return(client->noClientException);
484}
485
486static int
487ProcXTestDispatch (client)
488    register ClientPtr	client;
489{
490    REQUEST(xReq);
491    switch (stuff->data)
492    {
493    case X_XTestGetVersion:
494	return ProcXTestGetVersion(client);
495    case X_XTestCompareCursor:
496	return ProcXTestCompareCursor(client);
497    case X_XTestFakeInput:
498	return ProcXTestFakeInput(client);
499    case X_XTestGrabControl:
500	return ProcXTestGrabControl(client);
501    default:
502	return BadRequest;
503    }
504}
505
506static int
507SProcXTestGetVersion(client)
508    register ClientPtr	client;
509{
510    register int n;
511    REQUEST(xXTestGetVersionReq);
512
513    swaps(&stuff->length, n);
514    REQUEST_SIZE_MATCH(xXTestGetVersionReq);
515    swaps(&stuff->minorVersion, n);
516    return ProcXTestGetVersion(client);
517}
518
519static int
520SProcXTestCompareCursor(client)
521    register ClientPtr	client;
522{
523    register int n;
524    REQUEST(xXTestCompareCursorReq);
525
526    swaps(&stuff->length, n);
527    REQUEST_SIZE_MATCH(xXTestCompareCursorReq);
528    swapl(&stuff->window, n);
529    swapl(&stuff->cursor, n);
530    return ProcXTestCompareCursor(client);
531}
532
533static int
534XTestSwapFakeInput(client, req)
535    register ClientPtr	client;
536    xReq *req;
537{
538    register int nev;
539    register xEvent *ev;
540    xEvent sev;
541    EventSwapPtr proc;
542
543    nev = ((req->length << 2) - sizeof(xReq)) / sizeof(xEvent);
544    for (ev = (xEvent *)&req[1]; --nev >= 0; ev++)
545    {
546    	/* Swap event */
547    	proc = EventSwapVector[ev->u.u.type & 0177];
548	/* no swapping proc; invalid event type? */
549    	if (!proc ||  proc ==  NotImplemented) {
550	    client->errorValue = ev->u.u.type;
551	    return BadValue;
552	}
553    	(*proc)(ev, &sev);
554	*ev = sev;
555    }
556    return Success;
557}
558
559static int
560SProcXTestFakeInput(client)
561    register ClientPtr	client;
562{
563    register int n;
564    REQUEST(xReq);
565
566    swaps(&stuff->length, n);
567    n = XTestSwapFakeInput(client, stuff);
568    if (n != Success)
569	return n;
570    return ProcXTestFakeInput(client);
571}
572
573static int
574SProcXTestGrabControl(client)
575    register ClientPtr	client;
576{
577    register int n;
578    REQUEST(xXTestGrabControlReq);
579
580    swaps(&stuff->length, n);
581    REQUEST_SIZE_MATCH(xXTestGrabControlReq);
582    return ProcXTestGrabControl(client);
583}
584
585static int
586SProcXTestDispatch (client)
587    register ClientPtr	client;
588{
589    REQUEST(xReq);
590    switch (stuff->data)
591    {
592    case X_XTestGetVersion:
593	return SProcXTestGetVersion(client);
594    case X_XTestCompareCursor:
595	return SProcXTestCompareCursor(client);
596    case X_XTestFakeInput:
597	return SProcXTestFakeInput(client);
598    case X_XTestGrabControl:
599	return SProcXTestGrabControl(client);
600    default:
601	return BadRequest;
602    }
603}
604