609 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			609 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
| /* $XFree86$ */
 | |
| /*
 | |
|  * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina.
 | |
|  *
 | |
|  * All Rights Reserved.
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining
 | |
|  * a copy of this software and associated documentation files (the
 | |
|  * "Software"), to deal in the Software without restriction, including
 | |
|  * without limitation on the rights to use, copy, modify, merge,
 | |
|  * publish, distribute, sublicense, and/or sell copies of the Software,
 | |
|  * and to permit persons to whom the Software is furnished to do so,
 | |
|  * subject to the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice (including the
 | |
|  * next paragraph) shall be included in all copies or substantial
 | |
|  * portions of the Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | |
|  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
|  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | |
|  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
 | |
|  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 | |
|  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | |
|  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | |
|  * SOFTWARE.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Authors:
 | |
|  *   David H. Dawes <dawes@xfree86.org>
 | |
|  *   Kevin E. Martin <kem@redhat.com>
 | |
|  *   Rickard E. (Rik) Faith <faith@redhat.com>
 | |
|  */
 | |
| 
 | |
| /** \file
 | |
|  * These routines support taking input from devices on the backend
 | |
|  * (output) displays.  \see dmxcommon.c. */
 | |
| 
 | |
| #ifdef HAVE_DMX_CONFIG_H
 | |
| #include <dmx-config.h>
 | |
| #endif
 | |
| 
 | |
| #define DMX_BACKEND_DEBUG 0
 | |
| 
 | |
| #include "dmxinputinit.h"
 | |
| #include "dmxbackend.h"
 | |
| #include "dmxcommon.h"
 | |
| #include "dmxconsole.h"
 | |
| #include "dmxcursor.h"
 | |
| #include "dmxprop.h"
 | |
| #include "dmxsync.h"
 | |
| #include "dmxcb.h"              /* For dmxGlobalWidth and dmxGlobalHeight */
 | |
| #include "dmxevents.h"          /* For dmxGetGlobalPosition */
 | |
| #include "ChkNotMaskEv.h"
 | |
| 
 | |
| #include "inputstr.h"
 | |
| #include "input.h"
 | |
| #include <X11/keysym.h>
 | |
| #include "mipointer.h"
 | |
| #include "scrnintstr.h"
 | |
| #include "windowstr.h"
 | |
| 
 | |
| /* Private area for backend devices. */
 | |
| typedef struct _myPrivate {
 | |
|     DMX_COMMON_PRIVATE;
 | |
|     int                     myScreen;
 | |
|     DMXScreenInfo           *grabbedScreen;
 | |
|     
 | |
|     int                     lastX, lastY;
 | |
|     int                     centerX, centerY;
 | |
|     int                     relative;
 | |
|     int                     newscreen;
 | |
|     int                     initialized;
 | |
|     DevicePtr               mou, kbd;
 | |
|     int                     entered;
 | |
|     int                     offX, offY;
 | |
| } myPrivate;
 | |
| 
 | |
| #if DMX_BACKEND_DEBUG
 | |
| #define DMXDBG0(f)                   dmxLog(dmxDebug,f)
 | |
| #define DMXDBG1(f,a)                 dmxLog(dmxDebug,f,a)
 | |
| #define DMXDBG2(f,a,b)               dmxLog(dmxDebug,f,a,b)
 | |
| #define DMXDBG3(f,a,b,c)             dmxLog(dmxDebug,f,a,b,c)
 | |
| #define DMXDBG4(f,a,b,c,d)           dmxLog(dmxDebug,f,a,b,c,d)
 | |
| #define DMXDBG5(f,a,b,c,d,e)         dmxLog(dmxDebug,f,a,b,c,d,e)
 | |
| #define DMXDBG6(f,a,b,c,d,e,g)       dmxLog(dmxDebug,f,a,b,c,d,e,g)
 | |
| #define DMXDBG7(f,a,b,c,d,e,g,h)     dmxLog(dmxDebug,f,a,b,c,d,e,g,h)
 | |
| #define DMXDBG8(f,a,b,c,d,e,g,h,i)   dmxLog(dmxDebug,f,a,b,c,d,e,g,h,i)
 | |
| #define DMXDBG9(f,a,b,c,d,e,g,h,i,j) dmxLog(dmxDebug,f,a,b,c,d,e,g,h,i,j)
 | |
