2006-11-26 11:13:41 -07:00
|
|
|
/*
|
|
|
|
* 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;
|
2009-09-06 13:44:18 -06:00
|
|
|
myPrivate *priv = calloc(1, sizeof(*priv));
|
2006-11-26 11:13:41 -07:00
|
|
|
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)
|
|
|
|
{
|
2009-09-06 13:44:18 -06:00
|
|
|
if (private) free(private);
|
2006-11-26 11:13:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2010-07-27 13:02:24 -06:00
|
|
|
* event. \a x and \a y are global coordinants. */
|
2006-11-26 11:13:41 -07:00
|
|
|
void dmxBackendUpdatePosition(pointer private, int x, int y)
|
|
|
|
{
|
|
|
|
GETPRIVFROMPRIVATE;
|
2007-11-24 10:55:21 -07:00
|
|
|
int screen = miPointerGetScreen(inputInfo.pointer)->myNum;
|
2006-11-26 11:13:41 -07:00
|
|
|
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);
|
2007-11-24 10:55:21 -07:00
|
|
|
if (entered++)
|
|
|
|
continue;
|
2006-11-26 11:13:41 -07:00
|
|
|
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);
|
2007-11-24 10:55:21 -07:00
|
|
|
if (left++)
|
|
|
|
continue;
|
2006-11-26 11:13:41 -07:00
|
|
|
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);
|
2007-11-24 10:55:21 -07:00
|
|
|
if (dmxBackendPendingMotionEvent(priv, TRUE))
|
|
|
|
continue;
|
2006-11-26 11:13:41 -07:00
|
|
|
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;
|
2007-11-24 10:55:21 -07:00
|
|
|
case ButtonPress:
|
|
|
|
case ButtonRelease:
|
|
|
|
/* fall-through */
|
2006-11-26 11:13:41 -07:00
|
|
|
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)
|
|
|
|
{
|
2007-11-24 10:55:21 -07:00
|
|
|
const DMXScreenInfo *dmxScreen = dmxBackendInitPrivate(pDev);
|
|
|
|
|
2006-11-26 11:13:41 -07:00
|
|
|
info->buttonClass = 1;
|
|
|
|
dmxCommonMouGetMap(pDev, info->map, &info->numButtons);
|
|
|
|
info->valuatorClass = 1;
|
|
|
|
info->numRelAxes = 2;
|
|
|
|
info->minval[0] = 0;
|
2007-11-24 10:55:21 -07:00
|
|
|
info->minval[1] = 0;
|
|
|
|
info->maxval[0] = dmxScreen->beWidth;
|
|
|
|
info->maxval[1] = dmxScreen->beHeight;
|
2006-11-26 11:13:41 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|