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