| #else
 | |
| #define DMXDBG0(f)
 | |
| #define DMXDBG1(f,a)
 | |
| #define DMXDBG2(f,a,b)
 | |
| #define DMXDBG3(f,a,b,c)
 | |
| #define DMXDBG4(f,a,b,c,d)
 | |
| #define DMXDBG5(f,a,b,c,d,e)
 | |
| #define DMXDBG6(f,a,b,c,d,e,g)
 | |
| #define DMXDBG7(f,a,b,c,d,e,g,h)
 | |
| #define DMXDBG8(f,a,b,c,d,e,g,h,i)
 | |
| #define DMXDBG9(f,a,b,c,d,e,g,h,i,j)
 | |
| #endif
 | |
| 
 | |
| /** Create and return a private data structure. */
 | |
| pointer dmxBackendCreatePrivate(DeviceIntPtr pDevice)
 | |
| {
 | |
|     GETDMXLOCALFROMPDEVICE;
 | |
|     myPrivate *priv = xalloc(sizeof(*priv));
 | |
|     memset(priv, 0, sizeof(*priv));
 | |
|     priv->dmxLocal  = dmxLocal;
 | |
|     return priv;
 | |
| }
 | |
| 
 | |
| /** Destroy the private data structure.  No checking is performed to
 | |
|  * verify that the structure was actually created by
 | |
|  * #dmxBackendCreatePrivate. */
 | |
| void dmxBackendDestroyPrivate(pointer private)
 | |
| {
 | |
|     if (private) xfree(private);
 | |
| }
 | |
| 
 | |
| static void *dmxBackendTestScreen(DMXScreenInfo *dmxScreen, void *closure)
 | |
