xref: /OK3568_Linux_fs/external/xserver/hw/dmx/input/dmxbackend.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * All Rights Reserved.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining
7*4882a593Smuzhiyun  * a copy of this software and associated documentation files (the
8*4882a593Smuzhiyun  * "Software"), to deal in the Software without restriction, including
9*4882a593Smuzhiyun  * without limitation on the rights to use, copy, modify, merge,
10*4882a593Smuzhiyun  * publish, distribute, sublicense, and/or sell copies of the Software,
11*4882a593Smuzhiyun  * and to permit persons to whom the Software is furnished to do so,
12*4882a593Smuzhiyun  * subject to the following conditions:
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * The above copyright notice and this permission notice (including the
15*4882a593Smuzhiyun  * next paragraph) shall be included in all copies or substantial
16*4882a593Smuzhiyun  * portions of the Software.
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19*4882a593Smuzhiyun  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20*4882a593Smuzhiyun  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21*4882a593Smuzhiyun  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22*4882a593Smuzhiyun  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23*4882a593Smuzhiyun  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24*4882a593Smuzhiyun  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25*4882a593Smuzhiyun  * SOFTWARE.
26*4882a593Smuzhiyun  */
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun  * Authors:
30*4882a593Smuzhiyun  *   David H. Dawes <dawes@xfree86.org>
31*4882a593Smuzhiyun  *   Kevin E. Martin <kem@redhat.com>
32*4882a593Smuzhiyun  *   Rickard E. (Rik) Faith <faith@redhat.com>
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /** \file
36*4882a593Smuzhiyun  * These routines support taking input from devices on the backend
37*4882a593Smuzhiyun  * (output) displays.  \see dmxcommon.c. */
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #ifdef HAVE_DMX_CONFIG_H
40*4882a593Smuzhiyun #include <dmx-config.h>
41*4882a593Smuzhiyun #endif
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define DMX_BACKEND_DEBUG 0
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #include "dmxinputinit.h"
46*4882a593Smuzhiyun #include "dmxbackend.h"
47*4882a593Smuzhiyun #include "dmxcommon.h"
48*4882a593Smuzhiyun #include "dmxconsole.h"
49*4882a593Smuzhiyun #include "dmxcursor.h"
50*4882a593Smuzhiyun #include "dmxprop.h"
51*4882a593Smuzhiyun #include "dmxsync.h"
52*4882a593Smuzhiyun #include "dmxcb.h"              /* For dmxGlobalWidth and dmxGlobalHeight */
53*4882a593Smuzhiyun #include "dmxevents.h"          /* For dmxGetGlobalPosition */
54*4882a593Smuzhiyun #include "ChkNotMaskEv.h"
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #include "inputstr.h"
57*4882a593Smuzhiyun #include "input.h"
58*4882a593Smuzhiyun #include <X11/keysym.h>
59*4882a593Smuzhiyun #include "mipointer.h"
60*4882a593Smuzhiyun #include "scrnintstr.h"
61*4882a593Smuzhiyun #include "windowstr.h"
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun /* Private area for backend devices. */
64*4882a593Smuzhiyun typedef struct _myPrivate {
65*4882a593Smuzhiyun     DMX_COMMON_PRIVATE;
66*4882a593Smuzhiyun     int myScreen;
67*4882a593Smuzhiyun     DMXScreenInfo *grabbedScreen;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun     int lastX, lastY;
70*4882a593Smuzhiyun     int centerX, centerY;
71*4882a593Smuzhiyun     int relative;
72*4882a593Smuzhiyun     int newscreen;
73*4882a593Smuzhiyun     int initialized;
74*4882a593Smuzhiyun     DevicePtr mou, kbd;
75*4882a593Smuzhiyun     int entered;
76*4882a593Smuzhiyun     int offX, offY;
77*4882a593Smuzhiyun } myPrivate;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #if DMX_BACKEND_DEBUG
80*4882a593Smuzhiyun #define DMXDBG0(f)                   dmxLog(dmxDebug,f)
81*4882a593Smuzhiyun #define DMXDBG1(f,a)                 dmxLog(dmxDebug,f,a)
82*4882a593Smuzhiyun #define DMXDBG2(f,a,b)               dmxLog(dmxDebug,f,a,b)
83*4882a593Smuzhiyun #define DMXDBG3(f,a,b,c)             dmxLog(dmxDebug,f,a,b,c)
84*4882a593Smuzhiyun #define DMXDBG4(f,a,b,c,d)           dmxLog(dmxDebug,f,a,b,c,d)
85*4882a593Smuzhiyun #define DMXDBG5(f,a,b,c,d,e)         dmxLog(dmxDebug,f,a,b,c,d,e)
86*4882a593Smuzhiyun #define DMXDBG6(f,a,b,c,d,e,g)       dmxLog(dmxDebug,f,a,b,c,d,e,g)
87*4882a593Smuzhiyun #define DMXDBG7(f,a,b,c,d,e,g,h)     dmxLog(dmxDebug,f,a,b,c,d,e,g,h)
88*4882a593Smuzhiyun #define DMXDBG8(f,a,b,c,d,e,g,h,i)   dmxLog(dmxDebug,f,a,b,c,d,e,g,h,i)
89*4882a593Smuzhiyun #define DMXDBG9(f,a,b,c,d,e,g,h,i,j) dmxLog(dmxDebug,f,a,b,c,d,e,g,h,i,j)
90*4882a593Smuzhiyun #else
91*4882a593Smuzhiyun #define DMXDBG0(f)
92*4882a593Smuzhiyun #define DMXDBG1(f,a)
93*4882a593Smuzhiyun #define DMXDBG2(f,a,b)
94*4882a593Smuzhiyun #define DMXDBG3(f,a,b,c)
95*4882a593Smuzhiyun #define DMXDBG4(f,a,b,c,d)
96*4882a593Smuzhiyun #define DMXDBG5(f,a,b,c,d,e)
97*4882a593Smuzhiyun #define DMXDBG6(f,a,b,c,d,e,g)
98*4882a593Smuzhiyun #define DMXDBG7(f,a,b,c,d,e,g,h)
99*4882a593Smuzhiyun #define DMXDBG8(f,a,b,c,d,e,g,h,i)
100*4882a593Smuzhiyun #define DMXDBG9(f,a,b,c,d,e,g,h,i,j)
101*4882a593Smuzhiyun #endif
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /** Create and return a private data structure. */
104*4882a593Smuzhiyun void *
dmxBackendCreatePrivate(DeviceIntPtr pDevice)105*4882a593Smuzhiyun dmxBackendCreatePrivate(DeviceIntPtr pDevice)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun     GETDMXLOCALFROMPDEVICE;
108*4882a593Smuzhiyun     myPrivate *priv = calloc(1, sizeof(*priv));
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun     priv->dmxLocal = dmxLocal;
111*4882a593Smuzhiyun     return priv;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun /** Destroy the private data structure.  No checking is performed to
115*4882a593Smuzhiyun  * verify that the structure was actually created by
116*4882a593Smuzhiyun  * #dmxBackendCreatePrivate. */
117*4882a593Smuzhiyun void
dmxBackendDestroyPrivate(void * private)118*4882a593Smuzhiyun dmxBackendDestroyPrivate(void *private)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun     free(private);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun static void *
dmxBackendTestScreen(DMXScreenInfo * dmxScreen,void * closure)124*4882a593Smuzhiyun dmxBackendTestScreen(DMXScreenInfo * dmxScreen, void *closure)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun     long target = (long) closure;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun     if (dmxScreen->index == target)
129*4882a593Smuzhiyun         return dmxScreen;
130*4882a593Smuzhiyun     return NULL;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun /* Return non-zero if screen and priv->myScreen are on the same physical
134*4882a593Smuzhiyun  * backend display (1 if they are the same screen, 2 if they are
135*4882a593Smuzhiyun  * different screens).  Since this is a common operation, the results
136*4882a593Smuzhiyun  * are cached.  The cache is invalidated if \a priv is NULL (this should
137*4882a593Smuzhiyun  * be done with each server generation and reconfiguration). */
138*4882a593Smuzhiyun static int
dmxBackendSameDisplay(myPrivate * priv,long screen)139*4882a593Smuzhiyun dmxBackendSameDisplay(myPrivate * priv, long screen)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun     static myPrivate *oldpriv = NULL;
142*4882a593Smuzhiyun     static int oldscreen = -1;
143*4882a593Smuzhiyun     static int retcode = 0;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun     if (priv == oldpriv && screen == oldscreen)
146*4882a593Smuzhiyun         return retcode;
147*4882a593Smuzhiyun     if (!priv) {                /* Invalidate cache */
148*4882a593Smuzhiyun         oldpriv = NULL;
149*4882a593Smuzhiyun         oldscreen = -1;
150*4882a593Smuzhiyun         retcode = 0;
151*4882a593Smuzhiyun         return 0;
152*4882a593Smuzhiyun     }
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun     if (screen == priv->myScreen)
155*4882a593Smuzhiyun         retcode = 1;
156*4882a593Smuzhiyun     else if (screen < 0 || screen >= dmxNumScreens)
157*4882a593Smuzhiyun         retcode = 0;
158*4882a593Smuzhiyun     else if (dmxPropertyIterate(priv->be,
159*4882a593Smuzhiyun                                 dmxBackendTestScreen, (void *) screen))
160*4882a593Smuzhiyun         retcode = 2;
161*4882a593Smuzhiyun     else
162*4882a593Smuzhiyun         retcode = 0;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun     oldpriv = priv;
165*4882a593Smuzhiyun     oldscreen = screen;
166*4882a593Smuzhiyun     return retcode;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun static void *
dmxBackendTestEvents(DMXScreenInfo * dmxScreen,void * closure)170*4882a593Smuzhiyun dmxBackendTestEvents(DMXScreenInfo * dmxScreen, void *closure)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun     XEvent *X = (XEvent *) closure;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun     if (XCheckNotMaskEvent(dmxScreen->beDisplay, ExposureMask, X))
175*4882a593Smuzhiyun         return dmxScreen;
176*4882a593Smuzhiyun     return NULL;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun static void *
dmxBackendTestMotionEvent(DMXScreenInfo * dmxScreen,void * closure)180*4882a593Smuzhiyun dmxBackendTestMotionEvent(DMXScreenInfo * dmxScreen, void *closure)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun     XEvent *X = (XEvent *) closure;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun     if (XCheckTypedEvent(dmxScreen->beDisplay, MotionNotify, X))
185*4882a593Smuzhiyun         return dmxScreen;
186*4882a593Smuzhiyun     return NULL;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun static DMXScreenInfo *
dmxBackendGetEvent(myPrivate * priv,XEvent * X)190*4882a593Smuzhiyun dmxBackendGetEvent(myPrivate * priv, XEvent * X)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun     DMXScreenInfo *dmxScreen;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun     if ((dmxScreen = dmxPropertyIterate(priv->be, dmxBackendTestEvents, X)))
195*4882a593Smuzhiyun         return dmxScreen;
196*4882a593Smuzhiyun     return NULL;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun static DMXScreenInfo *
dmxBackendPendingMotionEvent(myPrivate * priv,int save)200*4882a593Smuzhiyun dmxBackendPendingMotionEvent(myPrivate * priv, int save)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun     DMXScreenInfo *dmxScreen;
203*4882a593Smuzhiyun     XEvent N;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun     if ((dmxScreen = dmxPropertyIterate(priv->be,
206*4882a593Smuzhiyun                                         dmxBackendTestMotionEvent, &N))) {
207*4882a593Smuzhiyun         if (save)
208*4882a593Smuzhiyun             XPutBackEvent(dmxScreen->beDisplay, &N);
209*4882a593Smuzhiyun         return dmxScreen;
210*4882a593Smuzhiyun     }
211*4882a593Smuzhiyun     return NULL;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun static void *
dmxBackendTestWindow(DMXScreenInfo * dmxScreen,void * closure)215*4882a593Smuzhiyun dmxBackendTestWindow(DMXScreenInfo * dmxScreen, void *closure)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun     Window win = (Window) (long) closure;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun     if (dmxScreen->scrnWin == win)
220*4882a593Smuzhiyun         return dmxScreen;
221*4882a593Smuzhiyun     return NULL;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun static DMXScreenInfo *
dmxBackendFindWindow(myPrivate * priv,Window win)225*4882a593Smuzhiyun dmxBackendFindWindow(myPrivate * priv, Window win)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun     return dmxPropertyIterate(priv->be, dmxBackendTestWindow,
228*4882a593Smuzhiyun                               (void *) (long) win);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun /* If the cursor is over a set of overlapping screens and one of those
232*4882a593Smuzhiyun  * screens takes backend input, then we want that particular screen to
233*4882a593Smuzhiyun  * be current, not one of the other ones. */
234*4882a593Smuzhiyun static int
dmxBackendFindOverlapping(myPrivate * priv,int screen,int x,int y)235*4882a593Smuzhiyun dmxBackendFindOverlapping(myPrivate * priv, int screen, int x, int y)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun     DMXScreenInfo *start = &dmxScreens[screen];
238*4882a593Smuzhiyun     DMXScreenInfo *pt;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun     if (!start->over)
241*4882a593Smuzhiyun         return screen;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun     for (pt = start->over; /* condition at end of loop */ ; pt = pt->over) {
244*4882a593Smuzhiyun         if (pt->index == priv->myScreen
245*4882a593Smuzhiyun             && dmxOnScreen(x, y, &dmxScreens[pt->index]))
246*4882a593Smuzhiyun             return pt->index;
247*4882a593Smuzhiyun         if (pt == start)
248*4882a593Smuzhiyun             break;
249*4882a593Smuzhiyun     }
250*4882a593Smuzhiyun     return screen;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun /* Return non-zero if \a x and \a y are off \a screen. */
254*4882a593Smuzhiyun static int
dmxBackendOffscreen(int screen,int x,int y)255*4882a593Smuzhiyun dmxBackendOffscreen(int screen, int x, int y)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun     DMXScreenInfo *dmxScreen = &dmxScreens[screen];
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun     return (!dmxOnScreen(x, y, dmxScreen));
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun /** This routine is called from #dmxCoreMotion for each motion
263*4882a593Smuzhiyun  * event. \a x and \a y are global coordinants. */
264*4882a593Smuzhiyun void
dmxBackendUpdatePosition(void * private,int x,int y)265*4882a593Smuzhiyun dmxBackendUpdatePosition(void *private, int x, int y)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun     GETPRIVFROMPRIVATE;
268*4882a593Smuzhiyun     int screen = miPointerGetScreen(inputInfo.pointer)->myNum;
269*4882a593Smuzhiyun     DMXScreenInfo *dmxScreen = &dmxScreens[priv->myScreen];
270*4882a593Smuzhiyun     int oldRelative = priv->relative;
271*4882a593Smuzhiyun     int topscreen = dmxBackendFindOverlapping(priv, screen, x, y);
272*4882a593Smuzhiyun     int same = dmxBackendSameDisplay(priv, topscreen);
273*4882a593Smuzhiyun     int offscreen = dmxBackendOffscreen(priv->myScreen, x, y);
274*4882a593Smuzhiyun     int offthis = dmxBackendOffscreen(screen, x, y);
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun     DMXDBG9("dmxBackendUpdatePosition(%d,%d) my=%d mi=%d rel=%d"
277*4882a593Smuzhiyun             " topscreen=%d same=%d offscreen=%d offthis=%d\n",
278*4882a593Smuzhiyun             x, y, priv->myScreen, screen, priv->relative,
279*4882a593Smuzhiyun             topscreen, same, offscreen, offthis);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun     if (offscreen) {
282*4882a593Smuzhiyun         /* If the cursor is off the input screen, it should be moving
283*4882a593Smuzhiyun          * relative unless it is visible on a screen of the same display
284*4882a593Smuzhiyun          * (i.e., one that shares the mouse). */
285*4882a593Smuzhiyun         if (same == 2 && !offthis) {
286*4882a593Smuzhiyun             if (priv->relative) {
287*4882a593Smuzhiyun                 DMXDBG0("   Off screen, but not absolute\n");
288*4882a593Smuzhiyun                 priv->relative = 0;
289*4882a593Smuzhiyun             }
290*4882a593Smuzhiyun         }
291*4882a593Smuzhiyun         else {
292*4882a593Smuzhiyun             if (!priv->relative) {
293*4882a593Smuzhiyun                 DMXDBG0("   Off screen, but not relative\n");
294*4882a593Smuzhiyun                 priv->relative = 1;
295*4882a593Smuzhiyun             }
296*4882a593Smuzhiyun         }
297*4882a593Smuzhiyun     }
298*4882a593Smuzhiyun     else {
299*4882a593Smuzhiyun         if (topscreen != screen) {
300*4882a593Smuzhiyun             DMXDBG2("   Using screen %d instead of %d (from mi)\n",
301*4882a593Smuzhiyun                     topscreen, screen);
302*4882a593Smuzhiyun         }
303*4882a593Smuzhiyun         if (same) {
304*4882a593Smuzhiyun             if (priv->relative) {
305*4882a593Smuzhiyun                 DMXDBG0("   On screen, but not absolute\n");
306*4882a593Smuzhiyun                 priv->relative = 0;
307*4882a593Smuzhiyun             }
308*4882a593Smuzhiyun         }
309*4882a593Smuzhiyun         else {
310*4882a593Smuzhiyun             if (!priv->relative) {
311*4882a593Smuzhiyun                 DMXDBG0("   Not on screen, but not relative\n");
312*4882a593Smuzhiyun                 priv->relative = 1;
313*4882a593Smuzhiyun             }
314*4882a593Smuzhiyun         }
315*4882a593Smuzhiyun     }
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun     if (oldRelative != priv->relative) {
318*4882a593Smuzhiyun         DMXDBG2("   Do switch, relative=%d same=%d\n", priv->relative, same);
319*4882a593Smuzhiyun         /* Discard all pre-switch events */
320*4882a593Smuzhiyun         dmxSync(dmxScreen, TRUE);
321*4882a593Smuzhiyun         while (dmxBackendPendingMotionEvent(priv, FALSE));
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun         if (dmxInput->console && offscreen) {
324*4882a593Smuzhiyun             /* Our special case is a console window and a backend window
325*4882a593Smuzhiyun              * share a display.  In this case, the cursor is either on
326*4882a593Smuzhiyun              * the backend window (taking absolute input), or not (in
327*4882a593Smuzhiyun              * which case the cursor needs to be in the console
328*4882a593Smuzhiyun              * window). */
329*4882a593Smuzhiyun             if (priv->grabbedScreen) {
330*4882a593Smuzhiyun                 DMXDBG2("   *** force ungrab on %s, display=%p\n",
331*4882a593Smuzhiyun                         priv->grabbedScreen->name,
332*4882a593Smuzhiyun                         priv->grabbedScreen->beDisplay);
333*4882a593Smuzhiyun                 XUngrabPointer(priv->grabbedScreen->beDisplay, CurrentTime);
334*4882a593Smuzhiyun                 dmxSync(priv->grabbedScreen, TRUE);
335*4882a593Smuzhiyun                 priv->grabbedScreen = NULL;
336*4882a593Smuzhiyun             }
337*4882a593Smuzhiyun             DMXDBG0("   Capturing console\n");
338*4882a593Smuzhiyun             dmxConsoleCapture(dmxInput);
339*4882a593Smuzhiyun         }
340*4882a593Smuzhiyun         else {
341*4882a593Smuzhiyun             priv->newscreen = 1;
342*4882a593Smuzhiyun             if (priv->relative && !dmxInput->console) {
343*4882a593Smuzhiyun                 DMXDBG5("   Hide cursor; warp from %d,%d to %d,%d on %d\n",
344*4882a593Smuzhiyun                         priv->lastX, priv->lastY, priv->centerX, priv->centerY,
345*4882a593Smuzhiyun                         priv->myScreen);
346*4882a593Smuzhiyun                 dmxConsoleUncapture(dmxInput);
347*4882a593Smuzhiyun                 dmxHideCursor(dmxScreen);
348*4882a593Smuzhiyun                 priv->lastX = priv->centerX;
349*4882a593Smuzhiyun                 priv->lastY = priv->centerY;
350*4882a593Smuzhiyun                 XWarpPointer(priv->display, None, priv->window,
351*4882a593Smuzhiyun                              0, 0, 0, 0, priv->lastX, priv->lastY);
352*4882a593Smuzhiyun                 dmxSync(dmxScreen, TRUE);
353*4882a593Smuzhiyun             }
354*4882a593Smuzhiyun             else {
355*4882a593Smuzhiyun                 DMXDBG0("   Check cursor\n");
356*4882a593Smuzhiyun                 dmxCheckCursor();
357*4882a593Smuzhiyun             }
358*4882a593Smuzhiyun         }
359*4882a593Smuzhiyun     }
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun /** Get events from the X queue on the backend servers and put the
363*4882a593Smuzhiyun  * events into the DMX event queue. */
364*4882a593Smuzhiyun void
dmxBackendCollectEvents(DevicePtr pDev,dmxMotionProcPtr motion,dmxEnqueueProcPtr enqueue,dmxCheckSpecialProcPtr checkspecial,DMXBlockType block)365*4882a593Smuzhiyun dmxBackendCollectEvents(DevicePtr pDev,
366*4882a593Smuzhiyun                         dmxMotionProcPtr motion,
367*4882a593Smuzhiyun                         dmxEnqueueProcPtr enqueue,
368*4882a593Smuzhiyun                         dmxCheckSpecialProcPtr checkspecial, DMXBlockType block)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun     GETPRIVFROMPDEV;
371*4882a593Smuzhiyun     GETDMXINPUTFROMPRIV;
372*4882a593Smuzhiyun     XEvent X;
373*4882a593Smuzhiyun     DMXScreenInfo *dmxScreen;
374*4882a593Smuzhiyun     int left = 0;
375*4882a593Smuzhiyun     int entered = priv->entered;
376*4882a593Smuzhiyun     int ignoreLeave = 0;
377*4882a593Smuzhiyun     int v[2];
378*4882a593Smuzhiyun     int retcode;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun     while ((dmxScreen = dmxBackendGetEvent(priv, &X))) {
381*4882a593Smuzhiyun         switch (X.type) {
382*4882a593Smuzhiyun         case EnterNotify:
383*4882a593Smuzhiyun             dmxCommonSaveState(priv);
384*4882a593Smuzhiyun             if (entered++)
385*4882a593Smuzhiyun                 continue;
386*4882a593Smuzhiyun             priv->entered = 1;
387*4882a593Smuzhiyun             ignoreLeave = 1;
388*4882a593Smuzhiyun             DMXDBG5("dmxBackendCollectEvents: Enter %lu %d,%d; GRAB %s %p\n",
389*4882a593Smuzhiyun                     X.xcrossing.root, X.xcrossing.x, X.xcrossing.y,
390*4882a593Smuzhiyun                     dmxScreen->name, dmxScreen->beDisplay);
391*4882a593Smuzhiyun             XRaiseWindow(dmxScreen->beDisplay, dmxScreen->scrnWin);
392*4882a593Smuzhiyun             priv->grabbedScreen = dmxScreen;
393*4882a593Smuzhiyun             if ((retcode = XGrabPointer(dmxScreen->beDisplay,
394*4882a593Smuzhiyun                                         dmxScreen->scrnWin,
395*4882a593Smuzhiyun                                         True, 0, GrabModeAsync,
396*4882a593Smuzhiyun                                         GrabModeAsync, None, None,
397*4882a593Smuzhiyun                                         CurrentTime))) {
398*4882a593Smuzhiyun                 dmxLog(dmxError,
399*4882a593Smuzhiyun                        "XGrabPointer failed during backend enter (%d)\n",
400*4882a593Smuzhiyun                        retcode);
401*4882a593Smuzhiyun             }
402*4882a593Smuzhiyun             break;
403*4882a593Smuzhiyun         case LeaveNotify:
404*4882a593Smuzhiyun             if (ignoreLeave) {
405*4882a593Smuzhiyun                 ignoreLeave = 0;
406*4882a593Smuzhiyun                 continue;
407*4882a593Smuzhiyun             }
408*4882a593Smuzhiyun             dmxCommonRestoreState(priv);
409*4882a593Smuzhiyun             if (left++)
410*4882a593Smuzhiyun                 continue;
411*4882a593Smuzhiyun             DMXDBG7("dmxBackendCollectEvents: Leave %lu %d,%d %d %d %s %s\n",
412*4882a593Smuzhiyun                     X.xcrossing.root, X.xcrossing.x, X.xcrossing.y,
413*4882a593Smuzhiyun                     X.xcrossing.detail, X.xcrossing.focus,
414*4882a593Smuzhiyun                     priv->grabbedScreen ? "UNGRAB" : "", dmxScreen->name);
415*4882a593Smuzhiyun             if (priv->grabbedScreen) {
416*4882a593Smuzhiyun                 XUngrabPointer(priv->grabbedScreen->beDisplay, CurrentTime);
417*4882a593Smuzhiyun                 dmxSync(priv->grabbedScreen, TRUE);
418*4882a593Smuzhiyun                 priv->grabbedScreen = NULL;
419*4882a593Smuzhiyun             }
420*4882a593Smuzhiyun             break;
421*4882a593Smuzhiyun         case MotionNotify:
422*4882a593Smuzhiyun             DMXDBG8("dmxBackendCollectEvents: MotionNotify %d/%d"
423*4882a593Smuzhiyun                     " newscreen=%d: %d %d (e=%d; last=%d,%d)\n",
424*4882a593Smuzhiyun                     dmxScreen->index, priv->myScreen,
425*4882a593Smuzhiyun                     priv->newscreen,
426*4882a593Smuzhiyun                     X.xmotion.x, X.xmotion.y,
427*4882a593Smuzhiyun                     entered, priv->lastX, priv->lastY);
428*4882a593Smuzhiyun             if (dmxBackendPendingMotionEvent(priv, TRUE))
429*4882a593Smuzhiyun                 continue;
430*4882a593Smuzhiyun             if (!(dmxScreen = dmxBackendFindWindow(priv, X.xmotion.window)))
431*4882a593Smuzhiyun                 dmxLog(dmxFatal,
432*4882a593Smuzhiyun                        "   Event on non-existant window %lu\n",
433*4882a593Smuzhiyun                        X.xmotion.window);
434*4882a593Smuzhiyun             if (!priv->relative || dmxInput->console) {
435*4882a593Smuzhiyun                 int newX = X.xmotion.x - dmxScreen->rootX;
436*4882a593Smuzhiyun                 int newY = X.xmotion.y - dmxScreen->rootY;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun                 if (!priv->newscreen) {
439*4882a593Smuzhiyun                     int width = dmxScreen->rootWidth;
440*4882a593Smuzhiyun                     int height = dmxScreen->rootHeight;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun                     if (!newX)
443*4882a593Smuzhiyun                         newX = -1;
444*4882a593Smuzhiyun                     if (newX == width - 1)
445*4882a593Smuzhiyun                         newX = width;
446*4882a593Smuzhiyun                     if (!newY)
447*4882a593Smuzhiyun                         newY = -1;
448*4882a593Smuzhiyun                     if (newY == height - 1)
449*4882a593Smuzhiyun                         newY = height;
450*4882a593Smuzhiyun                 }
451*4882a593Smuzhiyun                 priv->newscreen = 0;
452*4882a593Smuzhiyun                 v[0] = dmxScreen->rootXOrigin + newX;
453*4882a593Smuzhiyun                 v[1] = dmxScreen->rootYOrigin + newY;
454*4882a593Smuzhiyun                 DMXDBG8("   Absolute move: %d,%d (r=%dx%d+%d+%d s=%dx%d)\n",
455*4882a593Smuzhiyun                         v[0], v[1],
456*4882a593Smuzhiyun                         priv->be->rootWidth, priv->be->rootHeight,
457*4882a593Smuzhiyun                         priv->be->rootX, priv->be->rootY,
458*4882a593Smuzhiyun                         priv->be->scrnWidth, priv->be->scrnHeight);
459*4882a593Smuzhiyun                 motion(priv->mou, v, 0, 2, DMX_ABSOLUTE, block);
460*4882a593Smuzhiyun                 priv->entered = 0;
461*4882a593Smuzhiyun             }
462*4882a593Smuzhiyun             else {
463*4882a593Smuzhiyun                 int newX = priv->lastX - X.xmotion.x;
464*4882a593Smuzhiyun                 int newY = priv->lastY - X.xmotion.y;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun                 priv->lastX = X.xmotion.x;
467*4882a593Smuzhiyun                 priv->lastY = X.xmotion.y;
468*4882a593Smuzhiyun                 v[0] = newX;
469*4882a593Smuzhiyun                 v[1] = newY;
470*4882a593Smuzhiyun                 DMXDBG2("   Relative move: %d, %d\n", v[0], v[1]);
471*4882a593Smuzhiyun                 motion(priv->mou, v, 0, 2, DMX_RELATIVE, block);
472*4882a593Smuzhiyun             }
473*4882a593Smuzhiyun             if (entered && priv->relative) {
474*4882a593Smuzhiyun                 DMXDBG4("   **** Relative %d %d instead of absolute %d %d\n",
475*4882a593Smuzhiyun                         v[0], v[1],
476*4882a593Smuzhiyun                         (dmxScreen->rootXOrigin + X.xmotion.x
477*4882a593Smuzhiyun                          - dmxScreen->rootX),
478*4882a593Smuzhiyun                         (dmxScreen->rootYOrigin + X.xmotion.y
479*4882a593Smuzhiyun                          - dmxScreen->rootY));
480*4882a593Smuzhiyun             }
481*4882a593Smuzhiyun             break;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun         case KeyPress:
484*4882a593Smuzhiyun         case KeyRelease:
485*4882a593Smuzhiyun             enqueue(priv->kbd, X.type, X.xkey.keycode, 0, NULL, block);
486*4882a593Smuzhiyun             break;
487*4882a593Smuzhiyun         case ButtonPress:
488*4882a593Smuzhiyun         case ButtonRelease:
489*4882a593Smuzhiyun             /* fall-through */
490*4882a593Smuzhiyun         default:
491*4882a593Smuzhiyun             /* Pass the whole event here, because
492*4882a593Smuzhiyun              * this may be an extension event. */
493*4882a593Smuzhiyun             enqueue(priv->mou, X.type, X.xbutton.button, 0, &X, block);
494*4882a593Smuzhiyun             break;
495*4882a593Smuzhiyun         }
496*4882a593Smuzhiyun     }
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun /** Called after input events are processed from the DMX queue.  No
500*4882a593Smuzhiyun  * event processing actually takes place here, but this is a convenient
501*4882a593Smuzhiyun  * place to update the pointer. */
502*4882a593Smuzhiyun void
dmxBackendProcessInput(void * private)503*4882a593Smuzhiyun dmxBackendProcessInput(void *private)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun     GETPRIVFROMPRIVATE;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun     DMXDBG6("dmxBackendProcessInput: myScreen=%d relative=%d"
508*4882a593Smuzhiyun             " last=%d,%d center=%d,%d\n",
509*4882a593Smuzhiyun             priv->myScreen, priv->relative,
510*4882a593Smuzhiyun             priv->lastX, priv->lastY, priv->centerX, priv->centerY);
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun     if (priv->relative
513*4882a593Smuzhiyun         && !dmxInput->console
514*4882a593Smuzhiyun         && (priv->lastX != priv->centerX || priv->lastY != priv->centerY)) {
515*4882a593Smuzhiyun         DMXDBG4("   warping pointer from last=%d,%d to center=%d,%d\n",
516*4882a593Smuzhiyun                 priv->lastX, priv->lastY, priv->centerX, priv->centerY);
517*4882a593Smuzhiyun         priv->lastX = priv->centerX;
518*4882a593Smuzhiyun         priv->lastY = priv->centerY;
519*4882a593Smuzhiyun         XWarpPointer(priv->display, None, priv->window,
520*4882a593Smuzhiyun                      0, 0, 0, 0, priv->lastX, priv->lastY);
521*4882a593Smuzhiyun         dmxSync(&dmxScreens[priv->myScreen], TRUE);
522*4882a593Smuzhiyun     }
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun static void
dmxBackendComputeCenter(myPrivate * priv)526*4882a593Smuzhiyun dmxBackendComputeCenter(myPrivate * priv)
527*4882a593Smuzhiyun {
528*4882a593Smuzhiyun     int centerX;
529*4882a593Smuzhiyun     int centerY;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun     centerX = priv->be->rootWidth / 2 + priv->be->rootX;
532*4882a593Smuzhiyun     centerY = priv->be->rootHeight / 2 + priv->be->rootY;
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun     if (centerX > priv->be->rootWidth)
535*4882a593Smuzhiyun         centerX = priv->be->rootWidth - 1;
536*4882a593Smuzhiyun     if (centerY > priv->be->rootHeight)
537*4882a593Smuzhiyun         centerY = priv->be->rootHeight - 1;
538*4882a593Smuzhiyun     if (centerX < 1)
539*4882a593Smuzhiyun         centerX = 1;
540*4882a593Smuzhiyun     if (centerY < 1)
541*4882a593Smuzhiyun         centerY = 1;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun     priv->centerX = centerX;
544*4882a593Smuzhiyun     priv->centerY = centerY;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun static DMXScreenInfo *
dmxBackendInitPrivate(DevicePtr pDev)548*4882a593Smuzhiyun dmxBackendInitPrivate(DevicePtr pDev)
549*4882a593Smuzhiyun {
550*4882a593Smuzhiyun     GETPRIVFROMPDEV;
551*4882a593Smuzhiyun     DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
552*4882a593Smuzhiyun     DMXScreenInfo *dmxScreen;
553*4882a593Smuzhiyun     int i;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun     /* Fill in myPrivate */
556*4882a593Smuzhiyun     for (i = 0, dmxScreen = &dmxScreens[0]; i < dmxNumScreens; i++, dmxScreen++) {
557*4882a593Smuzhiyun         if (dmxPropertySameDisplay(dmxScreen, dmxInput->name)) {
558*4882a593Smuzhiyun             priv->display = dmxScreen->beDisplay;
559*4882a593Smuzhiyun             priv->window = dmxScreen->scrnWin;
560*4882a593Smuzhiyun             priv->be = dmxScreen;
561*4882a593Smuzhiyun             break;
562*4882a593Smuzhiyun         }
563*4882a593Smuzhiyun     }
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun     if (i >= dmxNumScreens)
566*4882a593Smuzhiyun         dmxLog(dmxFatal,
567*4882a593Smuzhiyun                "%s is not an existing backend display - cannot initialize\n",
568*4882a593Smuzhiyun                dmxInput->name);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun     return dmxScreen;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun /** Re-initialized the backend device described by \a pDev (after a
574*4882a593Smuzhiyun  * reconfig). */
575*4882a593Smuzhiyun void
dmxBackendLateReInit(DevicePtr pDev)576*4882a593Smuzhiyun dmxBackendLateReInit(DevicePtr pDev)
577*4882a593Smuzhiyun {
578*4882a593Smuzhiyun     GETPRIVFROMPDEV;
579*4882a593Smuzhiyun     int x, y;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun     dmxBackendSameDisplay(NULL, 0);     /* Invalidate cache */
582*4882a593Smuzhiyun     dmxBackendInitPrivate(pDev);
583*4882a593Smuzhiyun     dmxBackendComputeCenter(priv);
584*4882a593Smuzhiyun     dmxGetGlobalPosition(&x, &y);
585*4882a593Smuzhiyun     dmxInvalidateGlobalPosition();      /* To force event processing */
586*4882a593Smuzhiyun     dmxBackendUpdatePosition(priv, x, y);
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun /** Initialized the backend device described by \a pDev. */
590*4882a593Smuzhiyun void
dmxBackendInit(DevicePtr pDev)591*4882a593Smuzhiyun dmxBackendInit(DevicePtr pDev)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun     GETPRIVFROMPDEV;
594*4882a593Smuzhiyun     DMXScreenInfo *dmxScreen;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun     dmxBackendSameDisplay(NULL, 0);     /* Invalidate cache */
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun     if (dmxLocal->type == DMX_LOCAL_MOUSE)
599*4882a593Smuzhiyun         priv->mou = pDev;
600*4882a593Smuzhiyun     if (dmxLocal->type == DMX_LOCAL_KEYBOARD)
601*4882a593Smuzhiyun         priv->kbd = pDev;
602*4882a593Smuzhiyun     if (priv->initialized++)
603*4882a593Smuzhiyun         return;                 /* Only do once for mouse/keyboard pair */
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun     dmxScreen = dmxBackendInitPrivate(pDev);
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun     /* Finish initialization using computed values or constants. */
608*4882a593Smuzhiyun     dmxBackendComputeCenter(priv);
609*4882a593Smuzhiyun     priv->eventMask = (EnterWindowMask | LeaveWindowMask);
610*4882a593Smuzhiyun     priv->myScreen = dmxScreen->index;
611*4882a593Smuzhiyun     priv->lastX = priv->centerX;
612*4882a593Smuzhiyun     priv->lastY = priv->centerY;
613*4882a593Smuzhiyun     priv->relative = 0;
614*4882a593Smuzhiyun     priv->newscreen = 0;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun /** Get information about the backend pointer (for initialization). */
618*4882a593Smuzhiyun void
dmxBackendMouGetInfo(DevicePtr pDev,DMXLocalInitInfoPtr info)619*4882a593Smuzhiyun dmxBackendMouGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun     const DMXScreenInfo *dmxScreen = dmxBackendInitPrivate(pDev);
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun     info->buttonClass = 1;
624*4882a593Smuzhiyun     dmxCommonMouGetMap(pDev, info->map, &info->numButtons);
625*4882a593Smuzhiyun     info->valuatorClass = 1;
626*4882a593Smuzhiyun     info->numRelAxes = 2;
627*4882a593Smuzhiyun     info->minval[0] = 0;
628*4882a593Smuzhiyun     info->minval[1] = 0;
629*4882a593Smuzhiyun     info->maxval[0] = dmxScreen->beWidth;
630*4882a593Smuzhiyun     info->maxval[1] = dmxScreen->beHeight;
631*4882a593Smuzhiyun     info->res[0] = 1;
632*4882a593Smuzhiyun     info->minres[0] = 0;
633*4882a593Smuzhiyun     info->maxres[0] = 1;
634*4882a593Smuzhiyun     info->ptrFeedbackClass = 1;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun /** Get information about the backend keyboard (for initialization). */
638*4882a593Smuzhiyun void
dmxBackendKbdGetInfo(DevicePtr pDev,DMXLocalInitInfoPtr info)639*4882a593Smuzhiyun dmxBackendKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
640*4882a593Smuzhiyun {
641*4882a593Smuzhiyun     dmxCommonKbdGetInfo(pDev, info);
642*4882a593Smuzhiyun     info->keyboard = 1;
643*4882a593Smuzhiyun     info->keyClass = 1;
644*4882a593Smuzhiyun     dmxCommonKbdGetMap(pDev, &info->keySyms, info->modMap);
645*4882a593Smuzhiyun     info->freemap = 1;
646*4882a593Smuzhiyun     info->focusClass = 1;
647*4882a593Smuzhiyun     info->kbdFeedbackClass = 1;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun /** Process #DMXFunctionType functions.  The only function handled here
651*4882a593Smuzhiyun  * is to acknowledge a pending server shutdown. */
652*4882a593Smuzhiyun int
dmxBackendFunctions(void * private,DMXFunctionType function)653*4882a593Smuzhiyun dmxBackendFunctions(void *private, DMXFunctionType function)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun     switch (function) {
656*4882a593Smuzhiyun     case DMX_FUNCTION_TERMINATE:
657*4882a593Smuzhiyun         return 1;
658*4882a593Smuzhiyun     default:
659*4882a593Smuzhiyun         return 0;
660*4882a593Smuzhiyun     }
661*4882a593Smuzhiyun }
662