| {
 | |
|     long target = (long)closure;
 | |
| 
 | |
|     if (dmxScreen->index == target) return dmxScreen;
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| /* Return non-zero if screen and priv->myScreen are on the same physical
 | |
|  * backend display (1 if they are the same screen, 2 if they are
 | |
|  * different screens).  Since this is a common operation, the results
 | |
|  * are cached.  The cache is invalidated if \a priv is NULL (this should
 | |
|  * be done with each server generation and reconfiguration). */
 | |
| static int dmxBackendSameDisplay(myPrivate *priv, long screen)
 | |
| {
 | |
|     static myPrivate *oldpriv  = NULL;
 | |
|     static int       oldscreen = -1;
 | |
|     static int       retcode   = 0;
 | |
| 
 | |
|     if (priv == oldpriv && screen == oldscreen) return retcode;
 | |
|     if (!priv) {                /* Invalidate cache */
 | |
|         oldpriv   = NULL;
 | |
|         oldscreen = -1;
 | |
|         retcode   = 0;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     if (screen == priv->myScreen)                     retcode = 1;
 | |
|     else if (screen < 0 || screen >= dmxNumScreens)   retcode = 0;
 | |
|     else if (dmxPropertyIterate(priv->be,
 | |
|                                 dmxBackendTestScreen,
 | |
|                                 (void *)screen))      retcode = 2;
 | |
|     else                                              retcode = 0;
 | |
| 
 | |
|     oldpriv   = priv;
 | |
|     oldscreen = screen;
 | |
|     return retcode;
 | |
| }
 | |
| 
 | |
| static void *dmxBackendTestEvents(DMXScreenInfo *dmxScreen, void *closure)
 | |
| {
 | |
|     XEvent *X = (XEvent *)closure;
 | |
|     
 | |
|     if (XCheckNotMaskEvent(dmxScreen->beDisplay, ExposureMask, X))
 | |
|         return dmxScreen;
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| static void *dmxBackendTestMotionEvent(DMXScreenInfo *dmxScreen, void *closure)
 | |
| {
 | |
|     XEvent *X = (XEvent *)closure;
 | |
| 
 | |
|     if (XCheckTypedEvent(dmxScreen->beDisplay, MotionNotify, X))
 | |
|         return dmxScreen;
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| static DMXScreenInfo *dmxBackendGetEvent(myPrivate *priv, XEvent *X)
 | |
| {
 | |
|     DMXScreenInfo *dmxScreen;
 | |
| 
 | |
|     if ((dmxScreen = dmxPropertyIterate(priv->be, dmxBackendTestEvents, X)))
 | |
|         return dmxScreen;
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| static DMXScreenInfo *dmxBackendPendingMotionEvent(myPrivate *priv, int save)
 | |
| {
 | |
|     DMXScreenInfo *dmxScreen;
 | |
|     XEvent        N;
 | |
| 
 | |
|     if ((dmxScreen = dmxPropertyIterate(priv->be,
 | |
|                                         dmxBackendTestMotionEvent, &N))) {
 | |
|         if (save) XPutBackEvent(dmxScreen->beDisplay, &N);
 | |
|         return dmxScreen;
 | |
|     }
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| static void *dmxBackendTestWindow(DMXScreenInfo *dmxScreen, void *closure)
 | |
| {
 | |
|     Window win = (Window)(long)closure;
 | |
|     if (dmxScreen->scrnWin == win) return dmxScreen;
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| static DMXScreenInfo *dmxBackendFindWindow(myPrivate *priv, Window win)
 | |
| {
 | |
|     return dmxPropertyIterate(priv->be, dmxBackendTestWindow,
 | |
|                               (void *)(long)win);
 | |
| }
 | |
| 
 | |
| /* If the cursor is over a set of overlapping screens and one of those
 | |
|  * screens takes backend input, then we want that particular screen to
 | |
|  * be current, not one of the other ones. */
 | |
| static int dmxBackendFindOverlapping(myPrivate *priv, int screen, int x, int y)
 | |
| {
 | |
|     DMXScreenInfo *start = &dmxScreens[screen];
 | |
|     DMXScreenInfo *pt;
 | |
| 
 | |
|     if (!start->over) return screen;
 | |
|     
 | |
|     for (pt = start->over; /* condition at end of loop */; pt = pt->over) {
 | |
|         if (pt->index == priv->myScreen
 | |
|             && dmxOnScreen(x, y, &dmxScreens[pt->index])) return pt->index;
 | |
|         if (pt == start) break;
 | |
|     }
 | |
|     return screen;
 | |
| }
 | |
| 
 | |
| /* Return non-zero if \a x and \a y are off \a screen. */
 | |
| static int dmxBackendOffscreen(int screen, int x, int y)
 | |
| {
 | |
|     DMXScreenInfo *dmxScreen = &dmxScreens[screen];
 | |
| 
 | |
|     return (!dmxOnScreen(x, y, dmxScreen));
 | |
| }
 | |
| 
 | |
| /** This routine is called from #dmxCoreMotion for each motion
 | |
|  * event. #x and #y are global coordinants. */
 | |
| void dmxBackendUpdatePosition(pointer private, int x, int y)
 | |
| {
 | |
|     GETPRIVFROMPRIVATE;
 | |
|     int           screen      = miPointerCurrentScreen()->myNum;
 | |
|     DMXScreenInfo *dmxScreen  = &dmxScreens[priv->myScreen];
 | |
|     int           oldRelative = priv->relative;
 | |
|     int           topscreen   = dmxBackendFindOverlapping(priv, screen, x, y);
 | |
|     int           same        = dmxBackendSameDisplay(priv, topscreen);
 | |
|     int           offscreen   = dmxBackendOffscreen(priv->myScreen, x, y);
 | |
|     int           offthis     = dmxBackendOffscreen(screen, x, y);
 | |
| 
 | |
|     DMXDBG9("dmxBackendUpdatePosition(%d,%d) my=%d mi=%d rel=%d"
 | |
|             " topscreen=%d same=%d offscreen=%d offthis=%d\n",
 | |
|             x, y, priv->myScreen, screen, priv->relative,
 | |
|             topscreen, same, offscreen, offthis);
 | |
| 
 | |
|     if (offscreen) {
 | |
|         /* If the cursor is off the input screen, it should be moving
 | |
|          * relative unless it is visible on a screen of the same display
 | |
|          * (i.e., one that shares the mouse). */
 | |
|         if (same == 2 && !offthis) {
 | |
|             if (priv->relative) {
 | |
|                 DMXDBG0("   Off screen, but not absolute\n");
 | |
|                 priv->relative = 0;
 | |
|             }
 | |
|         } else {
 | |
|             if (!priv->relative) {
 | |
|                 DMXDBG0("   Off screen, but not relative\n");
 | |
|                 priv->relative = 1;
 | |
|             }
 | |
|         }
 | |
|     } else {
 | |
|         if (topscreen != screen) {
 | |
|             DMXDBG2("   Using screen %d instead of %d (from mi)\n",
 | |
|                     topscreen, screen);
 | |
|         }
 | |
|         if (same) {
 | |
|             if (priv->relative) {
 | |
|                 DMXDBG0("   On screen, but not absolute\n");
 | |
|                 priv->relative = 0;
 | |
|             }
 | |
|         } else {
 | |
|             if (!priv->relative) {
 | |
|                 DMXDBG0("   Not on screen, but not relative\n");
 | |
|                 priv->relative = 1;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (oldRelative != priv->relative) {
 | |
|         DMXDBG2("   Do switch, relative=%d same=%d\n",
 | |
|                 priv->relative, same);
 | |
|         /* Discard all pre-switch events */
 | |
|         dmxSync(dmxScreen, TRUE);
 | |
|         while (dmxBackendPendingMotionEvent(priv, FALSE));
 | |
|         
 | |
|         if (dmxInput->console && offscreen) {
 | |
|             /* Our special case is a console window and a backend window
 | |
|              * share a display.  In this case, the cursor is either on
 | |
|              * the backend window (taking absolute input), or not (in
 | |
|              * which case the cursor needs to be in the console
 | |
|              * window). */
 | |
|             if (priv->grabbedScreen) {
 | |
|                 DMXDBG2("   *** force ungrab on %s, display=%p\n",
 | |
|                         priv->grabbedScreen->name,
 | |
|                         priv->grabbedScreen->beDisplay);
 | |
|                 XUngrabPointer(priv->grabbedScreen->beDisplay, CurrentTime);
 | |
|                 dmxSync(priv->grabbedScreen, TRUE);
 | |
|                 priv->grabbedScreen = NULL;
 | |
|             }
 | |
|             DMXDBG0("   Capturing console\n");
 | |
|             dmxConsoleCapture(dmxInput);
 | |
|         } else {
 | |
|             priv->newscreen = 1;
 | |
|             if (priv->relative && !dmxInput->console) {
 | |
|                 DMXDBG5("   Hide cursor; warp from %d,%d to %d,%d on %d\n",
 | |
|                         priv->lastX, priv->lastY, priv->centerX, priv->centerY,
 | |
|                         priv->myScreen);
 | |
|                 dmxConsoleUncapture(dmxInput);
 | |
|                 dmxHideCursor(dmxScreen);
 | |
|                 priv->lastX   = priv->centerX;
 | |
|                 priv->lastY   = priv->centerY;
 | |
|                 XWarpPointer(priv->display, None, priv->window,
 | |
|                              0, 0, 0, 0, priv->lastX, priv->lastY);
 | |
|                 dmxSync(dmxScreen, TRUE);
 | |
|             } else {
 | |
|                 DMXDBG0("   Check cursor\n");
 | |
|                 dmxCheckCursor();
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /** Get events from the X queue on the backend servers and put the
 | |
|  * events into the DMX event queue. */
 | |
| void dmxBackendCollectEvents(DevicePtr pDev,
 | |
|                              dmxMotionProcPtr motion,
 | |
|                              dmxEnqueueProcPtr enqueue,
 | |
|                              dmxCheckSpecialProcPtr checkspecial,
 | |
|                              DMXBlockType block)
 | |
| {
 | |
|     GETPRIVFROMPDEV;
 | |
|     GETDMXINPUTFROMPRIV;
 | |
|     XEvent               X;
 | |
|     DMXScreenInfo        *dmxScreen;
 | |
|     int                  left        = 0;
 | |
|     int                  entered     = priv->entered;
 | |
|     int                  ignoreLeave = 0;
 | |
|     int                  v[2];
 | |
|     int                  retcode;
 | |
| 
 | |
|     while ((dmxScreen = dmxBackendGetEvent(priv, &X))) {
 | |
| 	switch (X.type) {
 | |
|         case EnterNotify:
 | |
|             dmxCommonSaveState(priv);
 | |
|             if (entered++) continue;
 | |
|             priv->entered = 1;
 | |
|             ignoreLeave   = 1;
 | |
|             DMXDBG5("dmxBackendCollectEvents: Enter %lu %d,%d; GRAB %s %p\n",
 | |
|                     X.xcrossing.root, X.xcrossing.x, X.xcrossing.y,
 | |
|                     dmxScreen->name, dmxScreen->beDisplay);
 | |
|             XRaiseWindow(dmxScreen->beDisplay, dmxScreen->scrnWin);
 | |
|             priv->grabbedScreen = dmxScreen;
 | |
|             if ((retcode = XGrabPointer(dmxScreen->beDisplay,
 | |
| 					dmxScreen->scrnWin,
 | |
|                                         True, 0, GrabModeAsync,
 | |
|                                         GrabModeAsync, None, None,
 | |
|                                         CurrentTime))) {
 | |
|                 dmxLog(dmxError,
 | |
|                        "XGrabPointer failed during backend enter (%d)\n",
 | |
|                        retcode);
 | |
|             }
 | |
|             break;
 | |
|         case LeaveNotify:
 | |
|             if (ignoreLeave) {
 | |
|                 ignoreLeave = 0;
 | |
|                 continue;
 | |
|             }
 | |
|             dmxCommonRestoreState(priv);
 | |
|             if (left++) continue;
 | |
|             DMXDBG7("dmxBackendCollectEvents: Leave %lu %d,%d %d %d %s %s\n",
 | |
|                     X.xcrossing.root, X.xcrossing.x, X.xcrossing.y,
 | |
|                     X.xcrossing.detail, X.xcrossing.focus,
 | |
|                     priv->grabbedScreen ? "UNGRAB" : "",
 | |
|                     dmxScreen->name);
 | |
|             if (priv->grabbedScreen) {
 | |
|                 XUngrabPointer(priv->grabbedScreen->beDisplay, CurrentTime);
 | |
|                 dmxSync(priv->grabbedScreen, TRUE);
 | |
|                 priv->grabbedScreen = NULL;
 | |
|             }
 | |
|             break;
 | |
| 	case MotionNotify:
 | |
|             DMXDBG9("dmxBackendCollectEvents: MotionNotify %d/%d (mi %d)"
 | |
|                     " newscreen=%d: %d %d (e=%d; last=%d,%d)\n",
 | |
|                     dmxScreen->index, priv->myScreen,
 | |
|                     miPointerCurrentScreen()->myNum,
 | |
|                     priv->newscreen,
 | |
|                     X.xmotion.x, X.xmotion.y,
 | |
|                     entered, priv->lastX, priv->lastY);
 | |
|             if (dmxBackendPendingMotionEvent(priv, TRUE)) continue;
 | |
|             if (!(dmxScreen = dmxBackendFindWindow(priv, X.xmotion.window)))
 | |
|                 dmxLog(dmxFatal,
 | |
|                        "   Event on non-existant window %lu\n",
 | |
|                        X.xmotion.window);
 | |
|             if (!priv->relative || dmxInput->console) {
 | |
|                 int newX = X.xmotion.x - dmxScreen->rootX;
 | |
|                 int newY = X.xmotion.y - dmxScreen->rootY;
 | |
| 
 | |
|                 if (!priv->newscreen) {
 | |
|                     int width  = dmxScreen->rootWidth;
 | |
|                     int height = dmxScreen->rootHeight;
 | |
|                     if (!newX)              newX = -1;
 | |
|                     if (newX == width - 1)  newX = width;
 | |
|                     if (!newY)              newY = -1;
 | |
|                     if (newY == height - 1) newY = height;
 | |
|                 }
 | |
|                 priv->newscreen = 0;
 | |
|                 v[0] = dmxScreen->rootXOrigin + newX;
 | |
|                 v[1] = dmxScreen->rootYOrigin + newY;
 | |
|                 DMXDBG8("   Absolute move: %d,%d (r=%dx%d+%d+%d s=%dx%d)\n",
 | |
|                         v[0], v[1],
 | |
|                         priv->be->rootWidth, priv->be->rootHeight,
 | |
|                         priv->be->rootX, priv->be->rootY,
 | |
|                         priv->be->scrnWidth, priv->be->scrnHeight);
 | |
|                 motion(priv->mou, v, 0, 2, DMX_ABSOLUTE, block);
 | |
|                 priv->entered = 0;
 | |
|             } else {
 | |
|                 int newX = priv->lastX - X.xmotion.x;
 | |
|                 int newY = priv->lastY - X.xmotion.y;
 | |
|                 priv->lastX = X.xmotion.x;
 | |
|                 priv->lastY = X.xmotion.y;
 | |
|                 v[0]        = newX;
 | |
|                 v[1]        = newY;
 | |
|                 DMXDBG2("   Relative move: %d, %d\n", v[0], v[1]);
 | |
|                 motion(priv->mou, v, 0, 2, DMX_RELATIVE, block);
 | |
|             }
 | |
|             if (entered && priv->relative) {
 | |
|                 DMXDBG4("   **** Relative %d %d instead of absolute %d %d\n",
 | |
|                         v[0], v[1],
 | |
|                         (dmxScreen->rootXOrigin + X.xmotion.x
 | |
|                          - dmxScreen->rootX),
 | |
|                         (dmxScreen->rootYOrigin + X.xmotion.y
 | |
|                          - dmxScreen->rootY));
 | |
|             }
 | |
| 	    break;
 | |
| 
 | |
|         case KeyPress:
 | |
|         case KeyRelease:
 | |
|             enqueue(priv->kbd, X.type, X.xkey.keycode, 0, NULL, block);
 | |
|             break;
 | |
| 	default:
 | |
|                                 /* Pass the whole event here, because
 | |
|                                  * this may be an extension event. */
 | |
|             enqueue(priv->mou, X.type, X.xbutton.button, 0, &X, block);
 | |
| 	    break;
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| /** Called after input events are processed from the DMX queue.  No
 | |
|  * event processing actually takes place here, but this is a convenient
 | |
|  * place to update the pointer. */
 | |
| void dmxBackendProcessInput(pointer private)
 | |
| {
 | |
|     GETPRIVFROMPRIVATE;
 | |
| 
 | |
|     DMXDBG6("dmxBackendProcessInput: myScreen=%d relative=%d"
 | |
|             " last=%d,%d center=%d,%d\n",
 | |
|             priv->myScreen, priv->relative,
 | |
|             priv->lastX, priv->lastY,
 | |
|             priv->centerX, priv->centerY);
 | |
| 
 | |
|     if (priv->relative
 | |
|         && !dmxInput->console
 | |
|         && (priv->lastX != priv->centerX || priv->lastY != priv->centerY)) {
 | |
|         DMXDBG4("   warping pointer from last=%d,%d to center=%d,%d\n",
 | |
|                 priv->lastX, priv->lastY, priv->centerX, priv->centerY);
 | |
| 	priv->lastX   = priv->centerX;
 | |
| 	priv->lastY   = priv->centerY;
 | |
|         XWarpPointer(priv->display, None, priv->window,
 | |
|                      0, 0, 0, 0, priv->lastX, priv->lastY);
 | |
|         dmxSync(&dmxScreens[priv->myScreen], TRUE);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void dmxBackendComputeCenter(myPrivate *priv)
 | |
| {
 | |
|     int centerX;
 | |
|     int centerY;
 | |
|     
 | |
|     centerX       = priv->be->rootWidth / 2 + priv->be->rootX;
 | |
|     centerY       = priv->be->rootHeight / 2 + priv->be->rootY;
 | |
| 
 | |
|     if (centerX > priv->be->rootWidth)  centerX = priv->be->rootWidth  - 1;
 | |
|     if (centerY > priv->be->rootHeight) centerY = priv->be->rootHeight - 1;
 | |
|     if (centerX < 1)                    centerX = 1;
 | |
|     if (centerY < 1)                    centerY = 1;
 | |
| 
 | |
|     priv->centerX = centerX;
 | |
|     priv->centerY = centerY;
 | |
| }
 | |
| 
 | |
| static DMXScreenInfo *dmxBackendInitPrivate(DevicePtr pDev)
 | |
| {
 | |
|     GETPRIVFROMPDEV;
 | |
|     DMXInputInfo      *dmxInput = &dmxInputs[dmxLocal->inputIdx];
 | |
|     DMXScreenInfo     *dmxScreen;
 | |
|     int               i;
 | |
| 
 | |
|     /* Fill in myPrivate */
 | |
|     for (i = 0,dmxScreen = &dmxScreens[0]; i<dmxNumScreens; i++,dmxScreen++) {
 | |
|         if (dmxPropertySameDisplay(dmxScreen, dmxInput->name)) {
 | |
|             priv->display  = dmxScreen->beDisplay;
 | |
|             priv->window   = dmxScreen->scrnWin;
 | |
|             priv->be       = dmxScreen;
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (i >= dmxNumScreens)
 | |
|         dmxLog(dmxFatal,
 | |
|                "%s is not an existing backend display - cannot initialize\n",
 | |
|                dmxInput->name);
 | |
| 
 | |
|     return dmxScreen;
 | |
| }
 | |
| 
 | |
| /** Re-initialized the backend device described by \a pDev (after a
 | |
|  * reconfig). */
 | |
| void dmxBackendLateReInit(DevicePtr pDev)
 | |
| {
 | |
|     GETPRIVFROMPDEV;
 | |
|     int               x, y;
 | |
| 
 | |
|     DMXDBG1("dmxBackendLateReInit miPointerCurrentScreen() = %p\n",
 | |
|             miPointerCurrentScreen());
 | |
| 
 | |
|     dmxBackendSameDisplay(NULL, 0); /* Invalidate cache */
 | |
|     dmxBackendInitPrivate(pDev);
 | |
|     dmxBackendComputeCenter(priv);
 | |
|     dmxGetGlobalPosition(&x, &y);
 | |
|     dmxInvalidateGlobalPosition(); /* To force event processing */
 | |
|     dmxBackendUpdatePosition(priv, x, y);
 | |
| }
 | |
| 
 | |
| /** Initialized the backend device described by \a pDev. */
 | |
| void dmxBackendInit(DevicePtr pDev)
 | |
| {
 | |
|     GETPRIVFROMPDEV;
 | |
|     DMXScreenInfo     *dmxScreen;
 | |
| 
 | |
|     dmxBackendSameDisplay(NULL, 0); /* Invalidate cache */
 | |
| 
 | |
|     if (dmxLocal->type == DMX_LOCAL_MOUSE)    priv->mou = pDev;
 | |
|     if (dmxLocal->type == DMX_LOCAL_KEYBOARD) priv->kbd = pDev;
 | |
|     if (priv->initialized++) return; /* Only do once for mouse/keyboard pair */
 | |
| 
 | |
|     dmxScreen = dmxBackendInitPrivate(pDev);
 | |
| 
 | |
|     /* Finish initialization using computed values or constants. */
 | |
|     dmxBackendComputeCenter(priv);
 | |
|     priv->eventMask          = (EnterWindowMask|LeaveWindowMask);
 | |
|     priv->myScreen           = dmxScreen->index;
 | |
|     priv->lastX              = priv->centerX;
 | |
|     priv->lastY              = priv->centerY;
 | |
|     priv->relative           = 0;
 | |
|     priv->newscreen          = 0;
 | |
| }
 | |
| 
 | |
| /** Get information about the backend pointer (for initialization). */
 | |
| void dmxBackendMouGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
 | |
| {
 | |
|     info->buttonClass      = 1;
 | |
|     dmxCommonMouGetMap(pDev, info->map, &info->numButtons);
 | |
|     info->valuatorClass    = 1;
 | |
|     info->numRelAxes       = 2;
 | |
|     info->minval[0]        = 0;
 | |
|     info->maxval[0]        = 0;
 | |
|     info->res[0]           = 1;
 | |
|     info->minres[0]        = 0;
 | |
|     info->maxres[0]        = 1;
 | |
|     info->ptrFeedbackClass = 1;
 | |
| }
 | |
| 
 | |
| /** Get information about the backend keyboard (for initialization). */
 | |
| void dmxBackendKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
 | |
| {
 | |
|     dmxCommonKbdGetInfo(pDev, info);
 | |
|     info->keyboard         = 1;
 | |
|     info->keyClass         = 1;
 | |
|     dmxCommonKbdGetMap(pDev, &info->keySyms, info->modMap);
 | |
|     info->freemap          = 1;
 | |
|     info->focusClass       = 1;
 | |
|     info->kbdFeedbackClass = 1;
 | |
| }
 | |
| 
 | |
| /** Process #DMXFunctionType functions.  The only function handled here
 | |
|  * is to acknowledge a pending server shutdown. */
 | |
| int dmxBackendFunctions(pointer private, DMXFunctionType function)
 | |
| {
 | |
|     switch (function) {
 | |
|     case DMX_FUNCTION_TERMINATE:
 | |
|         return 1;
 | |
|     default:
 | |
|         return 0;
 | |
|     }
 | |
| }
 |