From 4c61bf84b11e26e6f22648668c95ea760a379163 Mon Sep 17 00:00:00 2001 From: marha Date: Fri, 11 Jun 2010 12:14:52 +0000 Subject: xserver git update 11/6/2010 --- xorg-server/hw/dmx/input/dmxbackend.c | 1232 +++++++++--------- xorg-server/hw/dmx/input/dmxcommon.c | 1339 ++++++++++---------- xorg-server/hw/dmx/input/dmxconsole.c | 2059 +++++++++++++++---------------- xorg-server/hw/dmx/input/dmxinputinit.c | 18 +- xorg-server/hw/dmx/input/dmxinputinit.h | 582 ++++----- xorg-server/hw/dmx/input/lnx-keyboard.c | 2 +- xorg-server/hw/dmx/input/lnx-ms.c | 642 +++++----- xorg-server/hw/dmx/input/lnx-ps2.c | 578 ++++----- xorg-server/hw/dmx/input/usb-common.c | 762 ++++++------ 9 files changed, 3606 insertions(+), 3608 deletions(-) (limited to 'xorg-server/hw/dmx/input') diff --git a/xorg-server/hw/dmx/input/dmxbackend.c b/xorg-server/hw/dmx/input/dmxbackend.c index 55615cf39..35e9e9616 100644 --- a/xorg-server/hw/dmx/input/dmxbackend.c +++ b/xorg-server/hw/dmx/input/dmxbackend.c @@ -1,616 +1,616 @@ -/* - * 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 - * Kevin E. Martin - * Rickard E. (Rik) Faith - */ - -/** \file - * These routines support taking input from devices on the backend - * (output) displays. \see dmxcommon.c. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#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 -#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 = calloc(1, 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) free(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. \a x and \a y are global coordinants. */ -void dmxBackendUpdatePosition(pointer private, int x, int y) -{ - GETPRIVFROMPRIVATE; - int screen = miPointerGetScreen(inputInfo.pointer)->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; - case ButtonPress: - case ButtonRelease: - /* fall-through */ - 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]; iname)) { - 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) -{ - const DMXScreenInfo *dmxScreen = dmxBackendInitPrivate(pDev); - - info->buttonClass = 1; - dmxCommonMouGetMap(pDev, info->map, &info->numButtons); - info->valuatorClass = 1; - info->numRelAxes = 2; - info->minval[0] = 0; - info->minval[1] = 0; - info->maxval[0] = dmxScreen->beWidth; - info->maxval[1] = dmxScreen->beHeight; - 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; - } -} +/* + * 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 + * Kevin E. Martin + * Rickard E. (Rik) Faith + */ + +/** \file + * These routines support taking input from devices on the backend + * (output) displays. \see dmxcommon.c. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#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 +#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 = calloc(1, 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) +{ + free(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. \a x and \a y are global coordinants. */ +void dmxBackendUpdatePosition(pointer private, int x, int y) +{ + GETPRIVFROMPRIVATE; + int screen = miPointerGetScreen(inputInfo.pointer)->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; + case ButtonPress: + case ButtonRelease: + /* fall-through */ + 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]; iname)) { + 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) +{ + const DMXScreenInfo *dmxScreen = dmxBackendInitPrivate(pDev); + + info->buttonClass = 1; + dmxCommonMouGetMap(pDev, info->map, &info->numButtons); + info->valuatorClass = 1; + info->numRelAxes = 2; + info->minval[0] = 0; + info->minval[1] = 0; + info->maxval[0] = dmxScreen->beWidth; + info->maxval[1] = dmxScreen->beHeight; + 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; + } +} diff --git a/xorg-server/hw/dmx/input/dmxcommon.c b/xorg-server/hw/dmx/input/dmxcommon.c index da5b77893..29c1958ad 100644 --- a/xorg-server/hw/dmx/input/dmxcommon.c +++ b/xorg-server/hw/dmx/input/dmxcommon.c @@ -1,670 +1,669 @@ -/* - * 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 - * Kevin E. Martin - * Rickard E. (Rik) Faith - */ - -/** \file - * - * This file implements common routines used by the backend and console - * input devices. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#define DMX_STATE_DEBUG 0 - -#include "dmxinputinit.h" -#include "dmxcommon.h" -#include "dmxconsole.h" -#include "dmxprop.h" -#include "dmxsync.h" -#include "dmxmap.h" - -#include "inputstr.h" -#include "input.h" -#include -#include "mipointer.h" -#include "scrnintstr.h" - -#include /* For usleep() */ - -#if DMX_STATE_DEBUG -#define DMXDBG0(f) dmxLog(dmxDebug,f) -#else -#define DMXDBG0(f) -#endif - -/** Each device has a private area that is visible only from inside the - * driver code. */ -typedef struct _myPrivate { - DMX_COMMON_PRIVATE; -} myPrivate; - -static void dmxCommonKbdSetAR(Display *display, - unsigned char *old, unsigned char *new) -{ - XKeyboardControl kc; - XKeyboardState ks; - unsigned long mask = KBKey | KBAutoRepeatMode; - int i, j; - int minKeycode, maxKeycode; - - if (!old) { - XGetKeyboardControl(display, &ks); - old = (unsigned char *)ks.auto_repeats; - } - - XDisplayKeycodes(display, &minKeycode, &maxKeycode); - for (i = 1; i < 32; i++) { - if (!old || old[i] != new[i]) { - for (j = 0; j < 8; j++) { - if ((new[i] & (1 << j)) != (old[i] & (1 << j))) { - kc.key = i * 8 + j; - kc.auto_repeat_mode = ((new[i] & (1 << j)) - ? AutoRepeatModeOn - : AutoRepeatModeOff); - if (kc.key >= minKeycode && kc.key <= maxKeycode) - XChangeKeyboardControl(display, mask, &kc); - } - } - } - } -} - -static void dmxCommonKbdSetLeds(Display *display, unsigned long new) -{ - int i; - XKeyboardControl kc; - - for (i = 0; i < 32; i++) { - kc.led = i + 1; - kc.led_mode = (new & (1 << i)) ? LedModeOn : LedModeOff; - XChangeKeyboardControl(display, KBLed | KBLedMode, &kc); - } -} - -static void dmxCommonKbdSetCtrl(Display *display, - KeybdCtrl *old, KeybdCtrl *new) -{ - XKeyboardControl kc; - unsigned long mask = KBKeyClickPercent | KBAutoRepeatMode; - - if (!old - || old->click != new->click - || old->autoRepeat != new->autoRepeat) { - - kc.key_click_percent = new->click; - kc.auto_repeat_mode = new->autoRepeat; - - XChangeKeyboardControl(display, mask, &kc); - } - - dmxCommonKbdSetLeds(display, new->leds); - dmxCommonKbdSetAR(display, old ? old->autoRepeats : NULL, - new->autoRepeats); -} - -static void dmxCommonMouSetCtrl(Display *display, PtrCtrl *old, PtrCtrl *new) -{ - Bool do_accel, do_threshold; - - if (!old - || old->num != new->num - || old->den != new->den - || old->threshold != new->threshold) { - do_accel = (new->num > 0 && new->den > 0); - do_threshold = (new->threshold > 0); - if (do_accel || do_threshold) { - XChangePointerControl(display, do_accel, do_threshold, - new->num, new->den, new->threshold); - } - } -} - -/** Update the keyboard control. */ -void dmxCommonKbdCtrl(DevicePtr pDev, KeybdCtrl *ctrl) -{ - GETPRIVFROMPDEV; - - if (!priv->stateSaved && priv->be) dmxCommonSaveState(priv); - if (!priv->display || !priv->stateSaved) return; - dmxCommonKbdSetCtrl(priv->display, - priv->kctrlset ? &priv->kctrl : NULL, - ctrl); - priv->kctrl = *ctrl; - priv->kctrlset = 1; -} - -/** Update the mouse control. */ -void dmxCommonMouCtrl(DevicePtr pDev, PtrCtrl *ctrl) -{ - GETPRIVFROMPDEV; - - /* Don't set the acceleration for the - * console, because that should be - * controlled by the X server that the - * console is running on. Otherwise, - * the acceleration for the console - * window would be unexpected for the - * scale of the window. */ - if (priv->be) { - dmxCommonMouSetCtrl(priv->display, - priv->mctrlset ? &priv->mctrl : NULL, - ctrl); - priv->mctrl = *ctrl; - priv->mctrlset = 1; - } -} - -/** Sound they keyboard bell. */ -void dmxCommonKbdBell(DevicePtr pDev, int percent, - int volume, int pitch, int duration) -{ - GETPRIVFROMPDEV; - XKeyboardControl kc; - XKeyboardState ks; - unsigned long mask = KBBellPercent | KBBellPitch | KBBellDuration; - - if (!priv->be) XGetKeyboardControl(priv->display, &ks); - kc.bell_percent = volume; - kc.bell_pitch = pitch; - kc.bell_duration = duration; - XChangeKeyboardControl(priv->display, mask, &kc); - XBell(priv->display, percent); - if (!priv->be) { - kc.bell_percent = ks.bell_percent; - kc.bell_pitch = ks.bell_pitch; - kc.bell_duration = ks.bell_duration; - XChangeKeyboardControl(priv->display, mask, &kc); - } -} - -/** Get the keyboard mapping. */ -void dmxCommonKbdGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) -{ - GETPRIVFROMPDEV; - int min_keycode; - int max_keycode; - int map_width; - KeySym *keyboard_mapping; - XModifierKeymap *modifier_mapping; - int i, j; - - /* Compute pKeySyms. Cast - * XGetKeyboardMapping because of - * compiler warning on 64-bit machines. - * We assume pointers to 32-bit and - * 64-bit ints are the same. */ - XDisplayKeycodes(priv->display, &min_keycode, &max_keycode); - keyboard_mapping = (KeySym *)XGetKeyboardMapping(priv->display, - min_keycode, - max_keycode - - min_keycode + 1, - &map_width); - pKeySyms->minKeyCode = min_keycode; - pKeySyms->maxKeyCode = max_keycode; - pKeySyms->mapWidth = map_width; - pKeySyms->map = keyboard_mapping; - - - /* Compute pModMap */ - modifier_mapping = XGetModifierMapping(priv->display); - for (i = 0; i < MAP_LENGTH; i++) - pModMap[i] = 0; - for (j = 0; j < 8; j++) { - int max_keypermod = modifier_mapping->max_keypermod; - - for (i = 0; i < max_keypermod; i++) { - CARD8 keycode = modifier_mapping->modifiermap[j*max_keypermod + i]; - if (keycode) - pModMap[keycode] |= 1 << j; - } - } - XFreeModifiermap(modifier_mapping); -} - -/** Fill in the XKEYBOARD parts of the \a info structure for the - * specified \a pDev. */ -void dmxCommonKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) -{ - GETPRIVFROMPDEV; - GETDMXINPUTFROMPRIV; - char *pt; - - dmxCommonSaveState(priv); - if (priv->xkb) { -#define NAME(x) \ - priv->xkb->names->x ? XGetAtomName(priv->display,priv->xkb->names->x) : NULL - info->names.keycodes = NAME(keycodes); - info->names.types = NAME(types); - info->names.compat = NAME(compat); - info->names.symbols = NAME(symbols); - info->names.geometry = NAME(geometry); - info->freenames = 1; -#undef NAME - dmxLogInput(dmxInput, - "XKEYBOARD: keycodes = %s\n", info->names.keycodes); - dmxLogInput(dmxInput, - "XKEYBOARD: symbols = %s\n", info->names.symbols); - dmxLogInput(dmxInput, - "XKEYBOARD: geometry = %s\n", info->names.geometry); - if ((pt = strchr(info->names.keycodes, '+'))) *pt = '\0'; - } - dmxCommonRestoreState(priv); -} - -/** Turn \a pDev on (i.e., take input from \a pDev). */ -int dmxCommonKbdOn(DevicePtr pDev) -{ - GETPRIVFROMPDEV; - if (priv->be) dmxCommonSaveState(priv); - priv->eventMask |= DMX_KEYBOARD_EVENT_MASK; - XSelectInput(priv->display, priv->window, priv->eventMask); - if (priv->be) - XSetInputFocus(priv->display, priv->window, RevertToPointerRoot, - CurrentTime); - return -1; -} - -/** Turn \a pDev off. */ -void dmxCommonKbdOff(DevicePtr pDev) -{ - GETPRIVFROMPDEV; - priv->eventMask &= ~DMX_KEYBOARD_EVENT_MASK; - XSelectInput(priv->display, priv->window, priv->eventMask); - dmxCommonRestoreState(priv); -} - -/** Turn \a pDev on (i.e., take input from \a pDev). */ -int dmxCommonOthOn(DevicePtr pDev) -{ - GETPRIVFROMPDEV; - GETDMXINPUTFROMPRIV; - XEventClass event_list[DMX_MAX_XINPUT_EVENT_TYPES]; - int event_type[DMX_MAX_XINPUT_EVENT_TYPES]; - int count = 0; - -#define ADD(type) \ - if (count < DMX_MAX_XINPUT_EVENT_TYPES) { \ - type(priv->xi, event_type[count], event_list[count]); \ - if (event_type[count]) { \ - dmxMapInsert(dmxLocal, event_type[count], XI_##type); \ - ++count; \ - } \ - } else { \ - dmxLog(dmxWarning, "More than %d event types for %s\n", \ - DMX_MAX_XINPUT_EVENT_TYPES, dmxInput->name); \ - } - - if (!(priv->xi = XOpenDevice(priv->display, dmxLocal->deviceId))) { - dmxLog(dmxWarning, "Cannot open %s device (id=%d) on %s\n", - dmxLocal->deviceName ? dmxLocal->deviceName : "(unknown)", - dmxLocal->deviceId, dmxInput->name); - return -1; - } - ADD(DeviceKeyPress); - ADD(DeviceKeyRelease); - ADD(DeviceButtonPress); - ADD(DeviceButtonRelease); - ADD(DeviceMotionNotify); - ADD(DeviceFocusIn); - ADD(DeviceFocusOut); - ADD(ProximityIn); - ADD(ProximityOut); - ADD(DeviceStateNotify); - ADD(DeviceMappingNotify); - ADD(ChangeDeviceNotify); - XSelectExtensionEvent(priv->display, priv->window, event_list, count); - - return -1; -} - -/** Turn \a pDev off. */ -void dmxCommonOthOff(DevicePtr pDev) -{ - GETPRIVFROMPDEV; - - if (priv->xi) XCloseDevice(priv->display, priv->xi); - priv->xi = NULL; -} - -/** Fill the \a info structure with information needed to initialize \a - * pDev. */ -void dmxCommonOthGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) -{ - GETPRIVFROMPDEV; - GETDMXINPUTFROMPRIV; - XExtensionVersion *ext; - XDeviceInfo *devices; - Display *display = priv->display; - int num; - int i, j, k; - int (*handler)(Display *, char *, char *); - - if (!display && !(display = XOpenDisplay(dmxInput->name))) - return; - - /* Print out information about the XInput Extension. */ - handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); - ext = XGetExtensionVersion(display, INAME); - XSetExtensionErrorHandler(handler); - - if (ext && ext != (XExtensionVersion *)NoSuchExtension) { - XFree(ext); - devices = XListInputDevices(display, &num); - for (i = 0; i < num; i++) { - if (devices[i].id == (XID)dmxLocal->deviceId) { - XAnyClassPtr any; - XKeyInfoPtr ki; - XButtonInfoPtr bi; - XValuatorInfoPtr vi; - for (j = 0, any = devices[i].inputclassinfo; - j < devices[i].num_classes; - any = (XAnyClassPtr)((char *)any + any->length), j++) { - switch (any->class) { - case KeyClass: - ki = (XKeyInfoPtr)any; - info->keyboard = 1; - info->keyClass = 1; - info->keySyms.minKeyCode = ki->min_keycode; - info->keySyms.maxKeyCode = ki->max_keycode; - info->kbdFeedbackClass = 1; - break; - case ButtonClass: - bi = (XButtonInfoPtr)any; - info->buttonClass = 1; - info->numButtons = bi->num_buttons; - info->ptrFeedbackClass = 1; - break; - case ValuatorClass: - /* This assume all axes are either - * Absolute or Relative. */ - vi = (XValuatorInfoPtr)any; - info->valuatorClass = 1; - if (vi->mode == Absolute) - info->numAbsAxes = vi->num_axes; - else - info->numRelAxes = vi->num_axes; - for (k = 0; k < vi->num_axes; k++) { - info->res[k] = vi->axes[k].resolution; - info->minres[k] = vi->axes[k].resolution; - info->maxres[k] = vi->axes[k].resolution; - info->minval[k] = vi->axes[k].min_value; - info->maxval[k] = vi->axes[k].max_value; - } - break; - case FeedbackClass: - /* Only keyboard and pointer feedback - * are handled at this time. */ - break; - case ProximityClass: - info->proximityClass = 1; - break; - case FocusClass: - info->focusClass = 1; - break; - case OtherClass: - break; - } - } - } - } - XFreeDeviceList(devices); - } - if (display != priv->display) XCloseDisplay(display); -} - -/** Obtain the mouse button mapping. */ -void dmxCommonMouGetMap(DevicePtr pDev, unsigned char *map, int *nButtons) -{ - GETPRIVFROMPDEV; - int i; - - *nButtons = XGetPointerMapping(priv->display, map, DMX_MAX_BUTTONS); - for (i = 0; i <= *nButtons; i++) map[i] = i; -} - -static void *dmxCommonXSelect(DMXScreenInfo *dmxScreen, void *closure) -{ - myPrivate *priv = closure; - XSelectInput(dmxScreen->beDisplay, dmxScreen->scrnWin, priv->eventMask); - return NULL; -} - -static void *dmxCommonAddEnabledDevice(DMXScreenInfo *dmxScreen, void *closure) -{ - AddEnabledDevice(XConnectionNumber(dmxScreen->beDisplay)); - return NULL; -} - -static void *dmxCommonRemoveEnabledDevice(DMXScreenInfo *dmxScreen, - void *closure) -{ - RemoveEnabledDevice(XConnectionNumber(dmxScreen->beDisplay)); - return NULL; -} - -/** Turn \a pDev on (i.e., take input from \a pDev). */ -int dmxCommonMouOn(DevicePtr pDev) -{ - GETPRIVFROMPDEV; - GETDMXINPUTFROMPRIV; - - priv->eventMask |= DMX_POINTER_EVENT_MASK; - if (dmxShadowFB) { - XWarpPointer(priv->display, priv->window, priv->window, - 0, 0, 0, 0, - priv->initPointerX, - priv->initPointerY); - dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE); - } - if (!priv->be) { - XSelectInput(priv->display, priv->window, priv->eventMask); - AddEnabledDevice(XConnectionNumber(priv->display)); - } else { - dmxPropertyIterate(priv->be, dmxCommonXSelect, priv); - dmxPropertyIterate(priv->be, dmxCommonAddEnabledDevice, dmxInput); - } - - return -1; -} - -/** Turn \a pDev off. */ -void dmxCommonMouOff(DevicePtr pDev) -{ - GETPRIVFROMPDEV; - GETDMXINPUTFROMPRIV; - - priv->eventMask &= ~DMX_POINTER_EVENT_MASK; - if (!priv->be) { - RemoveEnabledDevice(XConnectionNumber(priv->display)); - XSelectInput(priv->display, priv->window, priv->eventMask); - } else { - dmxPropertyIterate(priv->be, dmxCommonRemoveEnabledDevice, dmxInput); - dmxPropertyIterate(priv->be, dmxCommonXSelect, priv); - } -} - -/** Given the global coordinates \a x and \a y, determine the screen - * with the lowest number on which those coordinates lie. If they are - * not on any screen, return -1. The number returned is an index into - * \a dmxScreenInfo and is between -1 and \a dmxNumScreens - 1, - * inclusive. */ -int dmxFindPointerScreen(int x, int y) -{ - int i; - - for (i = 0; i < dmxNumScreens; i++) { - if (x >= dixScreenOrigins[i].x - && x < dixScreenOrigins[i].x + screenInfo.screens[i]->width - && y >= dixScreenOrigins[i].y - && y < dixScreenOrigins[i].y + screenInfo.screens[i]->height) - return i; - } - return -1; -} - -/** Returns a pointer to the private area for the device that comes just - * prior to \a pDevice in the current \a dmxInput device list. This is - * used as the private area for the current device in some situations - * (e.g., when a keyboard and mouse form a pair that should share the - * same private area). If the requested private area cannot be located, - * then NULL is returned. */ -pointer dmxCommonCopyPrivate(DeviceIntPtr pDevice) -{ - GETDMXLOCALFROMPDEVICE; - DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; - int i; - - for (i = 0; i < dmxInput->numDevs; i++) - if (dmxInput->devs[i] == dmxLocal && i) - return dmxInput->devs[i-1]->private; - return NULL; -} - -/** This routine saves and resets some important state for the backend - * and console device drivers: - * - the modifier map is saved and set to 0 (so DMX controls the LEDs) - * - the key click, bell, led, and repeat masks are saved and set to the - * values that DMX claims to be using - * - * This routine and #dmxCommonRestoreState are used when the pointer - * enters and leaves the console window, or when the backend window is - * active or not active (for a full-screen window, this only happens at - * server startup and server shutdown). - */ -void dmxCommonSaveState(pointer private) -{ - GETPRIVFROMPRIVATE; - XKeyboardState ks; - unsigned long i; - XModifierKeymap *modmap; - - if (dmxInput->console) priv = dmxInput->devs[0]->private; - if (!priv->display || priv->stateSaved) return; - DMXDBG0("dmxCommonSaveState\n"); - if (dmxUseXKB && (priv->xkb = XkbAllocKeyboard())) { - if (XkbGetIndicatorMap(priv->display, XkbAllIndicatorsMask, priv->xkb) - || XkbGetNames(priv->display, XkbAllNamesMask, priv->xkb)) { - dmxLogInput(dmxInput, "Could not get XKB information\n"); - XkbFreeKeyboard(priv->xkb, 0, True); - priv->xkb = NULL; - } else { - if (priv->xkb->indicators) { - priv->savedIndicators = *priv->xkb->indicators; - for (i = 0; i < XkbNumIndicators; i++) - if (priv->xkb->indicators->phys_indicators & (1 << i)) { - priv->xkb->indicators->maps[i].flags - = XkbIM_NoAutomatic; - } - XkbSetIndicatorMap(priv->display, ~0, priv->xkb); - } - } - } - - XGetKeyboardControl(priv->display, &ks); - priv->savedKctrl.click = ks.key_click_percent; - priv->savedKctrl.bell = ks.bell_percent; - priv->savedKctrl.bell_pitch = ks.bell_pitch; - priv->savedKctrl.bell_duration = ks.bell_duration; - priv->savedKctrl.leds = ks.led_mask; - priv->savedKctrl.autoRepeat = ks.global_auto_repeat; - for (i = 0; i < 32; i++) - priv->savedKctrl.autoRepeats[i] = ks.auto_repeats[i]; - - dmxCommonKbdSetCtrl(priv->display, &priv->savedKctrl, - &priv->dmxLocal->kctrl); - - priv->savedModMap = XGetModifierMapping(priv->display); - - modmap = XNewModifiermap(0); - XSetModifierMapping(priv->display, modmap); - if (dmxInput->scrnIdx != -1) - dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE); - XFreeModifiermap(modmap); - - priv->stateSaved = 1; -} - -/** This routine restores all the information saved by #dmxCommonSaveState. */ -void dmxCommonRestoreState(pointer private) -{ - GETPRIVFROMPRIVATE; - int retcode = -1; - CARD32 start; - - if (dmxInput->console) - priv = dmxInput->devs[0]->private; - if (!priv->stateSaved) - return; - priv->stateSaved = 0; - - DMXDBG0("dmxCommonRestoreState\n"); - if (priv->xkb) { - *priv->xkb->indicators = priv->savedIndicators; - XkbSetIndicatorMap(priv->display, ~0, priv->xkb); - XkbFreeKeyboard(priv->xkb, 0, True); - priv->xkb = 0; - } - - for (start = GetTimeInMillis(); GetTimeInMillis() - start < 5000;) { - CARD32 tmp; - - retcode = XSetModifierMapping(priv->display, priv->savedModMap); - if (retcode == MappingSuccess) - break; - if (retcode == MappingBusy) - dmxLogInput(dmxInput, "Keyboard busy, waiting\n"); - else - dmxLogInput(dmxInput, "Keyboard error, waiting\n"); - - /* Don't generate X11 protocol for a bit */ - for (tmp = GetTimeInMillis(); GetTimeInMillis() - tmp < 250;) { - usleep(250); /* This ends up sleeping only until - * the next key press generates an - * interruption. We make the delay - * relatively short in case the user - * pressed they keys quickly. */ - } - - } - if (retcode != MappingSuccess) - dmxLog(dmxWarning, "Unable to restore keyboard modifier state!\n"); - - XFreeModifiermap(priv->savedModMap); - priv->savedModMap = NULL; - - dmxCommonKbdSetCtrl(priv->display, NULL, &priv->savedKctrl); - priv->kctrlset = 0; /* Invalidate copy */ -} +/* + * 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 + * Kevin E. Martin + * Rickard E. (Rik) Faith + */ + +/** \file + * + * This file implements common routines used by the backend and console + * input devices. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#define DMX_STATE_DEBUG 0 + +#include "dmxinputinit.h" +#include "dmxcommon.h" +#include "dmxconsole.h" +#include "dmxprop.h" +#include "dmxsync.h" +#include "dmxmap.h" + +#include "inputstr.h" +#include "input.h" +#include +#include "mipointer.h" +#include "scrnintstr.h" + +#include /* For usleep() */ + +#if DMX_STATE_DEBUG +#define DMXDBG0(f) dmxLog(dmxDebug,f) +#else +#define DMXDBG0(f) +#endif + +/** Each device has a private area that is visible only from inside the + * driver code. */ +typedef struct _myPrivate { + DMX_COMMON_PRIVATE; +} myPrivate; + +static void dmxCommonKbdSetAR(Display *display, + unsigned char *old, unsigned char *new) +{ + XKeyboardControl kc; + XKeyboardState ks; + unsigned long mask = KBKey | KBAutoRepeatMode; + int i, j; + int minKeycode, maxKeycode; + + if (!old) { + XGetKeyboardControl(display, &ks); + old = (unsigned char *)ks.auto_repeats; + } + + XDisplayKeycodes(display, &minKeycode, &maxKeycode); + for (i = 1; i < 32; i++) { + if (!old || old[i] != new[i]) { + for (j = 0; j < 8; j++) { + if ((new[i] & (1 << j)) != (old[i] & (1 << j))) { + kc.key = i * 8 + j; + kc.auto_repeat_mode = ((new[i] & (1 << j)) + ? AutoRepeatModeOn + : AutoRepeatModeOff); + if (kc.key >= minKeycode && kc.key <= maxKeycode) + XChangeKeyboardControl(display, mask, &kc); + } + } + } + } +} + +static void dmxCommonKbdSetLeds(Display *display, unsigned long new) +{ + int i; + XKeyboardControl kc; + + for (i = 0; i < 32; i++) { + kc.led = i + 1; + kc.led_mode = (new & (1 << i)) ? LedModeOn : LedModeOff; + XChangeKeyboardControl(display, KBLed | KBLedMode, &kc); + } +} + +static void dmxCommonKbdSetCtrl(Display *display, + KeybdCtrl *old, KeybdCtrl *new) +{ + XKeyboardControl kc; + unsigned long mask = KBKeyClickPercent | KBAutoRepeatMode; + + if (!old + || old->click != new->click + || old->autoRepeat != new->autoRepeat) { + + kc.key_click_percent = new->click; + kc.auto_repeat_mode = new->autoRepeat; + + XChangeKeyboardControl(display, mask, &kc); + } + + dmxCommonKbdSetLeds(display, new->leds); + dmxCommonKbdSetAR(display, old ? old->autoRepeats : NULL, + new->autoRepeats); +} + +static void dmxCommonMouSetCtrl(Display *display, PtrCtrl *old, PtrCtrl *new) +{ + Bool do_accel, do_threshold; + + if (!old + || old->num != new->num + || old->den != new->den + || old->threshold != new->threshold) { + do_accel = (new->num > 0 && new->den > 0); + do_threshold = (new->threshold > 0); + if (do_accel || do_threshold) { + XChangePointerControl(display, do_accel, do_threshold, + new->num, new->den, new->threshold); + } + } +} + +/** Update the keyboard control. */ +void dmxCommonKbdCtrl(DevicePtr pDev, KeybdCtrl *ctrl) +{ + GETPRIVFROMPDEV; + + if (!priv->stateSaved && priv->be) dmxCommonSaveState(priv); + if (!priv->display || !priv->stateSaved) return; + dmxCommonKbdSetCtrl(priv->display, + priv->kctrlset ? &priv->kctrl : NULL, + ctrl); + priv->kctrl = *ctrl; + priv->kctrlset = 1; +} + +/** Update the mouse control. */ +void dmxCommonMouCtrl(DevicePtr pDev, PtrCtrl *ctrl) +{ + GETPRIVFROMPDEV; + + /* Don't set the acceleration for the + * console, because that should be + * controlled by the X server that the + * console is running on. Otherwise, + * the acceleration for the console + * window would be unexpected for the + * scale of the window. */ + if (priv->be) { + dmxCommonMouSetCtrl(priv->display, + priv->mctrlset ? &priv->mctrl : NULL, + ctrl); + priv->mctrl = *ctrl; + priv->mctrlset = 1; + } +} + +/** Sound they keyboard bell. */ +void dmxCommonKbdBell(DevicePtr pDev, int percent, + int volume, int pitch, int duration) +{ + GETPRIVFROMPDEV; + XKeyboardControl kc; + XKeyboardState ks; + unsigned long mask = KBBellPercent | KBBellPitch | KBBellDuration; + + if (!priv->be) XGetKeyboardControl(priv->display, &ks); + kc.bell_percent = volume; + kc.bell_pitch = pitch; + kc.bell_duration = duration; + XChangeKeyboardControl(priv->display, mask, &kc); + XBell(priv->display, percent); + if (!priv->be) { + kc.bell_percent = ks.bell_percent; + kc.bell_pitch = ks.bell_pitch; + kc.bell_duration = ks.bell_duration; + XChangeKeyboardControl(priv->display, mask, &kc); + } +} + +/** Get the keyboard mapping. */ +void dmxCommonKbdGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) +{ + GETPRIVFROMPDEV; + int min_keycode; + int max_keycode; + int map_width; + KeySym *keyboard_mapping; + XModifierKeymap *modifier_mapping; + int i, j; + + /* Compute pKeySyms. Cast + * XGetKeyboardMapping because of + * compiler warning on 64-bit machines. + * We assume pointers to 32-bit and + * 64-bit ints are the same. */ + XDisplayKeycodes(priv->display, &min_keycode, &max_keycode); + keyboard_mapping = (KeySym *)XGetKeyboardMapping(priv->display, + min_keycode, + max_keycode + - min_keycode + 1, + &map_width); + pKeySyms->minKeyCode = min_keycode; + pKeySyms->maxKeyCode = max_keycode; + pKeySyms->mapWidth = map_width; + pKeySyms->map = keyboard_mapping; + + + /* Compute pModMap */ + modifier_mapping = XGetModifierMapping(priv->display); + for (i = 0; i < MAP_LENGTH; i++) + pModMap[i] = 0; + for (j = 0; j < 8; j++) { + int max_keypermod = modifier_mapping->max_keypermod; + + for (i = 0; i < max_keypermod; i++) { + CARD8 keycode = modifier_mapping->modifiermap[j*max_keypermod + i]; + if (keycode) + pModMap[keycode] |= 1 << j; + } + } + XFreeModifiermap(modifier_mapping); +} + +/** Fill in the XKEYBOARD parts of the \a info structure for the + * specified \a pDev. */ +void dmxCommonKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + char *pt; + + dmxCommonSaveState(priv); + if (priv->xkb) { +#define NAME(x) \ + priv->xkb->names->x ? XGetAtomName(priv->display,priv->xkb->names->x) : NULL + info->names.keycodes = NAME(keycodes); + info->names.types = NAME(types); + info->names.compat = NAME(compat); + info->names.symbols = NAME(symbols); + info->names.geometry = NAME(geometry); + info->freenames = 1; +#undef NAME + dmxLogInput(dmxInput, + "XKEYBOARD: keycodes = %s\n", info->names.keycodes); + dmxLogInput(dmxInput, + "XKEYBOARD: symbols = %s\n", info->names.symbols); + dmxLogInput(dmxInput, + "XKEYBOARD: geometry = %s\n", info->names.geometry); + if ((pt = strchr(info->names.keycodes, '+'))) *pt = '\0'; + } + dmxCommonRestoreState(priv); +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int dmxCommonKbdOn(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + if (priv->be) dmxCommonSaveState(priv); + priv->eventMask |= DMX_KEYBOARD_EVENT_MASK; + XSelectInput(priv->display, priv->window, priv->eventMask); + if (priv->be) + XSetInputFocus(priv->display, priv->window, RevertToPointerRoot, + CurrentTime); + return -1; +} + +/** Turn \a pDev off. */ +void dmxCommonKbdOff(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + priv->eventMask &= ~DMX_KEYBOARD_EVENT_MASK; + XSelectInput(priv->display, priv->window, priv->eventMask); + dmxCommonRestoreState(priv); +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int dmxCommonOthOn(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + XEventClass event_list[DMX_MAX_XINPUT_EVENT_TYPES]; + int event_type[DMX_MAX_XINPUT_EVENT_TYPES]; + int count = 0; + +#define ADD(type) \ + if (count < DMX_MAX_XINPUT_EVENT_TYPES) { \ + type(priv->xi, event_type[count], event_list[count]); \ + if (event_type[count]) { \ + dmxMapInsert(dmxLocal, event_type[count], XI_##type); \ + ++count; \ + } \ + } else { \ + dmxLog(dmxWarning, "More than %d event types for %s\n", \ + DMX_MAX_XINPUT_EVENT_TYPES, dmxInput->name); \ + } + + if (!(priv->xi = XOpenDevice(priv->display, dmxLocal->deviceId))) { + dmxLog(dmxWarning, "Cannot open %s device (id=%d) on %s\n", + dmxLocal->deviceName ? dmxLocal->deviceName : "(unknown)", + dmxLocal->deviceId, dmxInput->name); + return -1; + } + ADD(DeviceKeyPress); + ADD(DeviceKeyRelease); + ADD(DeviceButtonPress); + ADD(DeviceButtonRelease); + ADD(DeviceMotionNotify); + ADD(DeviceFocusIn); + ADD(DeviceFocusOut); + ADD(ProximityIn); + ADD(ProximityOut); + ADD(DeviceStateNotify); + ADD(DeviceMappingNotify); + ADD(ChangeDeviceNotify); + XSelectExtensionEvent(priv->display, priv->window, event_list, count); + + return -1; +} + +/** Turn \a pDev off. */ +void dmxCommonOthOff(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + + if (priv->xi) XCloseDevice(priv->display, priv->xi); + priv->xi = NULL; +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void dmxCommonOthGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + XExtensionVersion *ext; + XDeviceInfo *devices; + Display *display = priv->display; + int num; + int i, j, k; + XextErrorHandler handler; + + if (!display && !(display = XOpenDisplay(dmxInput->name))) + return; + + /* Print out information about the XInput Extension. */ + handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); + ext = XGetExtensionVersion(display, INAME); + XSetExtensionErrorHandler(handler); + + if (ext && ext != (XExtensionVersion *)NoSuchExtension) { + XFree(ext); + devices = XListInputDevices(display, &num); + for (i = 0; i < num; i++) { + if (devices[i].id == (XID)dmxLocal->deviceId) { + XAnyClassPtr any; + XKeyInfoPtr ki; + XButtonInfoPtr bi; + XValuatorInfoPtr vi; + for (j = 0, any = devices[i].inputclassinfo; + j < devices[i].num_classes; + any = (XAnyClassPtr)((char *)any + any->length), j++) { + switch (any->class) { + case KeyClass: + ki = (XKeyInfoPtr)any; + info->keyboard = 1; + info->keyClass = 1; + info->keySyms.minKeyCode = ki->min_keycode; + info->keySyms.maxKeyCode = ki->max_keycode; + info->kbdFeedbackClass = 1; + break; + case ButtonClass: + bi = (XButtonInfoPtr)any; + info->buttonClass = 1; + info->numButtons = bi->num_buttons; + info->ptrFeedbackClass = 1; + break; + case ValuatorClass: + /* This assume all axes are either + * Absolute or Relative. */ + vi = (XValuatorInfoPtr)any; + info->valuatorClass = 1; + if (vi->mode == Absolute) + info->numAbsAxes = vi->num_axes; + else + info->numRelAxes = vi->num_axes; + for (k = 0; k < vi->num_axes; k++) { + info->res[k] = vi->axes[k].resolution; + info->minres[k] = vi->axes[k].resolution; + info->maxres[k] = vi->axes[k].resolution; + info->minval[k] = vi->axes[k].min_value; + info->maxval[k] = vi->axes[k].max_value; + } + break; + case FeedbackClass: + /* Only keyboard and pointer feedback + * are handled at this time. */ + break; + case ProximityClass: + info->proximityClass = 1; + break; + case FocusClass: + info->focusClass = 1; + break; + case OtherClass: + break; + } + } + } + } + XFreeDeviceList(devices); + } + if (display != priv->display) XCloseDisplay(display); +} + +/** Obtain the mouse button mapping. */ +void dmxCommonMouGetMap(DevicePtr pDev, unsigned char *map, int *nButtons) +{ + GETPRIVFROMPDEV; + int i; + + *nButtons = XGetPointerMapping(priv->display, map, DMX_MAX_BUTTONS); + for (i = 0; i <= *nButtons; i++) map[i] = i; +} + +static void *dmxCommonXSelect(DMXScreenInfo *dmxScreen, void *closure) +{ + myPrivate *priv = closure; + XSelectInput(dmxScreen->beDisplay, dmxScreen->scrnWin, priv->eventMask); + return NULL; +} + +static void *dmxCommonAddEnabledDevice(DMXScreenInfo *dmxScreen, void *closure) +{ + AddEnabledDevice(XConnectionNumber(dmxScreen->beDisplay)); + return NULL; +} + +static void *dmxCommonRemoveEnabledDevice(DMXScreenInfo *dmxScreen, + void *closure) +{ + RemoveEnabledDevice(XConnectionNumber(dmxScreen->beDisplay)); + return NULL; +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int dmxCommonMouOn(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + + priv->eventMask |= DMX_POINTER_EVENT_MASK; + if (dmxShadowFB) { + XWarpPointer(priv->display, priv->window, priv->window, + 0, 0, 0, 0, + priv->initPointerX, + priv->initPointerY); + dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE); + } + if (!priv->be) { + XSelectInput(priv->display, priv->window, priv->eventMask); + AddEnabledDevice(XConnectionNumber(priv->display)); + } else { + dmxPropertyIterate(priv->be, dmxCommonXSelect, priv); + dmxPropertyIterate(priv->be, dmxCommonAddEnabledDevice, dmxInput); + } + + return -1; +} + +/** Turn \a pDev off. */ +void dmxCommonMouOff(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + + priv->eventMask &= ~DMX_POINTER_EVENT_MASK; + if (!priv->be) { + RemoveEnabledDevice(XConnectionNumber(priv->display)); + XSelectInput(priv->display, priv->window, priv->eventMask); + } else { + dmxPropertyIterate(priv->be, dmxCommonRemoveEnabledDevice, dmxInput); + dmxPropertyIterate(priv->be, dmxCommonXSelect, priv); + } +} + +/** Given the global coordinates \a x and \a y, determine the screen + * with the lowest number on which those coordinates lie. If they are + * not on any screen, return -1. The number returned is an index into + * \a dmxScreenInfo and is between -1 and \a dmxNumScreens - 1, + * inclusive. */ +int dmxFindPointerScreen(int x, int y) +{ + int i; + + for (i = 0; i < dmxNumScreens; i++) { + ScreenPtr pScreen = screenInfo.screens[i]; + if (x >= pScreen->x && x < pScreen->x + pScreen->width && + y >= pScreen->y && y < pScreen->y + pScreen->height) + return i; + } + return -1; +} + +/** Returns a pointer to the private area for the device that comes just + * prior to \a pDevice in the current \a dmxInput device list. This is + * used as the private area for the current device in some situations + * (e.g., when a keyboard and mouse form a pair that should share the + * same private area). If the requested private area cannot be located, + * then NULL is returned. */ +pointer dmxCommonCopyPrivate(DeviceIntPtr pDevice) +{ + GETDMXLOCALFROMPDEVICE; + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; + int i; + + for (i = 0; i < dmxInput->numDevs; i++) + if (dmxInput->devs[i] == dmxLocal && i) + return dmxInput->devs[i-1]->private; + return NULL; +} + +/** This routine saves and resets some important state for the backend + * and console device drivers: + * - the modifier map is saved and set to 0 (so DMX controls the LEDs) + * - the key click, bell, led, and repeat masks are saved and set to the + * values that DMX claims to be using + * + * This routine and #dmxCommonRestoreState are used when the pointer + * enters and leaves the console window, or when the backend window is + * active or not active (for a full-screen window, this only happens at + * server startup and server shutdown). + */ +void dmxCommonSaveState(pointer private) +{ + GETPRIVFROMPRIVATE; + XKeyboardState ks; + unsigned long i; + XModifierKeymap *modmap; + + if (dmxInput->console) priv = dmxInput->devs[0]->private; + if (!priv->display || priv->stateSaved) return; + DMXDBG0("dmxCommonSaveState\n"); + if (dmxUseXKB && (priv->xkb = XkbAllocKeyboard())) { + if (XkbGetIndicatorMap(priv->display, XkbAllIndicatorsMask, priv->xkb) + || XkbGetNames(priv->display, XkbAllNamesMask, priv->xkb)) { + dmxLogInput(dmxInput, "Could not get XKB information\n"); + XkbFreeKeyboard(priv->xkb, 0, True); + priv->xkb = NULL; + } else { + if (priv->xkb->indicators) { + priv->savedIndicators = *priv->xkb->indicators; + for (i = 0; i < XkbNumIndicators; i++) + if (priv->xkb->indicators->phys_indicators & (1 << i)) { + priv->xkb->indicators->maps[i].flags + = XkbIM_NoAutomatic; + } + XkbSetIndicatorMap(priv->display, ~0, priv->xkb); + } + } + } + + XGetKeyboardControl(priv->display, &ks); + priv->savedKctrl.click = ks.key_click_percent; + priv->savedKctrl.bell = ks.bell_percent; + priv->savedKctrl.bell_pitch = ks.bell_pitch; + priv->savedKctrl.bell_duration = ks.bell_duration; + priv->savedKctrl.leds = ks.led_mask; + priv->savedKctrl.autoRepeat = ks.global_auto_repeat; + for (i = 0; i < 32; i++) + priv->savedKctrl.autoRepeats[i] = ks.auto_repeats[i]; + + dmxCommonKbdSetCtrl(priv->display, &priv->savedKctrl, + &priv->dmxLocal->kctrl); + + priv->savedModMap = XGetModifierMapping(priv->display); + + modmap = XNewModifiermap(0); + XSetModifierMapping(priv->display, modmap); + if (dmxInput->scrnIdx != -1) + dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE); + XFreeModifiermap(modmap); + + priv->stateSaved = 1; +} + +/** This routine restores all the information saved by #dmxCommonSaveState. */ +void dmxCommonRestoreState(pointer private) +{ + GETPRIVFROMPRIVATE; + int retcode = -1; + CARD32 start; + + if (dmxInput->console) + priv = dmxInput->devs[0]->private; + if (!priv->stateSaved) + return; + priv->stateSaved = 0; + + DMXDBG0("dmxCommonRestoreState\n"); + if (priv->xkb) { + *priv->xkb->indicators = priv->savedIndicators; + XkbSetIndicatorMap(priv->display, ~0, priv->xkb); + XkbFreeKeyboard(priv->xkb, 0, True); + priv->xkb = 0; + } + + for (start = GetTimeInMillis(); GetTimeInMillis() - start < 5000;) { + CARD32 tmp; + + retcode = XSetModifierMapping(priv->display, priv->savedModMap); + if (retcode == MappingSuccess) + break; + if (retcode == MappingBusy) + dmxLogInput(dmxInput, "Keyboard busy, waiting\n"); + else + dmxLogInput(dmxInput, "Keyboard error, waiting\n"); + + /* Don't generate X11 protocol for a bit */ + for (tmp = GetTimeInMillis(); GetTimeInMillis() - tmp < 250;) { + usleep(250); /* This ends up sleeping only until + * the next key press generates an + * interruption. We make the delay + * relatively short in case the user + * pressed they keys quickly. */ + } + + } + if (retcode != MappingSuccess) + dmxLog(dmxWarning, "Unable to restore keyboard modifier state!\n"); + + XFreeModifiermap(priv->savedModMap); + priv->savedModMap = NULL; + + dmxCommonKbdSetCtrl(priv->display, NULL, &priv->savedKctrl); + priv->kctrlset = 0; /* Invalidate copy */ +} diff --git a/xorg-server/hw/dmx/input/dmxconsole.c b/xorg-server/hw/dmx/input/dmxconsole.c index 9542efacd..d4d73f2e8 100644 --- a/xorg-server/hw/dmx/input/dmxconsole.c +++ b/xorg-server/hw/dmx/input/dmxconsole.c @@ -1,1030 +1,1029 @@ -/* - * 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 - * Kevin E. Martin - * Rickard E. (Rik) Faith - * - */ - -/** \file - * - * This file implements the console input devices. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#define DMX_CONSOLE_DEBUG 0 -#define DMX_WINDOW_DEBUG 0 - -#include "dmxinputinit.h" -#include "dmxevents.h" -#include "dmxconsole.h" -#include "dmxcommon.h" -#include "dmxscrinit.h" -#include "dmxcb.h" -#include "dmxsync.h" - -#include "inputstr.h" -#include "input.h" -#include "mipointer.h" -#include "windowstr.h" - -#define CONSOLE_NUM 3 -#define CONSOLE_DEN 4 -#define DMX_CONSOLE_NAME "DMX Console" -#define DMX_RES_NAME "Xdmx" -#define DMX_RES_CLASS "XDmx" -#define CONSOLE_BG_COLOR "gray75" -#define CONSOLE_FG_COLOR "black" -#define CONSOLE_SCREEN_BG_COLOR "white" -#define CONSOLE_SCREEN_FG_COLOR "black" -#define CONSOLE_SCREEN_DET_COLOR "gray75" -#define CONSOLE_SCREEN_CUR_COLOR "red" - -#if DMX_CONSOLE_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) -#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) -#endif - -/* Private area for consoles. */ -typedef struct _myPrivate { - DMX_COMMON_PRIVATE; - int lastX; - int lastY; - int globalX; - int globalY; - int curX; - int curY; - int width; - int height; - int consWidth; - int consHeight; - double xScale; - double yScale; - XlibGC gc, gcDet, gcRev, gcCur; - int grabbed, fine, captured; - Cursor cursorNormal, cursorGrabbed, cursorEmpty; - Pixmap pixmap; - - CloseScreenProcPtr CloseScreen; - struct _myPrivate *next; /* for closing multiple consoles */ - int initialized; - DevicePtr mou, kbd; -} myPrivate; - -static int scalex(myPrivate *priv, int x) -{ - return (int)((x * priv->xScale) + .5); -} - -static int scaley(myPrivate *priv, int y) -{ - return (int)((y * priv->yScale) + .5); -} - -static int unscalex(myPrivate *priv, int x) -{ - return (int)((x / priv->xScale) + .5); -} - -static int unscaley(myPrivate *priv, int y) -{ - return (int)((y / priv->yScale) + .5); -} - -/** Create the private area for \a pDevice. */ -pointer dmxConsoleCreatePrivate(DeviceIntPtr pDevice) -{ - GETDMXLOCALFROMPDEVICE; - myPrivate *priv = calloc(1, sizeof(*priv)); - priv->dmxLocal = dmxLocal; - return priv; -} - -/** If \a private is non-NULL, free its associated memory. */ -void dmxConsoleDestroyPrivate(pointer private) -{ - if (private) free(private); -} - -static void dmxConsoleDrawFineCursor(myPrivate *priv, XRectangle *rect) -{ - int size = 6; - int x, y; - - XDrawLine(priv->display, priv->pixmap, priv->gcCur, - x = scalex(priv, priv->globalX) - size, - scaley(priv, priv->globalY), - scalex(priv, priv->globalX) + size, - scaley(priv, priv->globalY)); - XDrawLine(priv->display, priv->pixmap, priv->gcCur, - scalex(priv, priv->globalX), - y = scaley(priv, priv->globalY) - size, - scalex(priv, priv->globalX), - scaley(priv, priv->globalY) + size); - if (priv->grabbed) { - XDrawLine(priv->display, priv->pixmap, priv->gcCur, - scalex(priv, priv->globalX) - (int)(size / 1.4), - scaley(priv, priv->globalY) - (int)(size / 1.4), - scalex(priv, priv->globalX) + (int)(size / 1.4), - scaley(priv, priv->globalY) + (int)(size / 1.4)); - XDrawLine(priv->display, priv->pixmap, priv->gcCur, - scalex(priv, priv->globalX) - (int)(size / 1.4), - scaley(priv, priv->globalY) + (int)(size / 1.4), - scalex(priv, priv->globalX) + (int)(size / 1.4), - scaley(priv, priv->globalY) - (int)(size / 1.4)); - } - if (rect) { - rect->x = x; - rect->y = y; - rect->width = 2 * size; - rect->height = 2 * size; - } -} - -static void dmxConsoleDrawWindows(pointer private) -{ - GETONLYPRIVFROMPRIVATE; - Display *dpy = priv->display; - int i; - Region whole, used, avail; - XRectangle rect; - - whole = XCreateRegion(); - used = XCreateRegion(); - avail = XCreateRegion(); - rect.x = 0; - rect.y = 0; - rect.width = priv->consWidth; - rect.height = priv->consHeight; - XUnionRectWithRegion(&rect, whole, whole); - - for (i = 0; i < dmxNumScreens; i++) { - WindowPtr pRoot = WindowTable[i]; - WindowPtr pChild; - -#if DMX_WINDOW_DEBUG - dmxLog(dmxDebug, "%lu %p %p %p 2\n", - pRoot->drawable.id, - pRoot->parent, pRoot->firstChild, pRoot->lastChild); -#endif - - for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) { - if (pChild->mapped - && pChild->realized) { -#if DMX_WINDOW_DEBUG - dmxLog(dmxDebug, " %p %d,%d %dx%d %d %d %d RECTS\n", - pChild, - pChild->drawable.x, - pChild->drawable.y, - pChild->drawable.width, - pChild->drawable.height, - pChild->visibility, - pChild->overrideRedirect, - REGION_NUM_RECTS(&pChild->clipList)); -#endif - rect.x = scalex(priv, pChild->drawable.x - + dixScreenOrigins[i].x); - rect.y = scaley(priv, pChild->drawable.y - + dixScreenOrigins[i].y); - rect.width = scalex(priv, pChild->drawable.width); - rect.height = scaley(priv, pChild->drawable.height); - XDrawRectangle(dpy, priv->pixmap, priv->gc, - rect.x, rect.y, rect.width, rect.height); - XUnionRectWithRegion(&rect, used, used); - XSubtractRegion(whole, used, avail); - XSetRegion(dpy, priv->gc, avail); - } - } -#ifdef PANORAMIX - if (!noPanoramiXExtension) break; /* Screen 0 valid with Xinerama */ -#endif - } - XDestroyRegion(avail); - XDestroyRegion(used); - XDestroyRegion(whole); - XSetClipMask(dpy, priv->gc, None); -} - -static void dmxConsoleDraw(myPrivate *priv, int updateCursor, int update) -{ - GETDMXINPUTFROMPRIV; - Display *dpy = priv->display; - int i; - - XFillRectangle(dpy, priv->pixmap, priv->gc, 0, 0, - priv->consWidth, priv->consHeight); - - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - XFillRectangle(dpy, priv->pixmap, - dmxScreen->beDisplay ? priv->gcRev : priv->gcDet, - scalex(priv, dixScreenOrigins[i].x), - scaley(priv, dixScreenOrigins[i].y), - scalex(priv, screenInfo.screens[i]->width), - scaley(priv, screenInfo.screens[i]->height)); - } - for (i = 0; i < dmxNumScreens; i++) { - XDrawRectangle(dpy, priv->pixmap, priv->gc, - scalex(priv, dixScreenOrigins[i].x), - scaley(priv, dixScreenOrigins[i].y), - scalex(priv, screenInfo.screens[i]->width), - scaley(priv, screenInfo.screens[i]->height)); - } - if (dmxInput->windows) dmxConsoleDrawWindows(priv); - if (priv->fine && updateCursor) dmxConsoleDrawFineCursor(priv, 0); - if (update) { - XCopyArea(priv->display, priv->pixmap, priv->window, priv->gc, - 0, 0, priv->consWidth, priv->consHeight, 0, 0); - XSync(priv->display, False); /* Not a backend display */ - } -} - -static void dmxConsoleClearCursor(myPrivate *priv, int x, int y, - XRectangle *rect) -{ - int cw = 14, ch = 14; /* Clear width and height */ - - rect->x = scalex(priv, x) - cw/2; - rect->y = scaley(priv, y) - ch/2; - rect->width = cw; - rect->height = ch; - XSetClipRectangles(priv->display, priv->gc, 0, 0, rect, 1, Unsorted); - XSetClipRectangles(priv->display, priv->gcDet, 0, 0, rect, 1, Unsorted); - XSetClipRectangles(priv->display, priv->gcRev, 0, 0, rect, 1, Unsorted); - dmxConsoleDraw(priv, 0, 0); - XSetClipMask(priv->display, priv->gc, None); - XSetClipMask(priv->display, priv->gcDet, None); - XSetClipMask(priv->display, priv->gcRev, None); -} - - -static void dmxConsoleUpdateFineCursor(myPrivate *priv) -{ - int leave = 0; - XRectangle rects[2]; - - dmxConsoleClearCursor(priv, priv->globalX, priv->globalY, &rects[0]); - if (priv->dmxLocal->sendsCore) { - dmxGetGlobalPosition(&priv->globalX, &priv->globalY); - } else { - priv->globalX = priv->dmxLocal->lastX; - priv->globalY = priv->dmxLocal->lastY; - } - - priv->lastX = scalex(priv, priv->width / 2); - priv->lastY = scaley(priv, priv->height / 2); - - /* Compute new warp position, which may be - outside the window */ - if (priv->globalX < 1 || priv->globalX >= priv->width) { - if (priv->globalX < 1) priv->lastX = 0; - else priv->lastX = scalex(priv, priv->width); - priv->lastY = scaley(priv, priv->globalY); - ++leave; - } - if (priv->globalY < 1 || priv->globalY >= priv->height) { - if (priv->globalY < 1) priv->lastY = 0; - else priv->lastY = scaley(priv, priv->height); - priv->lastX = scalex(priv, priv->globalX); - ++leave; - } - - /* Draw pseudo cursor in window */ - dmxConsoleDrawFineCursor(priv, &rects[1]); - - XSetClipRectangles(priv->display, priv->gc, 0, 0, rects, 2, Unsorted); - XCopyArea(priv->display, priv->pixmap, priv->window, priv->gc, - 0, 0, priv->consWidth, priv->consHeight, 0, 0); - XSetClipMask(priv->display, priv->gc, None); - - DMXDBG2("dmxConsoleUpdateFineCursor: WARP %d %d\n", - priv->lastX, priv->lastY); - XWarpPointer(priv->display, priv->window, priv->window, - 0, 0, 0, 0, priv->lastX, priv->lastY); - XSync(priv->display, False); /* Not a backend display */ - - if (leave) { - XEvent X; - while (XCheckMaskEvent(priv->display, PointerMotionMask, &X)) { - if (X.type == MotionNotify) { - if (X.xmotion.x != priv->lastX || X.xmotion.y != priv->lastY) { - DMXDBG4("Ignoring motion to %d %d after leave frm %d %d\n", - X.xmotion.x, X.xmotion.y, - priv->lastX, priv->lastY); - } - } else { - dmxLog(dmxInfo, "Ignoring event (%d): %s ****************\n", - X.type, dmxEventName(X.type)); - } - } - } - DMXDBG6("dmxConsoleUpdateFineCursor: Warp %d %d on %d %d [%d %d]\n", - priv->lastX, priv->lastY, - scalex(priv, priv->width), - scaley(priv, priv->height), - priv->globalX, priv->globalY); -} - -/** Whenever the window layout (size, position, stacking order) might be - * changed, this routine is called with the \a pWindow that changed and - * the \a type of change. This routine is called in a conservative - * fashion: the actual layout of the windows of the screen might not - * have had any human-visible changes. */ -void dmxConsoleUpdateInfo(pointer private, DMXUpdateType type, - WindowPtr pWindow) -{ - GETONLYPRIVFROMPRIVATE; - dmxConsoleDraw(priv, 1, 1); -} - -static void dmxConsoleMoveAbsolute(myPrivate *priv, int x, int y, - DevicePtr pDev, dmxMotionProcPtr motion, - DMXBlockType block) -{ - int tmpX, tmpY, v[2]; - - tmpX = unscalex(priv, x); - tmpY = unscalex(priv, y); - DMXDBG6("dmxConsoleMoveAbsolute(,%d,%d) %d %d =? %d %d\n", - x, y, tmpX, tmpY, priv->curX, priv->curY); - if (tmpX == priv->curX && tmpY == priv->curY) return; - v[0] = unscalex(priv, x); - v[1] = unscaley(priv, y); - motion(pDev, v, 0, 2, DMX_ABSOLUTE_CONFINED, block); - /* dmxConsoleUpdatePosition gets called here by dmxCoreMotion */ -} - -static void dmxConsoleMoveRelative(myPrivate *priv, int x, int y, - DevicePtr pDev, dmxMotionProcPtr motion, - DMXBlockType block) -{ - int v[2]; - /* Ignore the event generated from * warping back to middle */ - if (x == priv->lastX && y == priv->lastY) return; - v[0] = priv->lastX - x; - v[1] = priv->lastY - y; - motion(pDev, v, 0, 2, DMX_RELATIVE, block); - /* dmxConsoleUpdatePosition gets called here by dmxCoreMotion */ -} - -/** This routine gets called from #dmxCoreMotion for each motion. This - * allows the console's notion of the cursor postion to change when - * another input device actually caused the change. */ -void dmxConsoleUpdatePosition(pointer private, int x, int y) -{ - GETONLYPRIVFROMPRIVATE; - int tmpX, tmpY; - Display *dpy = priv->display; - static unsigned long dmxGeneration = 0; - - - tmpX = scalex(priv, x); - tmpY = scaley(priv, y); - DMXDBG6("dmxConsoleUpdatePosition(,%d,%d) new=%d,%d dims=%d,%d\n", - x, y, tmpX, tmpY, priv->consWidth, priv->consHeight); - - if (priv->fine) dmxConsoleUpdateFineCursor(priv); - if (tmpX != priv->curX || tmpY != priv->curY) { - if (tmpX < 0) tmpX = 0; - if (tmpY < 0) tmpY = 0; - if (tmpX >= priv->consWidth) tmpX = priv->consWidth - 1; - if (tmpY >= priv->consHeight) tmpY = priv->consHeight - 1; - priv->curX = tmpX; - priv->curY = tmpY; - if (!priv->fine) { - DMXDBG2(" WARP B %d %d\n", priv->curX, priv->curY); - XWarpPointer(dpy, priv->window, - priv->window, 0, 0, 0, 0, tmpX, tmpY); - XSync(dpy, False); /* Not a backend display */ - } - } - - if (dmxGeneration != serverGeneration) { - dmxGeneration = serverGeneration; - dmxConsoleDraw(priv, 1, 1); - } -} - -/** Collect all pending events from the console's display. Plase these - * events on the server event queue using the \a motion and \a enqueue - * routines. The \a checkspecial routine is used to check for special - * keys that need handling. \a block tells if signals should be blocked - * when updating the event queue. */ -void dmxConsoleCollectEvents(DevicePtr pDev, - dmxMotionProcPtr motion, - dmxEnqueueProcPtr enqueue, - dmxCheckSpecialProcPtr checkspecial, - DMXBlockType block) -{ - GETPRIVFROMPDEV; - GETDMXINPUTFROMPRIV; - Display *dpy = priv->display; - Window win = priv->window; - int width = priv->width; - int height = priv->height; - XEvent X, N; - XSetWindowAttributes attribs; - static int rInitialized = 0; - static Region r; - XRectangle rect; - static int raising = 0, raiseX, raiseY; /* FIXME */ - - while (XPending(dpy)) { - XNextEvent(dpy, &X); - switch(X.type) { - case VisibilityNotify: - break; - case Expose: - DMXDBG5("dmxConsoleCollectEvents: Expose #%d %d %d %d %d\n", - X.xexpose.count, - X.xexpose.x, X.xexpose.y, - X.xexpose.width, X.xexpose.height); - if (!rInitialized++) r = XCreateRegion(); - rect.x = X.xexpose.x; - rect.y = X.xexpose.y; - rect.width = X.xexpose.width; - rect.height = X.xexpose.height; - XUnionRectWithRegion(&rect, r, r); - if (X.xexpose.count == 0) { - XSetRegion(dpy, priv->gc, r); - XSetRegion(dpy, priv->gcDet, r); - XSetRegion(dpy, priv->gcRev, r); - dmxConsoleDraw(priv, 1, 1); - XSetClipMask(dpy, priv->gc, None); - XSetClipMask(dpy, priv->gcDet, None); - XSetClipMask(dpy, priv->gcRev, None); - XDestroyRegion(r); - rInitialized = 0; - } - break; - case ResizeRequest: - DMXDBG2("dmxConsoleCollectEvents: Resize %d %d\n", - X.xresizerequest.width, X.xresizerequest.height); - priv->consWidth = X.xresizerequest.width; - priv->consHeight = X.xresizerequest.height; - priv->xScale = (double)priv->consWidth / width; - priv->yScale = (double)priv->consHeight / height; - attribs.override_redirect = True; - XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &attribs); - XResizeWindow(dpy, win, priv->consWidth, priv->consHeight); - XFreePixmap(dpy, priv->pixmap); - priv->pixmap = XCreatePixmap(dpy, - RootWindow(dpy, DefaultScreen(dpy)), - priv->consWidth, - priv->consHeight, - DefaultDepth(dpy,DefaultScreen(dpy))); - dmxConsoleDraw(priv, 1, 1); - attribs.override_redirect = False; - XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &attribs); - break; - case LeaveNotify: - DMXDBG4("dmxConsoleCollectEvents: Leave @ %d,%d; r=%d f=%d\n", - X.xcrossing.x, X.xcrossing.y, raising, priv->fine); - if (!priv->captured) dmxCommonRestoreState(priv); - else { - dmxConsoleUncapture(dmxInput); - dmxCommonRestoreState(priv); - } - break; - case EnterNotify: - DMXDBG6("dmxConsoleCollectEvents: Enter %d,%d r=%d f=%d (%d,%d)\n", - X.xcrossing.x, X.xcrossing.y, raising, priv->fine, - priv->curX, priv->curY); - dmxCommonSaveState(priv); - if (raising) { - raising = 0; - dmxConsoleMoveAbsolute(priv, raiseX, raiseY, - priv->mou, motion, block); - } else { - if (priv->fine) { - /* The raise will generate an event near the center, - * which is not where the cursor should be. So we - * save the real position, do the raise, and move - * the cursor here again after the raise generates - * the event. */ - raising = 1; - raiseX = X.xcrossing.x; - raiseY = X.xcrossing.y; - XRaiseWindow(dpy, priv->window); - } - XSync(dpy, False); /* Not a backend display */ - if (!X.xcrossing.x && !X.xcrossing.y) - dmxConsoleMoveAbsolute(priv, priv->curX, priv->curY, - priv->mou, motion, block); - } - break; - case MotionNotify: - if (priv->curX == X.xmotion.x && priv->curY == X.xmotion.y) - continue; - if (XPending(dpy)) { /* do motion compression */ - XPeekEvent(dpy, &N); - if (N.type == MotionNotify) continue; - } - DMXDBG2("dmxConsoleCollectEvents: Motion %d %d\n", - X.xmotion.x, X.xmotion.y); - if (raising) { - raising = 0; - dmxConsoleMoveAbsolute(priv, raiseX, raiseY, - priv->mou, motion, block); - } else { - if (priv->fine) - dmxConsoleMoveRelative(priv, X.xmotion.x, X.xmotion.y, - priv->mou, motion, block); - else - dmxConsoleMoveAbsolute(priv, X.xmotion.x, X.xmotion.y, - priv->mou, motion, block); - } - 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; - } - } -} - -static void dmxCloseConsole(myPrivate *priv) -{ - GETDMXINPUTFROMPRIV; - dmxCommonRestoreState(priv); - if (priv->display) { - XFreeGC(priv->display, priv->gc); - XFreeGC(priv->display, priv->gcDet); - XFreeGC(priv->display, priv->gcRev); - XFreeGC(priv->display, priv->gcCur); - if (!dmxInput->console) XCloseDisplay(priv->display); - } - priv->display = NULL; -} - -static Bool dmxCloseConsoleScreen(int idx, ScreenPtr pScreen) -{ - myPrivate *priv, *last; - - for (last = priv = (myPrivate *)dixLookupPrivate(&pScreen->devPrivates, - dmxScreenPrivateKey); - priv; - priv = priv->next) dmxCloseConsole(last = priv); - - DMX_UNWRAP(CloseScreen, last, pScreen); - return pScreen->CloseScreen(idx, pScreen); -} - -static Cursor dmxConsoleCreateEmptyCursor(myPrivate *priv) -{ - char noCursorData[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - Pixmap pixmap; - Cursor cursor; - XColor color, tmpColor; - Display *dpy = priv->display; - - /* Create empty cursor for window */ - pixmap = XCreateBitmapFromData(priv->display, priv->window, - noCursorData, 8, 8); - if (!XAllocNamedColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), - "black", - &color, - &tmpColor)) - dmxLog(dmxFatal, "Cannot allocate color for cursor\n"); - cursor = XCreatePixmapCursor(dpy, pixmap, pixmap, &color, &color, 0, 0); - XFreePixmap(dpy, pixmap); - return cursor; -} - -static void dmxConsoleComputeWidthHeight(myPrivate *priv, - int *width, int *height, - double *xScale, double *yScale, - int *consWidth, int *consHeight) -{ - int screen; - Display *dpy = priv->display; - - *width = 0; - *height = 0; - *xScale = 1.0; - *yScale = 1.0; - - screen = DefaultScreen(dpy); - *consWidth = DisplayWidth(dpy, screen) * CONSOLE_NUM / CONSOLE_DEN; - *consHeight = DisplayHeight(dpy, screen) * CONSOLE_NUM / CONSOLE_DEN; - - if (*consWidth < 1) *consWidth = 1; - if (*consHeight < 1) *consHeight = 1; - -#if 1 - /* Always keep the console size similar - * to the global bounding box. */ - *width = dmxGlobalWidth; - *height = dmxGlobalHeight; -#else - /* Make the console window as big as - * possible by computing the visible - * bounding box. */ - for (i = 0; i < dmxNumScreens; i++) { - if (dixScreenOrigins[i].x+screenInfo.screens[i]->width > *width) - *width = dixScreenOrigins[i].x+screenInfo.screens[i]->width; - - if (dixScreenOrigins[i].y+screenInfo.screens[i]->height > *height) - *height = dixScreenOrigins[i].y+screenInfo.screens[i]->height; - } -#endif - - if ((double)*consWidth / *width < (double)*consHeight / *height) - *xScale = *yScale = (double)*consWidth / *width; - else - *xScale = *yScale = (double)*consHeight / *height; - - *consWidth = scalex(priv, *width); - *consHeight = scaley(priv, *height); - if (*consWidth < 1) *consWidth = 1; - if (*consHeight < 1) *consHeight = 1; -} - -/** Re-initialized the console device described by \a pDev (after a - * reconfig). */ -void dmxConsoleReInit(DevicePtr pDev) -{ - GETPRIVFROMPDEV; - Display *dpy; - - if (!priv || !priv->initialized) return; - dpy = priv->display; - - dmxConsoleComputeWidthHeight(priv, - &priv->width, &priv->height, - &priv->xScale, &priv->yScale, - &priv->consWidth, &priv->consHeight); - XResizeWindow(dpy, priv->window, priv->consWidth, priv->consHeight); - XFreePixmap(dpy, priv->pixmap); - priv->pixmap = XCreatePixmap(dpy, - RootWindow(dpy, DefaultScreen(dpy)), - priv->consWidth, - priv->consHeight, - DefaultDepth(dpy,DefaultScreen(dpy))); - dmxConsoleDraw(priv, 1, 1); -} - -/** Initialized the console device described by \a pDev. */ -void dmxConsoleInit(DevicePtr pDev) -{ - GETPRIVFROMPDEV; - DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; - int screen; - unsigned long mask; - XSetWindowAttributes attribs; - Display *dpy; - Window win; - XGCValues gcvals; - XColor color; - XClassHint class_hints; - unsigned long tmp; - - 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 */ - - if (!(dpy = priv->display = XOpenDisplay(dmxInput->name))) - dmxLog(dmxFatal, - "dmxOpenConsole: cannot open console display %s\n", - dmxInput->name); - - /* Set up defaults */ - dmxConsoleComputeWidthHeight(priv, - &priv->width, &priv->height, - &priv->xScale, &priv->yScale, - &priv->consWidth, &priv->consHeight); - - /* Private initialization using computed values or constants. */ - screen = DefaultScreen(dpy); - priv->initPointerX = scalex(priv, priv->width / 2); - priv->initPointerY = scaley(priv, priv->height / 2); - priv->eventMask = (ButtonPressMask - | ButtonReleaseMask - | PointerMotionMask - | EnterWindowMask - | LeaveWindowMask - | KeyPressMask - | KeyReleaseMask - | ExposureMask - | ResizeRedirectMask); - - mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect; - attribs.colormap = DefaultColormap(dpy, screen); - if (XParseColor(dpy, attribs.colormap, CONSOLE_BG_COLOR, &color) - && XAllocColor(dpy, attribs.colormap, &color)) { - attribs.background_pixel = color.pixel; - } else - attribs.background_pixel = WhitePixel(dpy, screen); - - attribs.event_mask = priv->eventMask; - attribs.override_redirect = False; - - win = priv->window = XCreateWindow(dpy, - RootWindow(dpy, screen), - 0, 0, priv->consWidth, priv->consHeight, - 0, - DefaultDepth(dpy, screen), - InputOutput, - DefaultVisual(dpy, screen), - mask, &attribs); - priv->pixmap = XCreatePixmap(dpy, RootWindow(dpy, screen), - priv->consWidth, priv->consHeight, - DefaultDepth(dpy, screen)); - - /* Set up properties */ - XStoreName(dpy, win, DMX_CONSOLE_NAME); - class_hints.res_name = DMX_RES_NAME; - class_hints.res_class = DMX_RES_CLASS; - XSetClassHint(dpy, win, &class_hints); - - - /* Map the window */ - XMapWindow(dpy, win); - - /* Create cursors */ - priv->cursorNormal = XCreateFontCursor(dpy, XC_circle); - priv->cursorGrabbed = XCreateFontCursor(dpy, XC_spider); - priv->cursorEmpty = dmxConsoleCreateEmptyCursor(priv); - XDefineCursor(dpy, priv->window, priv->cursorNormal); - - /* Create GC */ - mask = (GCFunction | GCPlaneMask | GCClipMask | GCForeground | - GCBackground | GCLineWidth | GCLineStyle | GCCapStyle | - GCFillStyle | GCGraphicsExposures); - gcvals.function = GXcopy; - gcvals.plane_mask = AllPlanes; - gcvals.clip_mask = None; - if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_FG_COLOR, &color) - && XAllocColor(dpy, attribs.colormap, &color)) { - gcvals.foreground = color.pixel; - } else - gcvals.foreground = BlackPixel(dpy, screen); - if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_BG_COLOR, &color) - && XAllocColor(dpy, attribs.colormap, &color)) { - gcvals.background = color.pixel; - } else - gcvals.background = WhitePixel(dpy, screen); - gcvals.line_width = 0; - gcvals.line_style = LineSolid; - gcvals.cap_style = CapNotLast; - gcvals.fill_style = FillSolid; - gcvals.graphics_exposures = False; - - priv->gc = XCreateGC(dpy, win, mask, &gcvals); - - tmp = gcvals.foreground; - if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_DET_COLOR, &color) - && XAllocColor(dpy, attribs.colormap, &color)) { - gcvals.foreground = color.pixel; - } else - gcvals.foreground = BlackPixel(dpy, screen); - priv->gcDet = XCreateGC(dpy, win, mask, &gcvals); - gcvals.foreground = tmp; - - tmp = gcvals.background; - gcvals.background = gcvals.foreground; - gcvals.foreground = tmp; - priv->gcRev = XCreateGC(dpy, win, mask, &gcvals); - - gcvals.background = gcvals.foreground; - if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_CUR_COLOR, &color) - && XAllocColor(dpy, attribs.colormap, &color)) { - gcvals.foreground = color.pixel; - } else - gcvals.foreground = BlackPixel(dpy, screen); - priv->gcCur = XCreateGC(dpy, win, mask, &gcvals); - - dmxConsoleDraw(priv, 1, 1); - - if (dixLookupPrivate(&screenInfo.screens[0]->devPrivates, - dmxScreenPrivateKey)) - priv->next = dixLookupPrivate(&screenInfo.screens[0]->devPrivates, - dmxScreenPrivateKey); - else - DMX_WRAP(CloseScreen, dmxCloseConsoleScreen, - priv, screenInfo.screens[0]); - dixSetPrivate(&screenInfo.screens[0]->devPrivates, dmxScreenPrivateKey, - priv); -} - -/** Fill in the \a info structure for the specified \a pDev. Only used - * for pointers. */ -void dmxConsoleMouGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) -{ - GETPRIVFROMPDEV; - - info->buttonClass = 1; - dmxCommonMouGetMap(pDev, info->map, &info->numButtons); - info->valuatorClass = 1; - info->numRelAxes = 2; - info->minval[0] = 0; - info->minval[1] = 0; - /* max possible console window size: */ - info->maxval[0] = DisplayWidth(priv->display, DefaultScreen(priv->display)); - info->maxval[1] = DisplayHeight(priv->display, DefaultScreen(priv->display)); - info->res[0] = 1; - info->minres[0] = 0; - info->maxres[0] = 1; - info->ptrFeedbackClass = 1; -} - -/** Fill in the \a info structure for the specified \a pDev. Only used - * for keyboard. */ -void dmxConsoleKbdGetInfo(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; -} - -/** Handle special console-only keys. */ -int dmxConsoleFunctions(pointer private, DMXFunctionType function) -{ - GETONLYPRIVFROMPRIVATE; - XRectangle rect; - Display *dpy = priv->display; - - switch (function) { - case DMX_FUNCTION_FINE: - if (priv->fine) { - priv->fine = 0; - dmxConsoleClearCursor(priv, priv->globalX, priv->globalY, &rect); - XSetClipRectangles(dpy, priv->gc, 0, 0, &rect, 1, Unsorted); - XCopyArea(dpy, priv->pixmap, priv->window, priv->gc, - 0, 0, priv->consWidth, priv->consHeight, 0, 0); - XSetClipMask(dpy, priv->gc, None); - - XDefineCursor(dpy, priv->window, - priv->grabbed - ? priv->cursorGrabbed - : priv->cursorNormal); - XWarpPointer(dpy, priv->window, priv->window, - 0, 0, 0, 0, - scalex(priv, priv->globalX), - scaley(priv, priv->globalY)); - XSync(dpy, False); /* Not a backend display */ - } else { - priv->fine = 1; - XRaiseWindow(dpy, priv->window); - XDefineCursor(dpy, priv->window, priv->cursorEmpty); - dmxConsoleUpdateFineCursor(priv); - } - return 1; - case DMX_FUNCTION_GRAB: - if (priv->grabbed) { - XUngrabKeyboard(dpy, CurrentTime); - XUngrabPointer(dpy, CurrentTime); - XDefineCursor(dpy, priv->window, - priv->fine - ? priv->cursorEmpty - : priv->cursorNormal); - } else { - if (XGrabPointer(dpy, priv->window, True, - 0, GrabModeAsync, GrabModeAsync, priv->window, - None, CurrentTime)) { - dmxLog(dmxError, "XGrabPointer failed\n"); - return 0; - } - if (XGrabKeyboard(dpy, priv->window, True, - GrabModeAsync, GrabModeAsync, CurrentTime)) { - dmxLog(dmxError, "XGrabKeyboard failed\n"); - XUngrabPointer(dpy, CurrentTime); - return 0; - } - XDefineCursor(dpy, priv->window, - priv->fine - ? priv->cursorEmpty - : priv->cursorGrabbed); - } - priv->grabbed = !priv->grabbed; - if (priv->fine) dmxConsoleUpdateFineCursor(priv); - return 1; - case DMX_FUNCTION_TERMINATE: - return 1; - default: - return 0; - } -} - -static void dmxDump(void) -{ - int i, j; - DMXInputInfo *dmxInput; - XEvent X; - - for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) { - for (j = 0; j < dmxInput->numDevs; j++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; - myPrivate *priv = dmxLocal->private; - while (priv - && priv->display - && XCheckTypedEvent(priv->display, MotionNotify, &X)) { - DMXDBG4("dmxDump: %s/%d threw event away %d %s\n", - dmxInput->name, j, X.type, dmxEventName(X.type)); - } - } - } -} - -/** This routine is used to warp the pointer into the console window - * from anywhere on the screen. It is used when backend and console - * input are both being taken from the same X display. */ -void dmxConsoleCapture(DMXInputInfo *dmxInput) -{ - int i; - XEvent X; - - DMXDBG0("dmxConsoleCapture\n"); - dmxSync(NULL, TRUE); - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - myPrivate *priv = dmxLocal->private; - if (dmxLocal->extType != DMX_LOCAL_TYPE_CONSOLE) continue; - if (dmxLocal->type != DMX_LOCAL_MOUSE) continue; - if (priv->captured) continue; - priv->captured = 2; /* Ungrab only after proximal events. */ - XRaiseWindow(priv->display, priv->window); - XSync(priv->display, False); /* Not a backend display */ - while (XCheckTypedEvent(priv->display, MotionNotify, &X)) { - DMXDBG3(" Ignoring motion to %d %d after capture on %s\n", - X.xmotion.x, X.xmotion.y, dmxInput->name); - } - XWarpPointer(priv->display, None, - priv->window, 0, 0, 0, 0, priv->curX, priv->curY); - XSync(priv->display, False); /* Not a backend display */ - dmxDump(); - if (priv->fine) dmxConsoleUpdateFineCursor(priv); - } -} - -/** Undo the capture that was done by #dmxConsoleCapture. */ -void dmxConsoleUncapture(DMXInputInfo *dmxInput) -{ - int i; - - DMXDBG0("dmxConsoleUncapture\n"); - dmxSync(NULL, TRUE); - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - myPrivate *priv = dmxLocal->private; - if (dmxLocal->extType != DMX_LOCAL_TYPE_CONSOLE) continue; - if (dmxLocal->type != DMX_LOCAL_MOUSE) continue; - if (!priv->captured) continue; - priv->captured = 0; - XSync(priv->display, False); /* Not a backend display */ - } -} +/* + * 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 + * Kevin E. Martin + * Rickard E. (Rik) Faith + * + */ + +/** \file + * + * This file implements the console input devices. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#define DMX_CONSOLE_DEBUG 0 +#define DMX_WINDOW_DEBUG 0 + +#include "dmxinputinit.h" +#include "dmxevents.h" +#include "dmxconsole.h" +#include "dmxcommon.h" +#include "dmxscrinit.h" +#include "dmxcb.h" +#include "dmxsync.h" + +#include "inputstr.h" +#include "input.h" +#include "mipointer.h" +#include "windowstr.h" + +#define CONSOLE_NUM 3 +#define CONSOLE_DEN 4 +#define DMX_CONSOLE_NAME "DMX Console" +#define DMX_RES_NAME "Xdmx" +#define DMX_RES_CLASS "XDmx" +#define CONSOLE_BG_COLOR "gray75" +#define CONSOLE_FG_COLOR "black" +#define CONSOLE_SCREEN_BG_COLOR "white" +#define CONSOLE_SCREEN_FG_COLOR "black" +#define CONSOLE_SCREEN_DET_COLOR "gray75" +#define CONSOLE_SCREEN_CUR_COLOR "red" + +#if DMX_CONSOLE_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) +#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) +#endif + +/* Private area for consoles. */ +typedef struct _myPrivate { + DMX_COMMON_PRIVATE; + int lastX; + int lastY; + int globalX; + int globalY; + int curX; + int curY; + int width; + int height; + int consWidth; + int consHeight; + double xScale; + double yScale; + XlibGC gc, gcDet, gcRev, gcCur; + int grabbed, fine, captured; + Cursor cursorNormal, cursorGrabbed, cursorEmpty; + Pixmap pixmap; + + CloseScreenProcPtr CloseScreen; + struct _myPrivate *next; /* for closing multiple consoles */ + int initialized; + DevicePtr mou, kbd; +} myPrivate; + +static int scalex(myPrivate *priv, int x) +{ + return (int)((x * priv->xScale) + .5); +} + +static int scaley(myPrivate *priv, int y) +{ + return (int)((y * priv->yScale) + .5); +} + +static int unscalex(myPrivate *priv, int x) +{ + return (int)((x / priv->xScale) + .5); +} + +static int unscaley(myPrivate *priv, int y) +{ + return (int)((y / priv->yScale) + .5); +} + +/** Create the private area for \a pDevice. */ +pointer dmxConsoleCreatePrivate(DeviceIntPtr pDevice) +{ + GETDMXLOCALFROMPDEVICE; + myPrivate *priv = calloc(1, sizeof(*priv)); + priv->dmxLocal = dmxLocal; + return priv; +} + +/** If \a private is non-NULL, free its associated memory. */ +void dmxConsoleDestroyPrivate(pointer private) +{ + free(private); +} + +static void dmxConsoleDrawFineCursor(myPrivate *priv, XRectangle *rect) +{ + int size = 6; + int x, y; + + XDrawLine(priv->display, priv->pixmap, priv->gcCur, + x = scalex(priv, priv->globalX) - size, + scaley(priv, priv->globalY), + scalex(priv, priv->globalX) + size, + scaley(priv, priv->globalY)); + XDrawLine(priv->display, priv->pixmap, priv->gcCur, + scalex(priv, priv->globalX), + y = scaley(priv, priv->globalY) - size, + scalex(priv, priv->globalX), + scaley(priv, priv->globalY) + size); + if (priv->grabbed) { + XDrawLine(priv->display, priv->pixmap, priv->gcCur, + scalex(priv, priv->globalX) - (int)(size / 1.4), + scaley(priv, priv->globalY) - (int)(size / 1.4), + scalex(priv, priv->globalX) + (int)(size / 1.4), + scaley(priv, priv->globalY) + (int)(size / 1.4)); + XDrawLine(priv->display, priv->pixmap, priv->gcCur, + scalex(priv, priv->globalX) - (int)(size / 1.4), + scaley(priv, priv->globalY) + (int)(size / 1.4), + scalex(priv, priv->globalX) + (int)(size / 1.4), + scaley(priv, priv->globalY) - (int)(size / 1.4)); + } + if (rect) { + rect->x = x; + rect->y = y; + rect->width = 2 * size; + rect->height = 2 * size; + } +} + +static void dmxConsoleDrawWindows(pointer private) +{ + GETONLYPRIVFROMPRIVATE; + Display *dpy = priv->display; + int i; + Region whole, used, avail; + XRectangle rect; + + whole = XCreateRegion(); + used = XCreateRegion(); + avail = XCreateRegion(); + rect.x = 0; + rect.y = 0; + rect.width = priv->consWidth; + rect.height = priv->consHeight; + XUnionRectWithRegion(&rect, whole, whole); + + for (i = 0; i < dmxNumScreens; i++) { + ScreenPtr pScreen = screenInfo.screens[i]; + WindowPtr pRoot = pScreen->root; + WindowPtr pChild; + +#if DMX_WINDOW_DEBUG + dmxLog(dmxDebug, "%lu %p %p %p 2\n", + pRoot->drawable.id, + pRoot->parent, pRoot->firstChild, pRoot->lastChild); +#endif + + for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) { + if (pChild->mapped + && pChild->realized) { +#if DMX_WINDOW_DEBUG + dmxLog(dmxDebug, " %p %d,%d %dx%d %d %d %d RECTS\n", + pChild, + pChild->drawable.x, + pChild->drawable.y, + pChild->drawable.width, + pChild->drawable.height, + pChild->visibility, + pChild->overrideRedirect, + RegionNumRects(&pChild->clipList)); +#endif + rect.x = scalex(priv, pChild->drawable.x + pScreen->x); + rect.y = scaley(priv, pChild->drawable.y + pScreen->y); + rect.width = scalex(priv, pChild->drawable.width); + rect.height = scaley(priv, pChild->drawable.height); + XDrawRectangle(dpy, priv->pixmap, priv->gc, + rect.x, rect.y, rect.width, rect.height); + XUnionRectWithRegion(&rect, used, used); + XSubtractRegion(whole, used, avail); + XSetRegion(dpy, priv->gc, avail); + } + } +#ifdef PANORAMIX + if (!noPanoramiXExtension) break; /* Screen 0 valid with Xinerama */ +#endif + } + XDestroyRegion(avail); + XDestroyRegion(used); + XDestroyRegion(whole); + XSetClipMask(dpy, priv->gc, None); +} + +static void dmxConsoleDraw(myPrivate *priv, int updateCursor, int update) +{ + GETDMXINPUTFROMPRIV; + Display *dpy = priv->display; + int i; + + XFillRectangle(dpy, priv->pixmap, priv->gc, 0, 0, + priv->consWidth, priv->consHeight); + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + XFillRectangle(dpy, priv->pixmap, + dmxScreen->beDisplay ? priv->gcRev : priv->gcDet, + scalex(priv, screenInfo.screens[i]->x), + scaley(priv, screenInfo.screens[i]->y), + scalex(priv, screenInfo.screens[i]->width), + scaley(priv, screenInfo.screens[i]->height)); + } + for (i = 0; i < dmxNumScreens; i++) { + XDrawRectangle(dpy, priv->pixmap, priv->gc, + scalex(priv, screenInfo.screens[i]->x), + scaley(priv, screenInfo.screens[i]->y), + scalex(priv, screenInfo.screens[i]->width), + scaley(priv, screenInfo.screens[i]->height)); + } + if (dmxInput->windows) dmxConsoleDrawWindows(priv); + if (priv->fine && updateCursor) dmxConsoleDrawFineCursor(priv, 0); + if (update) { + XCopyArea(priv->display, priv->pixmap, priv->window, priv->gc, + 0, 0, priv->consWidth, priv->consHeight, 0, 0); + XSync(priv->display, False); /* Not a backend display */ + } +} + +static void dmxConsoleClearCursor(myPrivate *priv, int x, int y, + XRectangle *rect) +{ + int cw = 14, ch = 14; /* Clear width and height */ + + rect->x = scalex(priv, x) - cw/2; + rect->y = scaley(priv, y) - ch/2; + rect->width = cw; + rect->height = ch; + XSetClipRectangles(priv->display, priv->gc, 0, 0, rect, 1, Unsorted); + XSetClipRectangles(priv->display, priv->gcDet, 0, 0, rect, 1, Unsorted); + XSetClipRectangles(priv->display, priv->gcRev, 0, 0, rect, 1, Unsorted); + dmxConsoleDraw(priv, 0, 0); + XSetClipMask(priv->display, priv->gc, None); + XSetClipMask(priv->display, priv->gcDet, None); + XSetClipMask(priv->display, priv->gcRev, None); +} + + +static void dmxConsoleUpdateFineCursor(myPrivate *priv) +{ + int leave = 0; + XRectangle rects[2]; + + dmxConsoleClearCursor(priv, priv->globalX, priv->globalY, &rects[0]); + if (priv->dmxLocal->sendsCore) { + dmxGetGlobalPosition(&priv->globalX, &priv->globalY); + } else { + priv->globalX = priv->dmxLocal->lastX; + priv->globalY = priv->dmxLocal->lastY; + } + + priv->lastX = scalex(priv, priv->width / 2); + priv->lastY = scaley(priv, priv->height / 2); + + /* Compute new warp position, which may be + outside the window */ + if (priv->globalX < 1 || priv->globalX >= priv->width) { + if (priv->globalX < 1) priv->lastX = 0; + else priv->lastX = scalex(priv, priv->width); + priv->lastY = scaley(priv, priv->globalY); + ++leave; + } + if (priv->globalY < 1 || priv->globalY >= priv->height) { + if (priv->globalY < 1) priv->lastY = 0; + else priv->lastY = scaley(priv, priv->height); + priv->lastX = scalex(priv, priv->globalX); + ++leave; + } + + /* Draw pseudo cursor in window */ + dmxConsoleDrawFineCursor(priv, &rects[1]); + + XSetClipRectangles(priv->display, priv->gc, 0, 0, rects, 2, Unsorted); + XCopyArea(priv->display, priv->pixmap, priv->window, priv->gc, + 0, 0, priv->consWidth, priv->consHeight, 0, 0); + XSetClipMask(priv->display, priv->gc, None); + + DMXDBG2("dmxConsoleUpdateFineCursor: WARP %d %d\n", + priv->lastX, priv->lastY); + XWarpPointer(priv->display, priv->window, priv->window, + 0, 0, 0, 0, priv->lastX, priv->lastY); + XSync(priv->display, False); /* Not a backend display */ + + if (leave) { + XEvent X; + while (XCheckMaskEvent(priv->display, PointerMotionMask, &X)) { + if (X.type == MotionNotify) { + if (X.xmotion.x != priv->lastX || X.xmotion.y != priv->lastY) { + DMXDBG4("Ignoring motion to %d %d after leave frm %d %d\n", + X.xmotion.x, X.xmotion.y, + priv->lastX, priv->lastY); + } + } else { + dmxLog(dmxInfo, "Ignoring event (%d): %s ****************\n", + X.type, dmxEventName(X.type)); + } + } + } + DMXDBG6("dmxConsoleUpdateFineCursor: Warp %d %d on %d %d [%d %d]\n", + priv->lastX, priv->lastY, + scalex(priv, priv->width), + scaley(priv, priv->height), + priv->globalX, priv->globalY); +} + +/** Whenever the window layout (size, position, stacking order) might be + * changed, this routine is called with the \a pWindow that changed and + * the \a type of change. This routine is called in a conservative + * fashion: the actual layout of the windows of the screen might not + * have had any human-visible changes. */ +void dmxConsoleUpdateInfo(pointer private, DMXUpdateType type, + WindowPtr pWindow) +{ + GETONLYPRIVFROMPRIVATE; + dmxConsoleDraw(priv, 1, 1); +} + +static void dmxConsoleMoveAbsolute(myPrivate *priv, int x, int y, + DevicePtr pDev, dmxMotionProcPtr motion, + DMXBlockType block) +{ + int tmpX, tmpY, v[2]; + + tmpX = unscalex(priv, x); + tmpY = unscalex(priv, y); + DMXDBG6("dmxConsoleMoveAbsolute(,%d,%d) %d %d =? %d %d\n", + x, y, tmpX, tmpY, priv->curX, priv->curY); + if (tmpX == priv->curX && tmpY == priv->curY) return; + v[0] = unscalex(priv, x); + v[1] = unscaley(priv, y); + motion(pDev, v, 0, 2, DMX_ABSOLUTE_CONFINED, block); + /* dmxConsoleUpdatePosition gets called here by dmxCoreMotion */ +} + +static void dmxConsoleMoveRelative(myPrivate *priv, int x, int y, + DevicePtr pDev, dmxMotionProcPtr motion, + DMXBlockType block) +{ + int v[2]; + /* Ignore the event generated from * warping back to middle */ + if (x == priv->lastX && y == priv->lastY) return; + v[0] = priv->lastX - x; + v[1] = priv->lastY - y; + motion(pDev, v, 0, 2, DMX_RELATIVE, block); + /* dmxConsoleUpdatePosition gets called here by dmxCoreMotion */ +} + +/** This routine gets called from #dmxCoreMotion for each motion. This + * allows the console's notion of the cursor postion to change when + * another input device actually caused the change. */ +void dmxConsoleUpdatePosition(pointer private, int x, int y) +{ + GETONLYPRIVFROMPRIVATE; + int tmpX, tmpY; + Display *dpy = priv->display; + static unsigned long dmxGeneration = 0; + + + tmpX = scalex(priv, x); + tmpY = scaley(priv, y); + DMXDBG6("dmxConsoleUpdatePosition(,%d,%d) new=%d,%d dims=%d,%d\n", + x, y, tmpX, tmpY, priv->consWidth, priv->consHeight); + + if (priv->fine) dmxConsoleUpdateFineCursor(priv); + if (tmpX != priv->curX || tmpY != priv->curY) { + if (tmpX < 0) tmpX = 0; + if (tmpY < 0) tmpY = 0; + if (tmpX >= priv->consWidth) tmpX = priv->consWidth - 1; + if (tmpY >= priv->consHeight) tmpY = priv->consHeight - 1; + priv->curX = tmpX; + priv->curY = tmpY; + if (!priv->fine) { + DMXDBG2(" WARP B %d %d\n", priv->curX, priv->curY); + XWarpPointer(dpy, priv->window, + priv->window, 0, 0, 0, 0, tmpX, tmpY); + XSync(dpy, False); /* Not a backend display */ + } + } + + if (dmxGeneration != serverGeneration) { + dmxGeneration = serverGeneration; + dmxConsoleDraw(priv, 1, 1); + } +} + +/** Collect all pending events from the console's display. Plase these + * events on the server event queue using the \a motion and \a enqueue + * routines. The \a checkspecial routine is used to check for special + * keys that need handling. \a block tells if signals should be blocked + * when updating the event queue. */ +void dmxConsoleCollectEvents(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + dmxCheckSpecialProcPtr checkspecial, + DMXBlockType block) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + Display *dpy = priv->display; + Window win = priv->window; + int width = priv->width; + int height = priv->height; + XEvent X, N; + XSetWindowAttributes attribs; + static int rInitialized = 0; + static Region r; + XRectangle rect; + static int raising = 0, raiseX, raiseY; /* FIXME */ + + while (XPending(dpy)) { + XNextEvent(dpy, &X); + switch(X.type) { + case VisibilityNotify: + break; + case Expose: + DMXDBG5("dmxConsoleCollectEvents: Expose #%d %d %d %d %d\n", + X.xexpose.count, + X.xexpose.x, X.xexpose.y, + X.xexpose.width, X.xexpose.height); + if (!rInitialized++) r = XCreateRegion(); + rect.x = X.xexpose.x; + rect.y = X.xexpose.y; + rect.width = X.xexpose.width; + rect.height = X.xexpose.height; + XUnionRectWithRegion(&rect, r, r); + if (X.xexpose.count == 0) { + XSetRegion(dpy, priv->gc, r); + XSetRegion(dpy, priv->gcDet, r); + XSetRegion(dpy, priv->gcRev, r); + dmxConsoleDraw(priv, 1, 1); + XSetClipMask(dpy, priv->gc, None); + XSetClipMask(dpy, priv->gcDet, None); + XSetClipMask(dpy, priv->gcRev, None); + XDestroyRegion(r); + rInitialized = 0; + } + break; + case ResizeRequest: + DMXDBG2("dmxConsoleCollectEvents: Resize %d %d\n", + X.xresizerequest.width, X.xresizerequest.height); + priv->consWidth = X.xresizerequest.width; + priv->consHeight = X.xresizerequest.height; + priv->xScale = (double)priv->consWidth / width; + priv->yScale = (double)priv->consHeight / height; + attribs.override_redirect = True; + XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &attribs); + XResizeWindow(dpy, win, priv->consWidth, priv->consHeight); + XFreePixmap(dpy, priv->pixmap); + priv->pixmap = XCreatePixmap(dpy, + RootWindow(dpy, DefaultScreen(dpy)), + priv->consWidth, + priv->consHeight, + DefaultDepth(dpy,DefaultScreen(dpy))); + dmxConsoleDraw(priv, 1, 1); + attribs.override_redirect = False; + XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &attribs); + break; + case LeaveNotify: + DMXDBG4("dmxConsoleCollectEvents: Leave @ %d,%d; r=%d f=%d\n", + X.xcrossing.x, X.xcrossing.y, raising, priv->fine); + if (!priv->captured) dmxCommonRestoreState(priv); + else { + dmxConsoleUncapture(dmxInput); + dmxCommonRestoreState(priv); + } + break; + case EnterNotify: + DMXDBG6("dmxConsoleCollectEvents: Enter %d,%d r=%d f=%d (%d,%d)\n", + X.xcrossing.x, X.xcrossing.y, raising, priv->fine, + priv->curX, priv->curY); + dmxCommonSaveState(priv); + if (raising) { + raising = 0; + dmxConsoleMoveAbsolute(priv, raiseX, raiseY, + priv->mou, motion, block); + } else { + if (priv->fine) { + /* The raise will generate an event near the center, + * which is not where the cursor should be. So we + * save the real position, do the raise, and move + * the cursor here again after the raise generates + * the event. */ + raising = 1; + raiseX = X.xcrossing.x; + raiseY = X.xcrossing.y; + XRaiseWindow(dpy, priv->window); + } + XSync(dpy, False); /* Not a backend display */ + if (!X.xcrossing.x && !X.xcrossing.y) + dmxConsoleMoveAbsolute(priv, priv->curX, priv->curY, + priv->mou, motion, block); + } + break; + case MotionNotify: + if (priv->curX == X.xmotion.x && priv->curY == X.xmotion.y) + continue; + if (XPending(dpy)) { /* do motion compression */ + XPeekEvent(dpy, &N); + if (N.type == MotionNotify) continue; + } + DMXDBG2("dmxConsoleCollectEvents: Motion %d %d\n", + X.xmotion.x, X.xmotion.y); + if (raising) { + raising = 0; + dmxConsoleMoveAbsolute(priv, raiseX, raiseY, + priv->mou, motion, block); + } else { + if (priv->fine) + dmxConsoleMoveRelative(priv, X.xmotion.x, X.xmotion.y, + priv->mou, motion, block); + else + dmxConsoleMoveAbsolute(priv, X.xmotion.x, X.xmotion.y, + priv->mou, motion, block); + } + 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; + } + } +} + +static void dmxCloseConsole(myPrivate *priv) +{ + GETDMXINPUTFROMPRIV; + dmxCommonRestoreState(priv); + if (priv->display) { + XFreeGC(priv->display, priv->gc); + XFreeGC(priv->display, priv->gcDet); + XFreeGC(priv->display, priv->gcRev); + XFreeGC(priv->display, priv->gcCur); + if (!dmxInput->console) XCloseDisplay(priv->display); + } + priv->display = NULL; +} + +static Bool dmxCloseConsoleScreen(int idx, ScreenPtr pScreen) +{ + myPrivate *priv, *last; + + for (last = priv = (myPrivate *)dixLookupPrivate(&pScreen->devPrivates, + dmxScreenPrivateKey); + priv; + priv = priv->next) dmxCloseConsole(last = priv); + + DMX_UNWRAP(CloseScreen, last, pScreen); + return pScreen->CloseScreen(idx, pScreen); +} + +static Cursor dmxConsoleCreateEmptyCursor(myPrivate *priv) +{ + char noCursorData[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + Pixmap pixmap; + Cursor cursor; + XColor color, tmpColor; + Display *dpy = priv->display; + + /* Create empty cursor for window */ + pixmap = XCreateBitmapFromData(priv->display, priv->window, + noCursorData, 8, 8); + if (!XAllocNamedColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), + "black", + &color, + &tmpColor)) + dmxLog(dmxFatal, "Cannot allocate color for cursor\n"); + cursor = XCreatePixmapCursor(dpy, pixmap, pixmap, &color, &color, 0, 0); + XFreePixmap(dpy, pixmap); + return cursor; +} + +static void dmxConsoleComputeWidthHeight(myPrivate *priv, + int *width, int *height, + double *xScale, double *yScale, + int *consWidth, int *consHeight) +{ + int screen; + Display *dpy = priv->display; + + *width = 0; + *height = 0; + *xScale = 1.0; + *yScale = 1.0; + + screen = DefaultScreen(dpy); + *consWidth = DisplayWidth(dpy, screen) * CONSOLE_NUM / CONSOLE_DEN; + *consHeight = DisplayHeight(dpy, screen) * CONSOLE_NUM / CONSOLE_DEN; + + if (*consWidth < 1) *consWidth = 1; + if (*consHeight < 1) *consHeight = 1; + +#if 1 + /* Always keep the console size similar + * to the global bounding box. */ + *width = dmxGlobalWidth; + *height = dmxGlobalHeight; +#else + /* Make the console window as big as + * possible by computing the visible + * bounding box. */ + for (i = 0; i < dmxNumScreens; i++) { + if (screenInfo.screens[i]->x+screenInfo.screens[i]->width > *width) + *width = screenInfo.screens[i]->x+screenInfo.screens[i]->width; + + if (screenInfo.screens[i]->y+screenInfo.screens[i]->height > *height) + *height = screenInfo.screens[i]->y+screenInfo.screens[i]->height; + } +#endif + + if ((double)*consWidth / *width < (double)*consHeight / *height) + *xScale = *yScale = (double)*consWidth / *width; + else + *xScale = *yScale = (double)*consHeight / *height; + + *consWidth = scalex(priv, *width); + *consHeight = scaley(priv, *height); + if (*consWidth < 1) *consWidth = 1; + if (*consHeight < 1) *consHeight = 1; +} + +/** Re-initialized the console device described by \a pDev (after a + * reconfig). */ +void dmxConsoleReInit(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + Display *dpy; + + if (!priv || !priv->initialized) return; + dpy = priv->display; + + dmxConsoleComputeWidthHeight(priv, + &priv->width, &priv->height, + &priv->xScale, &priv->yScale, + &priv->consWidth, &priv->consHeight); + XResizeWindow(dpy, priv->window, priv->consWidth, priv->consHeight); + XFreePixmap(dpy, priv->pixmap); + priv->pixmap = XCreatePixmap(dpy, + RootWindow(dpy, DefaultScreen(dpy)), + priv->consWidth, + priv->consHeight, + DefaultDepth(dpy,DefaultScreen(dpy))); + dmxConsoleDraw(priv, 1, 1); +} + +/** Initialized the console device described by \a pDev. */ +void dmxConsoleInit(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; + int screen; + unsigned long mask; + XSetWindowAttributes attribs; + Display *dpy; + Window win; + XGCValues gcvals; + XColor color; + XClassHint class_hints; + unsigned long tmp; + + 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 */ + + if (!(dpy = priv->display = XOpenDisplay(dmxInput->name))) + dmxLog(dmxFatal, + "dmxOpenConsole: cannot open console display %s\n", + dmxInput->name); + + /* Set up defaults */ + dmxConsoleComputeWidthHeight(priv, + &priv->width, &priv->height, + &priv->xScale, &priv->yScale, + &priv->consWidth, &priv->consHeight); + + /* Private initialization using computed values or constants. */ + screen = DefaultScreen(dpy); + priv->initPointerX = scalex(priv, priv->width / 2); + priv->initPointerY = scaley(priv, priv->height / 2); + priv->eventMask = (ButtonPressMask + | ButtonReleaseMask + | PointerMotionMask + | EnterWindowMask + | LeaveWindowMask + | KeyPressMask + | KeyReleaseMask + | ExposureMask + | ResizeRedirectMask); + + mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect; + attribs.colormap = DefaultColormap(dpy, screen); + if (XParseColor(dpy, attribs.colormap, CONSOLE_BG_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + attribs.background_pixel = color.pixel; + } else + attribs.background_pixel = WhitePixel(dpy, screen); + + attribs.event_mask = priv->eventMask; + attribs.override_redirect = False; + + win = priv->window = XCreateWindow(dpy, + RootWindow(dpy, screen), + 0, 0, priv->consWidth, priv->consHeight, + 0, + DefaultDepth(dpy, screen), + InputOutput, + DefaultVisual(dpy, screen), + mask, &attribs); + priv->pixmap = XCreatePixmap(dpy, RootWindow(dpy, screen), + priv->consWidth, priv->consHeight, + DefaultDepth(dpy, screen)); + + /* Set up properties */ + XStoreName(dpy, win, DMX_CONSOLE_NAME); + class_hints.res_name = DMX_RES_NAME; + class_hints.res_class = DMX_RES_CLASS; + XSetClassHint(dpy, win, &class_hints); + + + /* Map the window */ + XMapWindow(dpy, win); + + /* Create cursors */ + priv->cursorNormal = XCreateFontCursor(dpy, XC_circle); + priv->cursorGrabbed = XCreateFontCursor(dpy, XC_spider); + priv->cursorEmpty = dmxConsoleCreateEmptyCursor(priv); + XDefineCursor(dpy, priv->window, priv->cursorNormal); + + /* Create GC */ + mask = (GCFunction | GCPlaneMask | GCClipMask | GCForeground | + GCBackground | GCLineWidth | GCLineStyle | GCCapStyle | + GCFillStyle | GCGraphicsExposures); + gcvals.function = GXcopy; + gcvals.plane_mask = AllPlanes; + gcvals.clip_mask = None; + if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_FG_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + gcvals.foreground = color.pixel; + } else + gcvals.foreground = BlackPixel(dpy, screen); + if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_BG_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + gcvals.background = color.pixel; + } else + gcvals.background = WhitePixel(dpy, screen); + gcvals.line_width = 0; + gcvals.line_style = LineSolid; + gcvals.cap_style = CapNotLast; + gcvals.fill_style = FillSolid; + gcvals.graphics_exposures = False; + + priv->gc = XCreateGC(dpy, win, mask, &gcvals); + + tmp = gcvals.foreground; + if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_DET_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + gcvals.foreground = color.pixel; + } else + gcvals.foreground = BlackPixel(dpy, screen); + priv->gcDet = XCreateGC(dpy, win, mask, &gcvals); + gcvals.foreground = tmp; + + tmp = gcvals.background; + gcvals.background = gcvals.foreground; + gcvals.foreground = tmp; + priv->gcRev = XCreateGC(dpy, win, mask, &gcvals); + + gcvals.background = gcvals.foreground; + if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_CUR_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + gcvals.foreground = color.pixel; + } else + gcvals.foreground = BlackPixel(dpy, screen); + priv->gcCur = XCreateGC(dpy, win, mask, &gcvals); + + dmxConsoleDraw(priv, 1, 1); + + if (dixLookupPrivate(&screenInfo.screens[0]->devPrivates, + dmxScreenPrivateKey)) + priv->next = dixLookupPrivate(&screenInfo.screens[0]->devPrivates, + dmxScreenPrivateKey); + else + DMX_WRAP(CloseScreen, dmxCloseConsoleScreen, + priv, screenInfo.screens[0]); + dixSetPrivate(&screenInfo.screens[0]->devPrivates, dmxScreenPrivateKey, + priv); +} + +/** Fill in the \a info structure for the specified \a pDev. Only used + * for pointers. */ +void dmxConsoleMouGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + GETPRIVFROMPDEV; + + info->buttonClass = 1; + dmxCommonMouGetMap(pDev, info->map, &info->numButtons); + info->valuatorClass = 1; + info->numRelAxes = 2; + info->minval[0] = 0; + info->minval[1] = 0; + /* max possible console window size: */ + info->maxval[0] = DisplayWidth(priv->display, DefaultScreen(priv->display)); + info->maxval[1] = DisplayHeight(priv->display, DefaultScreen(priv->display)); + info->res[0] = 1; + info->minres[0] = 0; + info->maxres[0] = 1; + info->ptrFeedbackClass = 1; +} + +/** Fill in the \a info structure for the specified \a pDev. Only used + * for keyboard. */ +void dmxConsoleKbdGetInfo(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; +} + +/** Handle special console-only keys. */ +int dmxConsoleFunctions(pointer private, DMXFunctionType function) +{ + GETONLYPRIVFROMPRIVATE; + XRectangle rect; + Display *dpy = priv->display; + + switch (function) { + case DMX_FUNCTION_FINE: + if (priv->fine) { + priv->fine = 0; + dmxConsoleClearCursor(priv, priv->globalX, priv->globalY, &rect); + XSetClipRectangles(dpy, priv->gc, 0, 0, &rect, 1, Unsorted); + XCopyArea(dpy, priv->pixmap, priv->window, priv->gc, + 0, 0, priv->consWidth, priv->consHeight, 0, 0); + XSetClipMask(dpy, priv->gc, None); + + XDefineCursor(dpy, priv->window, + priv->grabbed + ? priv->cursorGrabbed + : priv->cursorNormal); + XWarpPointer(dpy, priv->window, priv->window, + 0, 0, 0, 0, + scalex(priv, priv->globalX), + scaley(priv, priv->globalY)); + XSync(dpy, False); /* Not a backend display */ + } else { + priv->fine = 1; + XRaiseWindow(dpy, priv->window); + XDefineCursor(dpy, priv->window, priv->cursorEmpty); + dmxConsoleUpdateFineCursor(priv); + } + return 1; + case DMX_FUNCTION_GRAB: + if (priv->grabbed) { + XUngrabKeyboard(dpy, CurrentTime); + XUngrabPointer(dpy, CurrentTime); + XDefineCursor(dpy, priv->window, + priv->fine + ? priv->cursorEmpty + : priv->cursorNormal); + } else { + if (XGrabPointer(dpy, priv->window, True, + 0, GrabModeAsync, GrabModeAsync, priv->window, + None, CurrentTime)) { + dmxLog(dmxError, "XGrabPointer failed\n"); + return 0; + } + if (XGrabKeyboard(dpy, priv->window, True, + GrabModeAsync, GrabModeAsync, CurrentTime)) { + dmxLog(dmxError, "XGrabKeyboard failed\n"); + XUngrabPointer(dpy, CurrentTime); + return 0; + } + XDefineCursor(dpy, priv->window, + priv->fine + ? priv->cursorEmpty + : priv->cursorGrabbed); + } + priv->grabbed = !priv->grabbed; + if (priv->fine) dmxConsoleUpdateFineCursor(priv); + return 1; + case DMX_FUNCTION_TERMINATE: + return 1; + default: + return 0; + } +} + +static void dmxDump(void) +{ + int i, j; + DMXInputInfo *dmxInput; + XEvent X; + + for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) { + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; + myPrivate *priv = dmxLocal->private; + while (priv + && priv->display + && XCheckTypedEvent(priv->display, MotionNotify, &X)) { + DMXDBG4("dmxDump: %s/%d threw event away %d %s\n", + dmxInput->name, j, X.type, dmxEventName(X.type)); + } + } + } +} + +/** This routine is used to warp the pointer into the console window + * from anywhere on the screen. It is used when backend and console + * input are both being taken from the same X display. */ +void dmxConsoleCapture(DMXInputInfo *dmxInput) +{ + int i; + XEvent X; + + DMXDBG0("dmxConsoleCapture\n"); + dmxSync(NULL, TRUE); + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + myPrivate *priv = dmxLocal->private; + if (dmxLocal->extType != DMX_LOCAL_TYPE_CONSOLE) continue; + if (dmxLocal->type != DMX_LOCAL_MOUSE) continue; + if (priv->captured) continue; + priv->captured = 2; /* Ungrab only after proximal events. */ + XRaiseWindow(priv->display, priv->window); + XSync(priv->display, False); /* Not a backend display */ + while (XCheckTypedEvent(priv->display, MotionNotify, &X)) { + DMXDBG3(" Ignoring motion to %d %d after capture on %s\n", + X.xmotion.x, X.xmotion.y, dmxInput->name); + } + XWarpPointer(priv->display, None, + priv->window, 0, 0, 0, 0, priv->curX, priv->curY); + XSync(priv->display, False); /* Not a backend display */ + dmxDump(); + if (priv->fine) dmxConsoleUpdateFineCursor(priv); + } +} + +/** Undo the capture that was done by #dmxConsoleCapture. */ +void dmxConsoleUncapture(DMXInputInfo *dmxInput) +{ + int i; + + DMXDBG0("dmxConsoleUncapture\n"); + dmxSync(NULL, TRUE); + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + myPrivate *priv = dmxLocal->private; + if (dmxLocal->extType != DMX_LOCAL_TYPE_CONSOLE) continue; + if (dmxLocal->type != DMX_LOCAL_MOUSE) continue; + if (!priv->captured) continue; + priv->captured = 0; + XSync(priv->display, False); /* Not a backend display */ + } +} diff --git a/xorg-server/hw/dmx/input/dmxinputinit.c b/xorg-server/hw/dmx/input/dmxinputinit.c index c700a1246..2e062ef79 100644 --- a/xorg-server/hw/dmx/input/dmxinputinit.c +++ b/xorg-server/hw/dmx/input/dmxinputinit.c @@ -570,7 +570,7 @@ static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput, int i; #ifdef PANORAMIX - if (!noPanoramiXExtension && pWindow && pWindow->parent != WindowTable[0]) + if (!noPanoramiXExtension && pWindow && pWindow->parent != screenInfo.screens[0]->root) return; #endif #if DMX_WINDOW_DEBUG @@ -827,7 +827,7 @@ static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a) } } -int dmxInputExtensionErrorHandler(Display *dsp, char *name, char *reason) +int dmxInputExtensionErrorHandler(Display *dsp, _Xconst char *name, _Xconst char *reason) { return 0; } @@ -839,7 +839,7 @@ static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI) Display *display; int num; int i, j; - int (*handler)(Display *, char *, char *); + XextErrorHandler handler; if (!(display = XOpenDisplay(dmxInput->name))) return; @@ -1084,9 +1084,9 @@ static void dmxInputFreeLocal(DMXLocalInputInfoRec *local) if (local->isCore && local->type == DMX_LOCAL_KEYBOARD) dmxLocalCoreKeyboard = NULL; if (local->destroy_private) local->destroy_private(local->private); - if (local->history) free(local->history); - if (local->valuators) free(local->valuators); - if (local->deviceName) free(local->deviceName); + free(local->history); + free(local->valuators); + free(local->deviceName); local->private = NULL; local->history = NULL; local->deviceName = NULL; @@ -1100,9 +1100,9 @@ void dmxInputFree(DMXInputInfo *dmxInput) if (!dmxInput) return; - if (dmxInput->keycodes) free(dmxInput->keycodes); - if (dmxInput->symbols) free(dmxInput->symbols); - if (dmxInput->geometry) free(dmxInput->geometry); + free(dmxInput->keycodes); + free(dmxInput->symbols); + free(dmxInput->geometry); for (i = 0; i < dmxInput->numDevs; i++) { dmxInputFreeLocal(dmxInput->devs[i]); diff --git a/xorg-server/hw/dmx/input/dmxinputinit.h b/xorg-server/hw/dmx/input/dmxinputinit.h index 2e625cfd4..d23ad7a38 100644 --- a/xorg-server/hw/dmx/input/dmxinputinit.h +++ b/xorg-server/hw/dmx/input/dmxinputinit.h @@ -1,291 +1,291 @@ -/* - * Copyright 2002 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: - * Rickard E. (Rik) Faith - * - */ - -/** \file - * Interface for low-level input support. \see dmxinputinit.c */ - -#ifndef _DMXINPUTINIT_H_ -#define _DMXINPUTINIT_H_ - -#include "dmx.h" -#include "dmxinput.h" -#include "dmxlog.h" - - -#define DMX_LOCAL_DEFAULT_KEYBOARD "kbd" -#define DMX_LOCAL_DEFAULT_POINTER "ps2" -#define DMX_MAX_BUTTONS 256 -#define DMX_MOTION_SIZE 256 -#define DMX_MAX_VALUATORS 32 -#define DMX_MAX_AXES 32 -#define DMX_MAX_XINPUT_EVENT_TYPES 100 -#define DMX_MAP_ENTRIES 16 /* Must be a power of 2 */ -#define DMX_MAP_MASK (DMX_MAP_ENTRIES - 1) - -typedef enum { - DMX_FUNCTION_GRAB, - DMX_FUNCTION_TERMINATE, - DMX_FUNCTION_FINE -} DMXFunctionType; - -typedef enum { - DMX_LOCAL_HIGHLEVEL, - DMX_LOCAL_KEYBOARD, - DMX_LOCAL_MOUSE, - DMX_LOCAL_OTHER -} DMXLocalInputType; - -typedef enum { - DMX_LOCAL_TYPE_LOCAL, - DMX_LOCAL_TYPE_CONSOLE, - DMX_LOCAL_TYPE_BACKEND, - DMX_LOCAL_TYPE_COMMON -} DMXLocalInputExtType; - -typedef enum { - DMX_RELATIVE, - DMX_ABSOLUTE, - DMX_ABSOLUTE_CONFINED -} DMXMotionType; - -/** Stores information from low-level device that is used to initialize - * the device at the dix level. */ -typedef struct _DMXLocalInitInfo { - int keyboard; /**< Non-zero if the device is a keyboard */ - - int keyClass; /**< Non-zero if keys are present */ - KeySymsRec keySyms; /**< Key symbols */ - int freemap; /**< If non-zero, free keySyms.map */ - CARD8 modMap[MAP_LENGTH]; /**< Modifier map */ - XkbDescPtr xkb; /**< XKB description */ - XkbComponentNamesRec names; /**< XKB component names */ - int freenames; /**< Non-zero if names should be free'd */ - int force; /**< Do not allow command line override */ - - int buttonClass; /**< Non-zero if buttons are present */ - int numButtons; /**< Number of buttons */ - unsigned char map[DMX_MAX_BUTTONS]; /**< Button map */ - - int valuatorClass; /**< Non-zero if valuators are - * present */ - int numRelAxes; /**< Number of relative axes */ - int numAbsAxes; /**< Number of absolute axes */ - int minval[DMX_MAX_AXES]; /**< Minimum values */ - int maxval[DMX_MAX_AXES]; /**< Maximum values */ - int res[DMX_MAX_AXES]; /**< Resolution */ - int minres[DMX_MAX_AXES]; /**< Minimum resolutions */ - int maxres[DMX_MAX_AXES]; /**< Maximum resolutions */ - - int focusClass; /**< Non-zero if device can - * cause focus */ - int proximityClass; /**< Non-zero if device - * causes proximity events */ - int kbdFeedbackClass; /**< Non-zero if device has - * keyboard feedback */ - int ptrFeedbackClass; /**< Non-zero if device has - * pointer feedback */ - int ledFeedbackClass; /**< Non-zero if device has - * LED indicators */ - int belFeedbackClass; /**< Non-zero if device has a - * bell */ - int intFeedbackClass; /**< Non-zero if device has - * integer feedback */ - int strFeedbackClass; /**< Non-zero if device has - * string feedback */ - - int maxSymbols; /**< Maximum symbols */ - int maxSymbolsSupported; /**< Maximum symbols supported */ - KeySym *symbols; /**< Key symbols */ -} DMXLocalInitInfo, *DMXLocalInitInfoPtr; - -typedef pointer (*dmxCreatePrivateProcPtr)(DeviceIntPtr); -typedef void (*dmxDestroyPrivateProcPtr)(pointer); - -typedef void (*dmxInitProcPtr)(DevicePtr); -typedef void (*dmxReInitProcPtr)(DevicePtr); -typedef void (*dmxLateReInitProcPtr)(DevicePtr); -typedef void (*dmxGetInfoProcPtr)(DevicePtr, DMXLocalInitInfoPtr); -typedef int (*dmxOnProcPtr)(DevicePtr); -typedef void (*dmxOffProcPtr)(DevicePtr); -typedef void (*dmxUpdatePositionProcPtr)(pointer, int x, int y); - -typedef void (*dmxVTPreSwitchProcPtr)(pointer); /* Turn I/O Off */ -typedef void (*dmxVTPostSwitchProcPtr)(pointer); /* Turn I/O On */ -typedef void (*dmxVTSwitchReturnProcPtr)(pointer); -typedef int (*dmxVTSwitchProcPtr)(pointer, int vt, - dmxVTSwitchReturnProcPtr, pointer); - -typedef void (*dmxMotionProcPtr)(DevicePtr, - int *valuators, - int firstAxis, - int axesCount, - DMXMotionType type, - DMXBlockType block); -typedef void (*dmxEnqueueProcPtr)(DevicePtr, int type, int detail, - KeySym keySym, XEvent *e, - DMXBlockType block); -typedef int (*dmxCheckSpecialProcPtr)(DevicePtr, KeySym keySym); -typedef void (*dmxCollectEventsProcPtr)(DevicePtr, - dmxMotionProcPtr, - dmxEnqueueProcPtr, - dmxCheckSpecialProcPtr, - DMXBlockType); -typedef void (*dmxProcessInputProcPtr)(pointer); -typedef void (*dmxUpdateInfoProcPtr)(pointer, DMXUpdateType, WindowPtr); -typedef int (*dmxFunctionsProcPtr)(pointer, DMXFunctionType); - -typedef void (*dmxKBCtrlProcPtr)(DevicePtr, KeybdCtrl *ctrl); -typedef void (*dmxMCtrlProcPtr)(DevicePtr, PtrCtrl *ctrl); -typedef void (*dmxKBBellProcPtr)(DevicePtr, int percent, - int volume, int pitch, int duration); - -/** Stores a mapping between the device id on the remote X server and - * the id on the DMX server */ -typedef struct _DMXEventMap { - int remote; /**< Event number on remote X server */ - int server; /**< Event number (unbiased) on DMX server */ -} DMXEventMap; - -/** This is the device-independent structure used by the low-level input - * routines. The contents are not exposed to top-level .c files (except - * dmxextensions.c). \see dmxinput.h \see dmxextensions.c */ -typedef struct _DMXLocalInputInfo { - const char *name; /**< Device name */ - DMXLocalInputType type; /**< Device type */ - DMXLocalInputExtType extType; /**< Extended device type */ - int binding; /**< Count of how many consecutive - * structs are bound to the same - * device */ - - /* Low-level (e.g., keyboard/mouse drivers) */ - - dmxCreatePrivateProcPtr create_private; /**< Create - * device-dependent - * private */ - dmxDestroyPrivateProcPtr destroy_private; /**< Destroy - * device-dependent - * private */ - dmxInitProcPtr init; /**< Initialize device */ - dmxReInitProcPtr reinit; /**< Reinitialize device - * (during a - * reconfiguration) */ - dmxLateReInitProcPtr latereinit; /**< Reinitialize a device - * (called very late - * during a - * reconfiguration) */ - dmxGetInfoProcPtr get_info; /**< Get device information */ - dmxOnProcPtr on; /**< Turn device on */ - dmxOffProcPtr off; /**< Turn device off */ - dmxUpdatePositionProcPtr update_position; /**< Called when another - * device updates the - * cursor position */ - dmxVTPreSwitchProcPtr vt_pre_switch; /**< Called before a VT switch */ - dmxVTPostSwitchProcPtr vt_post_switch; /**< Called after a VT switch */ - dmxVTSwitchProcPtr vt_switch; /**< Causes a VT switch */ - - dmxCollectEventsProcPtr collect_events; /**< Collect and enqueue - * events from the - * device*/ - dmxProcessInputProcPtr process_input; /**< Process event (from - * queue) */ - dmxFunctionsProcPtr functions; - dmxUpdateInfoProcPtr update_info; /**< Update window layout - * information */ - - dmxMCtrlProcPtr mCtrl; /**< Pointer control */ - dmxKBCtrlProcPtr kCtrl; /**< Keyboard control */ - dmxKBBellProcPtr kBell; /**< Bell control */ - - pointer private; /**< Device-dependent private */ - int isCore; /**< Is a DMX core device */ - int sendsCore; /**< Sends DMX core events */ - KeybdCtrl kctrl; /**< Keyboard control */ - PtrCtrl mctrl; /**< Pointer control */ - - DeviceIntPtr pDevice; /**< X-level device */ - int inputIdx; /**< High-level index */ - int lastX, lastY; /**< Last known position; - * for XInput in - * dmxevents.c */ - - int head; /**< XInput motion history - * head */ - int tail; /**< XInput motion history - * tail */ - unsigned long *history; /**< XInput motion history */ - int *valuators; /**< Cache of previous values */ - - /* for XInput ChangePointerDevice */ - int (*savedMotionProc)(DeviceIntPtr, - xTimecoord *, - unsigned long, - unsigned long, - ScreenPtr); - int savedMotionEvents; /**< Saved motion events */ - int savedSendsCore; /**< Saved sends-core flag */ - - DMXEventMap map[DMX_MAP_ENTRIES]; /**< XInput device id map */ - int mapOptimize; /**< XInput device id - * map - * optimization */ - - long deviceId; /**< device id on remote side, - * if any */ - const char *deviceName; /**< devive name on remote - * side, if any */ -} DMXLocalInputInfoRec; - -extern DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard; - -extern void dmxLocalInitInput(DMXInputInfo *dmxInput); -extern DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput, - DMXLocalInputInfoPtr s); - -extern void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl); -extern void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl); -extern void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice, - pointer ctrl, int unknown); - -extern int dmxInputExtensionErrorHandler(Display *dsp, char *name, - char *reason); - -extern int dmxInputDetach(DMXInputInfo *dmxInput); -extern void dmxInputDetachAll(DMXScreenInfo *dmxScreen); -extern int dmxInputDetachId(int id); -extern DMXInputInfo *dmxInputLocateId(int id); -extern int dmxInputAttachConsole(const char *name, int isCore, - int *id); -extern int dmxInputAttachBackend(int physicalScreen, int isCore, - int *id); - -#endif +/* + * Copyright 2002 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: + * Rickard E. (Rik) Faith + * + */ + +/** \file + * Interface for low-level input support. \see dmxinputinit.c */ + +#ifndef _DMXINPUTINIT_H_ +#define _DMXINPUTINIT_H_ + +#include "dmx.h" +#include "dmxinput.h" +#include "dmxlog.h" + + +#define DMX_LOCAL_DEFAULT_KEYBOARD "kbd" +#define DMX_LOCAL_DEFAULT_POINTER "ps2" +#define DMX_MAX_BUTTONS 256 +#define DMX_MOTION_SIZE 256 +#define DMX_MAX_VALUATORS 32 +#define DMX_MAX_AXES 32 +#define DMX_MAX_XINPUT_EVENT_TYPES 100 +#define DMX_MAP_ENTRIES 16 /* Must be a power of 2 */ +#define DMX_MAP_MASK (DMX_MAP_ENTRIES - 1) + +typedef enum { + DMX_FUNCTION_GRAB, + DMX_FUNCTION_TERMINATE, + DMX_FUNCTION_FINE +} DMXFunctionType; + +typedef enum { + DMX_LOCAL_HIGHLEVEL, + DMX_LOCAL_KEYBOARD, + DMX_LOCAL_MOUSE, + DMX_LOCAL_OTHER +} DMXLocalInputType; + +typedef enum { + DMX_LOCAL_TYPE_LOCAL, + DMX_LOCAL_TYPE_CONSOLE, + DMX_LOCAL_TYPE_BACKEND, + DMX_LOCAL_TYPE_COMMON +} DMXLocalInputExtType; + +typedef enum { + DMX_RELATIVE, + DMX_ABSOLUTE, + DMX_ABSOLUTE_CONFINED +} DMXMotionType; + +/** Stores information from low-level device that is used to initialize + * the device at the dix level. */ +typedef struct _DMXLocalInitInfo { + int keyboard; /**< Non-zero if the device is a keyboard */ + + int keyClass; /**< Non-zero if keys are present */ + KeySymsRec keySyms; /**< Key symbols */ + int freemap; /**< If non-zero, free keySyms.map */ + CARD8 modMap[MAP_LENGTH]; /**< Modifier map */ + XkbDescPtr xkb; /**< XKB description */ + XkbComponentNamesRec names; /**< XKB component names */ + int freenames; /**< Non-zero if names should be free'd */ + int force; /**< Do not allow command line override */ + + int buttonClass; /**< Non-zero if buttons are present */ + int numButtons; /**< Number of buttons */ + unsigned char map[DMX_MAX_BUTTONS]; /**< Button map */ + + int valuatorClass; /**< Non-zero if valuators are + * present */ + int numRelAxes; /**< Number of relative axes */ + int numAbsAxes; /**< Number of absolute axes */ + int minval[DMX_MAX_AXES]; /**< Minimum values */ + int maxval[DMX_MAX_AXES]; /**< Maximum values */ + int res[DMX_MAX_AXES]; /**< Resolution */ + int minres[DMX_MAX_AXES]; /**< Minimum resolutions */ + int maxres[DMX_MAX_AXES]; /**< Maximum resolutions */ + + int focusClass; /**< Non-zero if device can + * cause focus */ + int proximityClass; /**< Non-zero if device + * causes proximity events */ + int kbdFeedbackClass; /**< Non-zero if device has + * keyboard feedback */ + int ptrFeedbackClass; /**< Non-zero if device has + * pointer feedback */ + int ledFeedbackClass; /**< Non-zero if device has + * LED indicators */ + int belFeedbackClass; /**< Non-zero if device has a + * bell */ + int intFeedbackClass; /**< Non-zero if device has + * integer feedback */ + int strFeedbackClass; /**< Non-zero if device has + * string feedback */ + + int maxSymbols; /**< Maximum symbols */ + int maxSymbolsSupported; /**< Maximum symbols supported */ + KeySym *symbols; /**< Key symbols */ +} DMXLocalInitInfo, *DMXLocalInitInfoPtr; + +typedef pointer (*dmxCreatePrivateProcPtr)(DeviceIntPtr); +typedef void (*dmxDestroyPrivateProcPtr)(pointer); + +typedef void (*dmxInitProcPtr)(DevicePtr); +typedef void (*dmxReInitProcPtr)(DevicePtr); +typedef void (*dmxLateReInitProcPtr)(DevicePtr); +typedef void (*dmxGetInfoProcPtr)(DevicePtr, DMXLocalInitInfoPtr); +typedef int (*dmxOnProcPtr)(DevicePtr); +typedef void (*dmxOffProcPtr)(DevicePtr); +typedef void (*dmxUpdatePositionProcPtr)(pointer, int x, int y); + +typedef void (*dmxVTPreSwitchProcPtr)(pointer); /* Turn I/O Off */ +typedef void (*dmxVTPostSwitchProcPtr)(pointer); /* Turn I/O On */ +typedef void (*dmxVTSwitchReturnProcPtr)(pointer); +typedef int (*dmxVTSwitchProcPtr)(pointer, int vt, + dmxVTSwitchReturnProcPtr, pointer); + +typedef void (*dmxMotionProcPtr)(DevicePtr, + int *valuators, + int firstAxis, + int axesCount, + DMXMotionType type, + DMXBlockType block); +typedef void (*dmxEnqueueProcPtr)(DevicePtr, int type, int detail, + KeySym keySym, XEvent *e, + DMXBlockType block); +typedef int (*dmxCheckSpecialProcPtr)(DevicePtr, KeySym keySym); +typedef void (*dmxCollectEventsProcPtr)(DevicePtr, + dmxMotionProcPtr, + dmxEnqueueProcPtr, + dmxCheckSpecialProcPtr, + DMXBlockType); +typedef void (*dmxProcessInputProcPtr)(pointer); +typedef void (*dmxUpdateInfoProcPtr)(pointer, DMXUpdateType, WindowPtr); +typedef int (*dmxFunctionsProcPtr)(pointer, DMXFunctionType); + +typedef void (*dmxKBCtrlProcPtr)(DevicePtr, KeybdCtrl *ctrl); +typedef void (*dmxMCtrlProcPtr)(DevicePtr, PtrCtrl *ctrl); +typedef void (*dmxKBBellProcPtr)(DevicePtr, int percent, + int volume, int pitch, int duration); + +/** Stores a mapping between the device id on the remote X server and + * the id on the DMX server */ +typedef struct _DMXEventMap { + int remote; /**< Event number on remote X server */ + int server; /**< Event number (unbiased) on DMX server */ +} DMXEventMap; + +/** This is the device-independent structure used by the low-level input + * routines. The contents are not exposed to top-level .c files (except + * dmxextensions.c). \see dmxinput.h \see dmxextensions.c */ +typedef struct _DMXLocalInputInfo { + const char *name; /**< Device name */ + DMXLocalInputType type; /**< Device type */ + DMXLocalInputExtType extType; /**< Extended device type */ + int binding; /**< Count of how many consecutive + * structs are bound to the same + * device */ + + /* Low-level (e.g., keyboard/mouse drivers) */ + + dmxCreatePrivateProcPtr create_private; /**< Create + * device-dependent + * private */ + dmxDestroyPrivateProcPtr destroy_private; /**< Destroy + * device-dependent + * private */ + dmxInitProcPtr init; /**< Initialize device */ + dmxReInitProcPtr reinit; /**< Reinitialize device + * (during a + * reconfiguration) */ + dmxLateReInitProcPtr latereinit; /**< Reinitialize a device + * (called very late + * during a + * reconfiguration) */ + dmxGetInfoProcPtr get_info; /**< Get device information */ + dmxOnProcPtr on; /**< Turn device on */ + dmxOffProcPtr off; /**< Turn device off */ + dmxUpdatePositionProcPtr update_position; /**< Called when another + * device updates the + * cursor position */ + dmxVTPreSwitchProcPtr vt_pre_switch; /**< Called before a VT switch */ + dmxVTPostSwitchProcPtr vt_post_switch; /**< Called after a VT switch */ + dmxVTSwitchProcPtr vt_switch; /**< Causes a VT switch */ + + dmxCollectEventsProcPtr collect_events; /**< Collect and enqueue + * events from the + * device*/ + dmxProcessInputProcPtr process_input; /**< Process event (from + * queue) */ + dmxFunctionsProcPtr functions; + dmxUpdateInfoProcPtr update_info; /**< Update window layout + * information */ + + dmxMCtrlProcPtr mCtrl; /**< Pointer control */ + dmxKBCtrlProcPtr kCtrl; /**< Keyboard control */ + dmxKBBellProcPtr kBell; /**< Bell control */ + + pointer private; /**< Device-dependent private */ + int isCore; /**< Is a DMX core device */ + int sendsCore; /**< Sends DMX core events */ + KeybdCtrl kctrl; /**< Keyboard control */ + PtrCtrl mctrl; /**< Pointer control */ + + DeviceIntPtr pDevice; /**< X-level device */ + int inputIdx; /**< High-level index */ + int lastX, lastY; /**< Last known position; + * for XInput in + * dmxevents.c */ + + int head; /**< XInput motion history + * head */ + int tail; /**< XInput motion history + * tail */ + unsigned long *history; /**< XInput motion history */ + int *valuators; /**< Cache of previous values */ + + /* for XInput ChangePointerDevice */ + int (*savedMotionProc)(DeviceIntPtr, + xTimecoord *, + unsigned long, + unsigned long, + ScreenPtr); + int savedMotionEvents; /**< Saved motion events */ + int savedSendsCore; /**< Saved sends-core flag */ + + DMXEventMap map[DMX_MAP_ENTRIES]; /**< XInput device id map */ + int mapOptimize; /**< XInput device id + * map + * optimization */ + + long deviceId; /**< device id on remote side, + * if any */ + const char *deviceName; /**< devive name on remote + * side, if any */ +} DMXLocalInputInfoRec; + +extern DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard; + +extern void dmxLocalInitInput(DMXInputInfo *dmxInput); +extern DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput, + DMXLocalInputInfoPtr s); + +extern void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl); +extern void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl); +extern void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice, + pointer ctrl, int unknown); + +extern int dmxInputExtensionErrorHandler(Display *dsp, _Xconst char *name, + _Xconst char *reason); + +extern int dmxInputDetach(DMXInputInfo *dmxInput); +extern void dmxInputDetachAll(DMXScreenInfo *dmxScreen); +extern int dmxInputDetachId(int id); +extern DMXInputInfo *dmxInputLocateId(int id); +extern int dmxInputAttachConsole(const char *name, int isCore, + int *id); +extern int dmxInputAttachBackend(int physicalScreen, int isCore, + int *id); + +#endif diff --git a/xorg-server/hw/dmx/input/lnx-keyboard.c b/xorg-server/hw/dmx/input/lnx-keyboard.c index 11f21e25c..269e84435 100644 --- a/xorg-server/hw/dmx/input/lnx-keyboard.c +++ b/xorg-server/hw/dmx/input/lnx-keyboard.c @@ -368,7 +368,7 @@ pointer kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard) /** Destroy a private structure. */ void kbdLinuxDestroyPrivate(pointer priv) { - if (priv) free(priv); + free(priv); } /** Ring the bell. diff --git a/xorg-server/hw/dmx/input/lnx-ms.c b/xorg-server/hw/dmx/input/lnx-ms.c index 549df46e2..e6d203c4b 100644 --- a/xorg-server/hw/dmx/input/lnx-ms.c +++ b/xorg-server/hw/dmx/input/lnx-ms.c @@ -1,321 +1,321 @@ -/* Portions of this file were derived from the following files: - * - ********************************************************************** - * - * Xserver/hw/kdrive/linux/ms.c - * - * Copyright (c) 2001 by Juliusz Chroboczek - * Copyright (c) 1999 by Keith Packard - * - * 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 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 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 - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * 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. - * - */ - -/* - * 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: - * Rickard E. (Rik) Faith - * - */ - -/** \file - * - * This code implements a low-level device driver for a serial MS mouse. - * The code is derived from code by Juliusz Chroboczek and Keith Packard - * (see the source code for complete references). */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "inputstr.h" -#include -#include -#include - -/*****************************************************************************/ -/* Define some macros to make it easier to move this file to another - * part of the Xserver tree. All calls to the dmx* layer are #defined - * here for the .c file. The .h file will also have to be edited. */ -#include "dmxinputinit.h" -#include "lnx-ms.h" - -#define GETPRIV myPrivate *priv \ - = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private - -#define LOG0(f) dmxLog(dmxDebug,f) -#define LOG1(f,a) dmxLog(dmxDebug,f,a) -#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) -#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) -#define FATAL0(f) dmxLog(dmxFatal,f) -#define FATAL1(f,a) dmxLog(dmxFatal,f,a) -#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) -#define MOTIONPROC dmxMotionProcPtr -#define ENQUEUEPROC dmxEnqueueProcPtr -#define CHECKPROC dmxCheckSpecialProcPtr -#define BLOCK DMXBlockType - -/* End of interface definitions. */ -/*****************************************************************************/ - -/* Private area for MS mouse devices. */ -typedef struct _myPrivate { - DeviceIntPtr pMouse; - int fd; - struct termios tty; - enum { - button1 = 0x0001, - button2 = 0x0002, - button3 = 0x0004, - button4 = 0x0008, - button5 = 0x0010 - } buttons; -} myPrivate; - -static int msLinuxReadBytes(int fd, unsigned char *buf, int len, int min) -{ - int n, tot; - fd_set set; - struct timeval tv; - - tot = 0; - while (len) { - n = read(fd, buf, len); - if (n > 0) { - tot += n; - buf += n; - len -= n; - } - if (tot % min == 0) break; - FD_ZERO(&set); - FD_SET(fd, &set); - tv.tv_sec = 0; - tv.tv_usec = 100 * 1000; - n = select(fd + 1, &set, 0, 0, &tv); - if (n <= 0) break; - } - return tot; -} - -static void msLinuxButton(DevicePtr pDev, ENQUEUEPROC enqueue, int buttons, - BLOCK block) -{ - GETPRIV; - -#define PRESS(b) \ - do { \ - enqueue(pDev, ButtonPress, 0, 0, NULL, block); \ - } while (0) - -#define RELEASE(b) \ - do { \ - enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \ - } while (0) - - if ((buttons & button1) && !(priv->buttons & button1)) PRESS(1); - if (!(buttons & button1) && (priv->buttons & button1)) RELEASE(1); - - if ((buttons & button2) && !(priv->buttons & button2)) PRESS(2); - if (!(buttons & button2) && (priv->buttons & button2)) RELEASE(2); - - if ((buttons & button3) && !(priv->buttons & button3)) PRESS(3); - if (!(buttons & button3) && (priv->buttons & button3)) RELEASE(3); - - if ((buttons & button4) && !(priv->buttons & button4)) PRESS(4); - if (!(buttons & button4) && (priv->buttons & button4)) RELEASE(4); - - if ((buttons & button5) && !(priv->buttons & button5)) PRESS(5); - if (!(buttons & button5) && (priv->buttons & button5)) RELEASE(5); - - priv->buttons = buttons; -} - -/** Read an event from the \a pDev device. If the event is a motion - * event, enqueue it with the \a motion function. Otherwise, check for - * special keys with the \a checkspecial function and enqueue the event - * with the \a enqueue function. The \a block type is passed to the - * functions so that they may block SIGIO handling as appropriate to the - * caller of this function. */ -void msLinuxRead(DevicePtr pDev, - MOTIONPROC motion, - ENQUEUEPROC enqueue, - CHECKPROC checkspecial, - BLOCK block) -{ - GETPRIV; - unsigned char buf[3 * 200]; /* RATS: Use ok */ - unsigned char *b; - int n; - int dx, dy, v[2]; - - while ((n = msLinuxReadBytes(priv->fd, buf, sizeof(buf), 3)) > 0) { - b = buf; - while (n >= 3) { - dx = (char)(((b[0] & 0x03) << 6) | (b[1] & 0x3f)); - dy = (char)(((b[0] & 0x0c) << 4) | (b[2] & 0x3f)); - v[0] = -dx; - v[1] = -dy; - - motion(pDev, v, 0, 2, 1, block); - msLinuxButton(pDev, enqueue, (((b[0] & 0x10) ? button3 : 0) - | ((b[0] & 0x20) ? button1 : 0)), - block); - n -= 3; - b += 3; - } - } -} - -/** Initialize \a pDev. */ -void msLinuxInit(DevicePtr pDev) -{ - GETPRIV; - const char *names[] = { "/dev/serialmouse", "/dev/mouse", NULL }; - int i; - - if (priv->fd >=0) return; - - for (i = 0; names[i]; i++) { - if ((priv->fd = open(names[i], O_RDWR | O_NONBLOCK, 0)) >= 0) break; - } - if (priv->fd < 0) - FATAL1("msLinuxInit: Cannot open mouse port (%s)\n", - strerror(errno)); - - if (!isatty(priv->fd)) - FATAL1("msLinuxInit: Mouse port %s is not a tty\n", names[i]); - - if (tcgetattr(priv->fd, &priv->tty) < 0) - FATAL1("msLinuxInit: tcgetattr failed (%s)\n", strerror(errno)); - - write(priv->fd, "*n", 2); /* 1200 baud */ - usleep(100000); -} - -/** Turn \a pDev on (i.e., take input from \a pDev). */ -int msLinuxOn(DevicePtr pDev) -{ - GETPRIV; - struct termios nTty; - - if (priv->fd < 0) msLinuxInit(pDev); - - nTty = priv->tty; - nTty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR - | IGNCR | ICRNL | IXON | IXOFF); - nTty.c_oflag &= ~OPOST; - nTty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - nTty.c_cflag &= ~(CSIZE | PARENB); - nTty.c_cflag |= CS8 | CLOCAL | CSTOPB; - nTty.c_cc[VTIME] = 0; - nTty.c_cc[VMIN] = 1; - cfsetispeed (&nTty, B1200); - cfsetospeed (&nTty, B1200); - if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0) - FATAL1("msLinuxInit: tcsetattr failed (%s)\n", strerror(errno)); - write(priv->fd, "*V", 2); /* 2 button 3 byte protocol */ - return priv->fd; -} - -/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ -void msLinuxOff(DevicePtr pDev) -{ - GETPRIV; - - tcsetattr(priv->fd, TCSANOW, &priv->tty); - close(priv->fd); - priv->fd = -1; -} - -static void msLinuxGetMap(DevicePtr pDev, unsigned char *map, int *nButtons) -{ - int i; - - if (nButtons) *nButtons = 3; - if (map) for (i = 0; i <= *nButtons; i++) map[i] = i; -} - -/** Currently unused hook called prior to an VT switch. */ -void msLinuxVTPreSwitch(pointer p) -{ -} - -/** Currently unused hook called after returning from a VT switch. */ -void msLinuxVTPostSwitch(pointer p) -{ -} - -/** Create a private structure for use within this file. */ -pointer msLinuxCreatePrivate(DeviceIntPtr pMouse) -{ - myPrivate *priv = calloc(1, sizeof(*priv)); - priv->fd = -1; - priv->pMouse = pMouse; - return priv; -} - -/** Destroy a private structure. */ -void msLinuxDestroyPrivate(pointer priv) -{ - if (priv) free(priv); -} - -/** Fill the \a info structure with information needed to initialize \a - * pDev. */ -void msLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) -{ - info->buttonClass = 1; - msLinuxGetMap(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; -} +/* Portions of this file were derived from the following files: + * + ********************************************************************** + * + * Xserver/hw/kdrive/linux/ms.c + * + * Copyright (c) 2001 by Juliusz Chroboczek + * Copyright (c) 1999 by Keith Packard + * + * 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 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 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 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * 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. + * + */ + +/* + * 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: + * Rickard E. (Rik) Faith + * + */ + +/** \file + * + * This code implements a low-level device driver for a serial MS mouse. + * The code is derived from code by Juliusz Chroboczek and Keith Packard + * (see the source code for complete references). */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "inputstr.h" +#include +#include +#include + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "dmxinputinit.h" +#include "lnx-ms.h" + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define BLOCK DMXBlockType + +/* End of interface definitions. */ +/*****************************************************************************/ + +/* Private area for MS mouse devices. */ +typedef struct _myPrivate { + DeviceIntPtr pMouse; + int fd; + struct termios tty; + enum { + button1 = 0x0001, + button2 = 0x0002, + button3 = 0x0004, + button4 = 0x0008, + button5 = 0x0010 + } buttons; +} myPrivate; + +static int msLinuxReadBytes(int fd, unsigned char *buf, int len, int min) +{ + int n, tot; + fd_set set; + struct timeval tv; + + tot = 0; + while (len) { + n = read(fd, buf, len); + if (n > 0) { + tot += n; + buf += n; + len -= n; + } + if (tot % min == 0) break; + FD_ZERO(&set); + FD_SET(fd, &set); + tv.tv_sec = 0; + tv.tv_usec = 100 * 1000; + n = select(fd + 1, &set, 0, 0, &tv); + if (n <= 0) break; + } + return tot; +} + +static void msLinuxButton(DevicePtr pDev, ENQUEUEPROC enqueue, int buttons, + BLOCK block) +{ + GETPRIV; + +#define PRESS(b) \ + do { \ + enqueue(pDev, ButtonPress, 0, 0, NULL, block); \ + } while (0) + +#define RELEASE(b) \ + do { \ + enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \ + } while (0) + + if ((buttons & button1) && !(priv->buttons & button1)) PRESS(1); + if (!(buttons & button1) && (priv->buttons & button1)) RELEASE(1); + + if ((buttons & button2) && !(priv->buttons & button2)) PRESS(2); + if (!(buttons & button2) && (priv->buttons & button2)) RELEASE(2); + + if ((buttons & button3) && !(priv->buttons & button3)) PRESS(3); + if (!(buttons & button3) && (priv->buttons & button3)) RELEASE(3); + + if ((buttons & button4) && !(priv->buttons & button4)) PRESS(4); + if (!(buttons & button4) && (priv->buttons & button4)) RELEASE(4); + + if ((buttons & button5) && !(priv->buttons & button5)) PRESS(5); + if (!(buttons & button5) && (priv->buttons & button5)) RELEASE(5); + + priv->buttons = buttons; +} + +/** Read an event from the \a pDev device. If the event is a motion + * event, enqueue it with the \a motion function. Otherwise, check for + * special keys with the \a checkspecial function and enqueue the event + * with the \a enqueue function. The \a block type is passed to the + * functions so that they may block SIGIO handling as appropriate to the + * caller of this function. */ +void msLinuxRead(DevicePtr pDev, + MOTIONPROC motion, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + unsigned char buf[3 * 200]; /* RATS: Use ok */ + unsigned char *b; + int n; + int dx, dy, v[2]; + + while ((n = msLinuxReadBytes(priv->fd, buf, sizeof(buf), 3)) > 0) { + b = buf; + while (n >= 3) { + dx = (char)(((b[0] & 0x03) << 6) | (b[1] & 0x3f)); + dy = (char)(((b[0] & 0x0c) << 4) | (b[2] & 0x3f)); + v[0] = -dx; + v[1] = -dy; + + motion(pDev, v, 0, 2, 1, block); + msLinuxButton(pDev, enqueue, (((b[0] & 0x10) ? button3 : 0) + | ((b[0] & 0x20) ? button1 : 0)), + block); + n -= 3; + b += 3; + } + } +} + +/** Initialize \a pDev. */ +void msLinuxInit(DevicePtr pDev) +{ + GETPRIV; + const char *names[] = { "/dev/serialmouse", "/dev/mouse", NULL }; + int i; + + if (priv->fd >=0) return; + + for (i = 0; names[i]; i++) { + if ((priv->fd = open(names[i], O_RDWR | O_NONBLOCK, 0)) >= 0) break; + } + if (priv->fd < 0) + FATAL1("msLinuxInit: Cannot open mouse port (%s)\n", + strerror(errno)); + + if (!isatty(priv->fd)) + FATAL1("msLinuxInit: Mouse port %s is not a tty\n", names[i]); + + if (tcgetattr(priv->fd, &priv->tty) < 0) + FATAL1("msLinuxInit: tcgetattr failed (%s)\n", strerror(errno)); + + write(priv->fd, "*n", 2); /* 1200 baud */ + usleep(100000); +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int msLinuxOn(DevicePtr pDev) +{ + GETPRIV; + struct termios nTty; + + if (priv->fd < 0) msLinuxInit(pDev); + + nTty = priv->tty; + nTty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR + | IGNCR | ICRNL | IXON | IXOFF); + nTty.c_oflag &= ~OPOST; + nTty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + nTty.c_cflag &= ~(CSIZE | PARENB); + nTty.c_cflag |= CS8 | CLOCAL | CSTOPB; + nTty.c_cc[VTIME] = 0; + nTty.c_cc[VMIN] = 1; + cfsetispeed (&nTty, B1200); + cfsetospeed (&nTty, B1200); + if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0) + FATAL1("msLinuxInit: tcsetattr failed (%s)\n", strerror(errno)); + write(priv->fd, "*V", 2); /* 2 button 3 byte protocol */ + return priv->fd; +} + +/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ +void msLinuxOff(DevicePtr pDev) +{ + GETPRIV; + + tcsetattr(priv->fd, TCSANOW, &priv->tty); + close(priv->fd); + priv->fd = -1; +} + +static void msLinuxGetMap(DevicePtr pDev, unsigned char *map, int *nButtons) +{ + int i; + + if (nButtons) *nButtons = 3; + if (map) for (i = 0; i <= *nButtons; i++) map[i] = i; +} + +/** Currently unused hook called prior to an VT switch. */ +void msLinuxVTPreSwitch(pointer p) +{ +} + +/** Currently unused hook called after returning from a VT switch. */ +void msLinuxVTPostSwitch(pointer p) +{ +} + +/** Create a private structure for use within this file. */ +pointer msLinuxCreatePrivate(DeviceIntPtr pMouse) +{ + myPrivate *priv = calloc(1, sizeof(*priv)); + priv->fd = -1; + priv->pMouse = pMouse; + return priv; +} + +/** Destroy a private structure. */ +void msLinuxDestroyPrivate(pointer priv) +{ + free(priv); +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void msLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + info->buttonClass = 1; + msLinuxGetMap(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; +} diff --git a/xorg-server/hw/dmx/input/lnx-ps2.c b/xorg-server/hw/dmx/input/lnx-ps2.c index 70918eef4..f40441fe7 100644 --- a/xorg-server/hw/dmx/input/lnx-ps2.c +++ b/xorg-server/hw/dmx/input/lnx-ps2.c @@ -1,289 +1,289 @@ -/* Portions of this file were derived from the following files: - * - ********************************************************************** - * - * Xserver/hw/kdrive/linux/ps2.c - * - * Copyright (c) 1999 by Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - * - */ - -/* - * 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: - * Rickard E. (Rik) Faith - * - */ - -/** \file - * - * This code implements a low-level device driver for a serial MS mouse. - * The code is derived from code by Keith Packard (see the source code - * for complete references). */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "inputstr.h" -#include -#include -#include - -/*****************************************************************************/ -/* Define some macros to make it easier to move this file to another - * part of the Xserver tree. All calls to the dmx* layer are #defined - * here for the .c file. The .h file will also have to be edited. */ -#include "dmxinputinit.h" -#include "lnx-ps2.h" - -#define GETPRIV myPrivate *priv \ - = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private - -#define LOG0(f) dmxLog(dmxDebug,f) -#define LOG1(f,a) dmxLog(dmxDebug,f,a) -#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) -#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) -#define FATAL0(f) dmxLog(dmxFatal,f) -#define FATAL1(f,a) dmxLog(dmxFatal,f,a) -#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) -#define MOTIONPROC dmxMotionProcPtr -#define ENQUEUEPROC dmxEnqueueProcPtr -#define CHECKPROC dmxCheckSpecialProcPtr -#define BLOCK DMXBlockType - -/* End of interface definitions. */ -/*****************************************************************************/ - -/* Private area for PS/2 devices. */ -typedef struct _myPrivate { - DeviceIntPtr pMouse; - int fd; - enum { - button1 = 0x0001, - button2 = 0x0002, - button3 = 0x0004, - button4 = 0x0008, - button5 = 0x0010 - } buttons; -} myPrivate; - -static int ps2LinuxReadBytes(int fd, unsigned char *buf, int len, int min) -{ - int n, tot; - fd_set set; - struct timeval tv; - - tot = 0; - while (len) { - n = read(fd, buf, len); - if (n > 0) { - tot += n; - buf += n; - len -= n; - } - if (tot % min == 0) break; - FD_ZERO(&set); - FD_SET(fd, &set); - tv.tv_sec = 0; - tv.tv_usec = 100 * 1000; - n = select(fd + 1, &set, 0, 0, &tv); - if (n <= 0) break; - } - return tot; -} - -static void ps2LinuxButton(DevicePtr pDev, ENQUEUEPROC enqueue, - int buttons, BLOCK block) -{ - GETPRIV; - -#define PRESS(b) \ - do { \ - enqueue(pDev, ButtonPress, 0, 0, NULL, block); \ - } while (0) - -#define RELEASE(b) \ - do { \ - enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \ - } while (0) - - if ((buttons & button1) && !(priv->buttons & button1)) PRESS(1); - if (!(buttons & button1) && (priv->buttons & button1)) RELEASE(1); - - if ((buttons & button2) && !(priv->buttons & button2)) PRESS(2); - if (!(buttons & button2) && (priv->buttons & button2)) RELEASE(2); - - if ((buttons & button3) && !(priv->buttons & button3)) PRESS(3); - if (!(buttons & button3) && (priv->buttons & button3)) RELEASE(3); - - if ((buttons & button4) && !(priv->buttons & button4)) PRESS(4); - if (!(buttons & button4) && (priv->buttons & button4)) RELEASE(4); - - if ((buttons & button5) && !(priv->buttons & button5)) PRESS(5); - if (!(buttons & button5) && (priv->buttons & button5)) RELEASE(5); - - priv->buttons = buttons; -} - -/** Read an event from the \a pDev device. If the event is a motion - * event, enqueue it with the \a motion function. Otherwise, check for - * special keys with the \a checkspecial function and enqueue the event - * with the \a enqueue function. The \a block type is passed to the - * functions so that they may block SIGIO handling as appropriate to the - * caller of this function. */ -void ps2LinuxRead(DevicePtr pDev, MOTIONPROC motion, - ENQUEUEPROC enqueue, CHECKPROC checkspecial, BLOCK block) -{ - GETPRIV; - unsigned char buf[3 * 200]; /* RATS: Use ok */ - unsigned char *b; - int n; - int dx, dy, v[2]; - - while ((n = ps2LinuxReadBytes(priv->fd, buf, sizeof(buf), 3)) > 0) { - b = buf; - while (n >= 3) { - dx = b[1] - ((b[0] & 0x10) ? 256 : 0); - dy = -b[2] + ((b[0] & 0x20) ? 256 : 0); - v[0] = -dx; - v[1] = -dy; - - motion(pDev, v, 0, 2, 1, block); - ps2LinuxButton(pDev, enqueue, (((b[0] & 4) ? button2 : 0) - | ((b[0] & 2) ? button3 : 0) - | ((b[0] & 1) ? button1 : 0)), - block); - n -= 3; - b += 3; - } - } -} - -/** Initialize \a pDev. */ -void ps2LinuxInit(DevicePtr pDev) -{ - GETPRIV; - const char *names[] = { "/dev/mouse", "/dev/psaux", NULL }; - int i; - - if (priv->fd >=0) return; - - for (i = 0; names[i]; i++) { - if ((priv->fd = open(names[i], O_RDWR | O_NONBLOCK, 0)) >= 0) break; - } - if (priv->fd < 0) - FATAL1("ps2LinuxInit: Cannot open mouse port (%s)\n", - strerror(errno)); -} - -/** Turn \a pDev on (i.e., take input from \a pDev). */ -int ps2LinuxOn(DevicePtr pDev) -{ - GETPRIV; - - if (priv->fd < 0) ps2LinuxInit(pDev); - return priv->fd; -} - -/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ -void ps2LinuxOff(DevicePtr pDev) -{ - GETPRIV; - - close(priv->fd); - priv->fd = -1; -} - -static void ps2LinuxGetMap(DevicePtr pDev, unsigned char *map, int *nButtons) -{ - int i; - - if (nButtons) *nButtons = 3; - if (map) for (i = 0; i <= *nButtons; i++) map[i] = i; -} - -/** Currently unused hook called prior to an VT switch. */ -void ps2LinuxVTPreSwitch(pointer p) -{ -} - -/** Currently unused hook called after returning from a VT switch. */ -void ps2LinuxVTPostSwitch(pointer p) -{ -} - -/** Create a private structure for use within this file. */ -pointer ps2LinuxCreatePrivate(DeviceIntPtr pMouse) -{ - myPrivate *priv = calloc(1, sizeof(*priv)); - priv->fd = -1; - priv->pMouse = pMouse; - return priv; -} - -/** Destroy a private structure. */ -void ps2LinuxDestroyPrivate(pointer priv) -{ - if (priv) free(priv); -} - -/** Fill the \a info structure with information needed to initialize \a - * pDev. */ -void ps2LinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) -{ - info->buttonClass = 1; - ps2LinuxGetMap(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; -} +/* Portions of this file were derived from the following files: + * + ********************************************************************** + * + * Xserver/hw/kdrive/linux/ps2.c + * + * Copyright (c) 1999 by Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* + * 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: + * Rickard E. (Rik) Faith + * + */ + +/** \file + * + * This code implements a low-level device driver for a serial MS mouse. + * The code is derived from code by Keith Packard (see the source code + * for complete references). */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "inputstr.h" +#include +#include +#include + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "dmxinputinit.h" +#include "lnx-ps2.h" + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define BLOCK DMXBlockType + +/* End of interface definitions. */ +/*****************************************************************************/ + +/* Private area for PS/2 devices. */ +typedef struct _myPrivate { + DeviceIntPtr pMouse; + int fd; + enum { + button1 = 0x0001, + button2 = 0x0002, + button3 = 0x0004, + button4 = 0x0008, + button5 = 0x0010 + } buttons; +} myPrivate; + +static int ps2LinuxReadBytes(int fd, unsigned char *buf, int len, int min) +{ + int n, tot; + fd_set set; + struct timeval tv; + + tot = 0; + while (len) { + n = read(fd, buf, len); + if (n > 0) { + tot += n; + buf += n; + len -= n; + } + if (tot % min == 0) break; + FD_ZERO(&set); + FD_SET(fd, &set); + tv.tv_sec = 0; + tv.tv_usec = 100 * 1000; + n = select(fd + 1, &set, 0, 0, &tv); + if (n <= 0) break; + } + return tot; +} + +static void ps2LinuxButton(DevicePtr pDev, ENQUEUEPROC enqueue, + int buttons, BLOCK block) +{ + GETPRIV; + +#define PRESS(b) \ + do { \ + enqueue(pDev, ButtonPress, 0, 0, NULL, block); \ + } while (0) + +#define RELEASE(b) \ + do { \ + enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \ + } while (0) + + if ((buttons & button1) && !(priv->buttons & button1)) PRESS(1); + if (!(buttons & button1) && (priv->buttons & button1)) RELEASE(1); + + if ((buttons & button2) && !(priv->buttons & button2)) PRESS(2); + if (!(buttons & button2) && (priv->buttons & button2)) RELEASE(2); + + if ((buttons & button3) && !(priv->buttons & button3)) PRESS(3); + if (!(buttons & button3) && (priv->buttons & button3)) RELEASE(3); + + if ((buttons & button4) && !(priv->buttons & button4)) PRESS(4); + if (!(buttons & button4) && (priv->buttons & button4)) RELEASE(4); + + if ((buttons & button5) && !(priv->buttons & button5)) PRESS(5); + if (!(buttons & button5) && (priv->buttons & button5)) RELEASE(5); + + priv->buttons = buttons; +} + +/** Read an event from the \a pDev device. If the event is a motion + * event, enqueue it with the \a motion function. Otherwise, check for + * special keys with the \a checkspecial function and enqueue the event + * with the \a enqueue function. The \a block type is passed to the + * functions so that they may block SIGIO handling as appropriate to the + * caller of this function. */ +void ps2LinuxRead(DevicePtr pDev, MOTIONPROC motion, + ENQUEUEPROC enqueue, CHECKPROC checkspecial, BLOCK block) +{ + GETPRIV; + unsigned char buf[3 * 200]; /* RATS: Use ok */ + unsigned char *b; + int n; + int dx, dy, v[2]; + + while ((n = ps2LinuxReadBytes(priv->fd, buf, sizeof(buf), 3)) > 0) { + b = buf; + while (n >= 3) { + dx = b[1] - ((b[0] & 0x10) ? 256 : 0); + dy = -b[2] + ((b[0] & 0x20) ? 256 : 0); + v[0] = -dx; + v[1] = -dy; + + motion(pDev, v, 0, 2, 1, block); + ps2LinuxButton(pDev, enqueue, (((b[0] & 4) ? button2 : 0) + | ((b[0] & 2) ? button3 : 0) + | ((b[0] & 1) ? button1 : 0)), + block); + n -= 3; + b += 3; + } + } +} + +/** Initialize \a pDev. */ +void ps2LinuxInit(DevicePtr pDev) +{ + GETPRIV; + const char *names[] = { "/dev/mouse", "/dev/psaux", NULL }; + int i; + + if (priv->fd >=0) return; + + for (i = 0; names[i]; i++) { + if ((priv->fd = open(names[i], O_RDWR | O_NONBLOCK, 0)) >= 0) break; + } + if (priv->fd < 0) + FATAL1("ps2LinuxInit: Cannot open mouse port (%s)\n", + strerror(errno)); +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int ps2LinuxOn(DevicePtr pDev) +{ + GETPRIV; + + if (priv->fd < 0) ps2LinuxInit(pDev); + return priv->fd; +} + +/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ +void ps2LinuxOff(DevicePtr pDev) +{ + GETPRIV; + + close(priv->fd); + priv->fd = -1; +} + +static void ps2LinuxGetMap(DevicePtr pDev, unsigned char *map, int *nButtons) +{ + int i; + + if (nButtons) *nButtons = 3; + if (map) for (i = 0; i <= *nButtons; i++) map[i] = i; +} + +/** Currently unused hook called prior to an VT switch. */ +void ps2LinuxVTPreSwitch(pointer p) +{ +} + +/** Currently unused hook called after returning from a VT switch. */ +void ps2LinuxVTPostSwitch(pointer p) +{ +} + +/** Create a private structure for use within this file. */ +pointer ps2LinuxCreatePrivate(DeviceIntPtr pMouse) +{ + myPrivate *priv = calloc(1, sizeof(*priv)); + priv->fd = -1; + priv->pMouse = pMouse; + return priv; +} + +/** Destroy a private structure. */ +void ps2LinuxDestroyPrivate(pointer priv) +{ + free(priv); +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void ps2LinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + info->buttonClass = 1; + ps2LinuxGetMap(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; +} diff --git a/xorg-server/hw/dmx/input/usb-common.c b/xorg-server/hw/dmx/input/usb-common.c index 95c00b839..c655a2984 100644 --- a/xorg-server/hw/dmx/input/usb-common.c +++ b/xorg-server/hw/dmx/input/usb-common.c @@ -1,381 +1,381 @@ -/* - * Copyright 2002-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: - * Rickard E. (Rik) Faith - * - */ - -/** \file - * - * Routines that are common between \a usb-keyboard.c, \a usb-mouse.c, and - * \a usb-other.c */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "usb-private.h" - -#define USB_COMMON_DEBUG 1 - -/*****************************************************************************/ -/* Define some macros to make it easier to move this file to another - * part of the Xserver tree. All calls to the dmx* layer are #defined - * here for the .c file. The .h file will also have to be edited. */ -#include "usb-mouse.h" - -#define GETPRIV myPrivate *priv \ - = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private - -#define GETNAME ((DMXLocalInputInfoPtr)(pDevice->public.devicePrivate)) \ - ->name - -#define LOG0(f) dmxLog(dmxDebug,f) -#define LOG1(f,a) dmxLog(dmxDebug,f,a) -#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) -#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) -#define LOG1INPUT(p,f,a) dmxLogInput(p->dmxInput,f,a) -#define LOG3INPUT(p,f,a,b,c) dmxLogInput(p->dmxInput,f,a,b,c) -#define LOG5INPUT(p,f,a,b,c,d,e) dmxLogInput(p->dmxInput,f,a,b,c,d,e) -#define FATAL0(f) dmxLog(dmxFatal,f) -#define FATAL1(f,a) dmxLog(dmxFatal,f,a) -#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) -#define MOTIONPROC dmxMotionProcPtr -#define ENQUEUEPROC dmxEnqueueProcPtr -#define CHECKPROC dmxCheckSpecialProcPtr -#define BLOCK DMXBlockType - -/* End of interface definitions. */ -/*****************************************************************************/ - - -/** Read an event from the \a pDev device. If the event is a motion - * event, enqueue it with the \a motion function. Otherwise, enqueue - * the event with the \a enqueue function. The \a block type is passed - * to the functions so that they may block SIGIO handling as appropriate - * to the caller of this function. - * - * Since USB devices return EV_KEY events for buttons and keys, \a - * minButton is used to decide if a Button or Key event should be - * queued.*/ -void usbRead(DevicePtr pDev, - MOTIONPROC motion, - ENQUEUEPROC enqueue, - int minButton, - BLOCK block) -{ - GETPRIV; - struct input_event raw; - int v[DMX_MAX_AXES]; - int axis; - -#define PRESS(b) \ - do { \ - enqueue(pDev, ButtonPress, 0, 0, NULL, block); \ - } while (0) - -#define RELEASE(b) \ - do { \ - enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \ - } while (0) - - while (read(priv->fd, &raw, sizeof(raw)) > 0) { -#if USB_COMMON_DEBUG > 1 - LOG3("USB: type = %d, code = 0x%02x, value = %d\n", - raw.type, raw.code, raw.value); -#endif - switch (raw.type) { - case EV_KEY: - /* raw.value = 1 for first, 2 for repeat */ - if (raw.code > minButton) { - if (raw.value) PRESS((raw.code & 0x0f) + 1); - else RELEASE((raw.code & 0x0f) + 1); - } else { - enqueue(pDev, raw.value ? KeyPress : KeyRelease, - 0, 0, NULL, block); - } - break; - case EV_REL: - switch (raw.code) { - case REL_X: - v[0] = -raw.value; - v[1] = 0; - motion(pDev, v, 0, 2, DMX_RELATIVE, block); - break; - case REL_Y: - v[0] = 0; - v[1] = -raw.value; - motion(pDev, v, 0, 2, DMX_RELATIVE, block); - break; - case REL_WHEEL: - if ((int)raw.value > 0) { - PRESS(4); - RELEASE(4); - } else if ((int)raw.value < 0) { - PRESS(5); - RELEASE(5); - } - break; - default: - memset(v, 0, sizeof(v)); - axis = priv->relmap[raw.code]; - v[axis] = raw.value; - motion(pDev, v, axis, 1, DMX_RELATIVE, block); - } - break; - case EV_ABS: - memset(v, 0, sizeof(v)); - axis = priv->absmap[raw.code]; - v[axis] = raw.value; - motion(pDev, v, axis, 1, DMX_ABSOLUTE, block); - break; - } - } -} - -#define test_bit(bit) (priv->mask[(bit)/8] & (1 << ((bit)%8))) -#define test_bits(bit) (bits[(bit)/8] & (1 << ((bit)%8))) - -static void usbPrint(myPrivate *priv, - const char *filename, const char *devname, int fd) -{ - int j, k; - DeviceIntPtr pDevice = priv->pDevice; - unsigned char bits[KEY_MAX/8 + 1]; /* RATS: Use ok assuming that - * KEY_MAX is greater than - * REL_MAX, ABS_MAX, SND_MAX, and - * LED_MAX. */ - - LOG3INPUT(priv, "%s (%s) using %s\n", pDevice->name, GETNAME, filename); - LOG1INPUT(priv, " %s\n", devname); - for (j = 0; j < EV_MAX; j++) { - if (test_bit(j)) { - const char *type = "unknown"; - char extra[256]; /* FIXME: may cause buffer overflow */ - extra[0] = '\0'; - switch(j) { - case EV_KEY: type = "keys/buttons"; break; - case EV_REL: type = "relative"; - memset(bits, 0, sizeof(bits)); - ioctl(priv->fd, EVIOCGBIT(EV_REL, sizeof(bits)), bits); - for (k = 0; k < REL_MAX; k++) { - if (test_bits(k)) switch (k) { - case REL_X: strcat(extra, " X"); break; - case REL_Y: strcat(extra, " Y"); break; - case REL_Z: strcat(extra, " Z"); break; - case REL_HWHEEL: strcat(extra, " HWheel"); break; - case REL_DIAL: strcat(extra, " Dial"); break; - case REL_WHEEL: strcat(extra, " Wheel"); break; - case REL_MISC: strcat(extra, " Misc"); break; - } - } - break; - case EV_ABS: type = "absolute"; - memset(bits, 0, sizeof(bits)); - ioctl(priv->fd, EVIOCGBIT(EV_ABS, sizeof(bits)), bits); - for (k = 0; k < ABS_MAX; k++) { - if (test_bits(k)) switch (k) { - case ABS_X: strcat(extra," X"); break; - case ABS_Y: strcat(extra," Y"); break; - case ABS_Z: strcat(extra," Z"); break; - case ABS_RX: strcat(extra," RX"); break; - case ABS_RY: strcat(extra," RY"); break; - case ABS_RZ: strcat(extra," RZ"); break; - case ABS_THROTTLE: strcat(extra," Throttle");break; - case ABS_RUDDER: strcat(extra," Rudder"); break; - case ABS_WHEEL: strcat(extra," Wheel"); break; - case ABS_GAS: strcat(extra," Gas"); break; - case ABS_BRAKE: strcat(extra," Break"); break; - case ABS_HAT0X: strcat(extra," Hat0X"); break; - case ABS_HAT0Y: strcat(extra," Hat0Y"); break; - case ABS_HAT1X: strcat(extra," Hat1X"); break; - case ABS_HAT1Y: strcat(extra," Hat1Y"); break; - case ABS_HAT2X: strcat(extra," Hat2X"); break; - case ABS_HAT2Y: strcat(extra," Hat2Y"); break; - case ABS_HAT3X: strcat(extra," Hat3X"); break; - case ABS_HAT3Y: strcat(extra," Hat3Y"); break; - case ABS_PRESSURE: strcat(extra," Pressure");break; - case ABS_DISTANCE: strcat(extra," Distance");break; - case ABS_TILT_X: strcat(extra," TiltX"); break; - case ABS_TILT_Y: strcat(extra," TiltY"); break; - case ABS_MISC: strcat(extra," Misc"); break; - } - } - break; - case EV_MSC: type = "reserved"; break; - case EV_LED: type = "leds"; - memset(bits, 0, sizeof(bits)); - ioctl(priv->fd, EVIOCGBIT(EV_LED, sizeof(bits)), bits); - for (k = 0; k < LED_MAX; k++) { - if (test_bits(k)) switch (k) { - case LED_NUML: strcat(extra," NumLock"); break; - case LED_CAPSL: strcat(extra," CapsLock"); break; - case LED_SCROLLL: strcat(extra," ScrlLock"); break; - case LED_COMPOSE: strcat(extra," Compose"); break; - case LED_KANA: strcat(extra," Kana"); break; - case LED_SLEEP: strcat(extra," Sleep"); break; - case LED_SUSPEND: strcat(extra," Suspend"); break; - case LED_MUTE: strcat(extra," Mute"); break; - case LED_MISC: strcat(extra," Misc"); break; - } - } - break; - case EV_SND: type = "sound"; - memset(bits, 0, sizeof(bits)); - ioctl(priv->fd, EVIOCGBIT(EV_SND, sizeof(bits)), bits); - for (k = 0; k < SND_MAX; k++) { - if (test_bits(k)) switch (k) { - case SND_CLICK: strcat(extra," Click"); break; - case SND_BELL: strcat(extra," Bell"); break; - } - } - break; - case EV_REP: type = "repeat"; break; - case EV_FF: type = "feedback"; break; - } - LOG5INPUT(priv, " Feature 0x%02x = %s%s%s%s\n", j, type, - extra[0] ? " [" : "", - extra[0] ? extra+1 : "", - extra[0] ? "]" : ""); - } - } -} - -/** Initialized \a pDev as a \a usbMouse, \a usbKeyboard, or \a usbOther -device. */ -void usbInit(DevicePtr pDev, usbType type) -{ - GETPRIV; - char name[64]; /* RATS: Only used in XmuSnprintf */ - int i, j, k; - char buf[256] = { 0, }; /* RATS: Use ok */ - int version; - unsigned char bits[KEY_MAX/8 + 1]; /* RATS: Use ok assuming that - * KEY_MAX is greater than - * REL_MAX, ABS_MAX, SND_MAX, and - * LED_MAX. */ - - if (priv->fd >=0) return; - - for (i = 0; i < 32; i++) { - XmuSnprintf(name, sizeof(name), "/dev/input/event%d", i); - if ((priv->fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) { - ioctl(priv->fd, EVIOCGVERSION, &version); - ioctl(priv->fd, EVIOCGNAME(sizeof(buf)), buf); - memset(priv->mask, 0, sizeof(priv->mask)); - ioctl(priv->fd, EVIOCGBIT(0, sizeof(priv->mask)), priv->mask); - - for (j = 0; j < EV_MAX; j++) { - if (test_bit(j)) { - switch(j) { - case EV_REL: - memset(bits, 0, sizeof(bits)); - ioctl(priv->fd, EVIOCGBIT(EV_REL, sizeof(bits)), bits); - for (k = 0; k < REL_MAX; k++) { - if (test_bits(k)) { - if (k == REL_X) priv->relmap[k] = 0; - else if (k == REL_Y) priv->relmap[k] = 1; - else priv->relmap[k] = 2 + priv->numAbs; - ++priv->numRel; - } - } - break; - case EV_ABS: - memset(bits, 0, sizeof(bits)); - ioctl(priv->fd, EVIOCGBIT(EV_ABS, sizeof(bits)), bits); - for (k = 0; k < ABS_MAX; k++) { - if (test_bits(k)) { - priv->absmap[k] = priv->numAbs; - ++priv->numAbs; - } - } - break; - case EV_LED: - memset(bits, 0, sizeof(bits)); - ioctl(priv->fd, EVIOCGBIT(EV_LED, sizeof(bits)), bits); - for (k = 0; k < LED_MAX; k++) { - if (test_bits(k)) ++priv->numLeds; - } - break; - } - } - } - switch (type) { - case usbMouse: - if (test_bit(EV_REL) && test_bit(EV_KEY)) - goto found; - break; - case usbKeyboard: - if (test_bit(EV_KEY) && test_bit(EV_LED) && !test_bit(EV_ABS)) - goto found; - break; - case usbOther: - if (!(test_bit(EV_REL) && test_bit(EV_KEY)) - && !(test_bit(EV_KEY) && test_bit(EV_LED) - && !test_bit(EV_ABS))) - goto found; - break; - } - close(priv->fd); - priv->fd = -1; - } - } - if (priv->fd < 0) - FATAL1("usbInit: Cannot open /dev/input/event* port (%s)\n" - " If you have not done so, you may need to:\n" - " rmmod mousedev; rmmod keybdev\n" - " modprobe evdev\n", - strerror(errno)); - found: - usbPrint(priv, name, buf, priv->fd); -} - -/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ -void usbOff(DevicePtr pDev) -{ - GETPRIV; - - if (priv->fd >= 0) close(priv->fd); - priv->fd = -1; -} - -/** Create a private structure for use within this file. */ -pointer usbCreatePrivate(DeviceIntPtr pDevice) -{ - myPrivate *priv = calloc(1, sizeof(*priv)); - priv->fd = -1; - priv->pDevice = pDevice; - return priv; -} - -/** Destroy a private structure. */ -void usbDestroyPrivate(pointer priv) -{ - if (priv) free(priv); -} +/* + * Copyright 2002-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: + * Rickard E. (Rik) Faith + * + */ + +/** \file + * + * Routines that are common between \a usb-keyboard.c, \a usb-mouse.c, and + * \a usb-other.c */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "usb-private.h" + +#define USB_COMMON_DEBUG 1 + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "usb-mouse.h" + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define GETNAME ((DMXLocalInputInfoPtr)(pDevice->public.devicePrivate)) \ + ->name + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define LOG1INPUT(p,f,a) dmxLogInput(p->dmxInput,f,a) +#define LOG3INPUT(p,f,a,b,c) dmxLogInput(p->dmxInput,f,a,b,c) +#define LOG5INPUT(p,f,a,b,c,d,e) dmxLogInput(p->dmxInput,f,a,b,c,d,e) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define BLOCK DMXBlockType + +/* End of interface definitions. */ +/*****************************************************************************/ + + +/** Read an event from the \a pDev device. If the event is a motion + * event, enqueue it with the \a motion function. Otherwise, enqueue + * the event with the \a enqueue function. The \a block type is passed + * to the functions so that they may block SIGIO handling as appropriate + * to the caller of this function. + * + * Since USB devices return EV_KEY events for buttons and keys, \a + * minButton is used to decide if a Button or Key event should be + * queued.*/ +void usbRead(DevicePtr pDev, + MOTIONPROC motion, + ENQUEUEPROC enqueue, + int minButton, + BLOCK block) +{ + GETPRIV; + struct input_event raw; + int v[DMX_MAX_AXES]; + int axis; + +#define PRESS(b) \ + do { \ + enqueue(pDev, ButtonPress, 0, 0, NULL, block); \ + } while (0) + +#define RELEASE(b) \ + do { \ + enqueue(pDev, ButtonRelease, 0, 0, NULL, block); \ + } while (0) + + while (read(priv->fd, &raw, sizeof(raw)) > 0) { +#if USB_COMMON_DEBUG > 1 + LOG3("USB: type = %d, code = 0x%02x, value = %d\n", + raw.type, raw.code, raw.value); +#endif + switch (raw.type) { + case EV_KEY: + /* raw.value = 1 for first, 2 for repeat */ + if (raw.code > minButton) { + if (raw.value) PRESS((raw.code & 0x0f) + 1); + else RELEASE((raw.code & 0x0f) + 1); + } else { + enqueue(pDev, raw.value ? KeyPress : KeyRelease, + 0, 0, NULL, block); + } + break; + case EV_REL: + switch (raw.code) { + case REL_X: + v[0] = -raw.value; + v[1] = 0; + motion(pDev, v, 0, 2, DMX_RELATIVE, block); + break; + case REL_Y: + v[0] = 0; + v[1] = -raw.value; + motion(pDev, v, 0, 2, DMX_RELATIVE, block); + break; + case REL_WHEEL: + if ((int)raw.value > 0) { + PRESS(4); + RELEASE(4); + } else if ((int)raw.value < 0) { + PRESS(5); + RELEASE(5); + } + break; + default: + memset(v, 0, sizeof(v)); + axis = priv->relmap[raw.code]; + v[axis] = raw.value; + motion(pDev, v, axis, 1, DMX_RELATIVE, block); + } + break; + case EV_ABS: + memset(v, 0, sizeof(v)); + axis = priv->absmap[raw.code]; + v[axis] = raw.value; + motion(pDev, v, axis, 1, DMX_ABSOLUTE, block); + break; + } + } +} + +#define test_bit(bit) (priv->mask[(bit)/8] & (1 << ((bit)%8))) +#define test_bits(bit) (bits[(bit)/8] & (1 << ((bit)%8))) + +static void usbPrint(myPrivate *priv, + const char *filename, const char *devname, int fd) +{ + int j, k; + DeviceIntPtr pDevice = priv->pDevice; + unsigned char bits[KEY_MAX/8 + 1]; /* RATS: Use ok assuming that + * KEY_MAX is greater than + * REL_MAX, ABS_MAX, SND_MAX, and + * LED_MAX. */ + + LOG3INPUT(priv, "%s (%s) using %s\n", pDevice->name, GETNAME, filename); + LOG1INPUT(priv, " %s\n", devname); + for (j = 0; j < EV_MAX; j++) { + if (test_bit(j)) { + const char *type = "unknown"; + char extra[256]; /* FIXME: may cause buffer overflow */ + extra[0] = '\0'; + switch(j) { + case EV_KEY: type = "keys/buttons"; break; + case EV_REL: type = "relative"; + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_REL, sizeof(bits)), bits); + for (k = 0; k < REL_MAX; k++) { + if (test_bits(k)) switch (k) { + case REL_X: strcat(extra, " X"); break; + case REL_Y: strcat(extra, " Y"); break; + case REL_Z: strcat(extra, " Z"); break; + case REL_HWHEEL: strcat(extra, " HWheel"); break; + case REL_DIAL: strcat(extra, " Dial"); break; + case REL_WHEEL: strcat(extra, " Wheel"); break; + case REL_MISC: strcat(extra, " Misc"); break; + } + } + break; + case EV_ABS: type = "absolute"; + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_ABS, sizeof(bits)), bits); + for (k = 0; k < ABS_MAX; k++) { + if (test_bits(k)) switch (k) { + case ABS_X: strcat(extra," X"); break; + case ABS_Y: strcat(extra," Y"); break; + case ABS_Z: strcat(extra," Z"); break; + case ABS_RX: strcat(extra," RX"); break; + case ABS_RY: strcat(extra," RY"); break; + case ABS_RZ: strcat(extra," RZ"); break; + case ABS_THROTTLE: strcat(extra," Throttle");break; + case ABS_RUDDER: strcat(extra," Rudder"); break; + case ABS_WHEEL: strcat(extra," Wheel"); break; + case ABS_GAS: strcat(extra," Gas"); break; + case ABS_BRAKE: strcat(extra," Break"); break; + case ABS_HAT0X: strcat(extra," Hat0X"); break; + case ABS_HAT0Y: strcat(extra," Hat0Y"); break; + case ABS_HAT1X: strcat(extra," Hat1X"); break; + case ABS_HAT1Y: strcat(extra," Hat1Y"); break; + case ABS_HAT2X: strcat(extra," Hat2X"); break; + case ABS_HAT2Y: strcat(extra," Hat2Y"); break; + case ABS_HAT3X: strcat(extra," Hat3X"); break; + case ABS_HAT3Y: strcat(extra," Hat3Y"); break; + case ABS_PRESSURE: strcat(extra," Pressure");break; + case ABS_DISTANCE: strcat(extra," Distance");break; + case ABS_TILT_X: strcat(extra," TiltX"); break; + case ABS_TILT_Y: strcat(extra," TiltY"); break; + case ABS_MISC: strcat(extra," Misc"); break; + } + } + break; + case EV_MSC: type = "reserved"; break; + case EV_LED: type = "leds"; + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_LED, sizeof(bits)), bits); + for (k = 0; k < LED_MAX; k++) { + if (test_bits(k)) switch (k) { + case LED_NUML: strcat(extra," NumLock"); break; + case LED_CAPSL: strcat(extra," CapsLock"); break; + case LED_SCROLLL: strcat(extra," ScrlLock"); break; + case LED_COMPOSE: strcat(extra," Compose"); break; + case LED_KANA: strcat(extra," Kana"); break; + case LED_SLEEP: strcat(extra," Sleep"); break; + case LED_SUSPEND: strcat(extra," Suspend"); break; + case LED_MUTE: strcat(extra," Mute"); break; + case LED_MISC: strcat(extra," Misc"); break; + } + } + break; + case EV_SND: type = "sound"; + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_SND, sizeof(bits)), bits); + for (k = 0; k < SND_MAX; k++) { + if (test_bits(k)) switch (k) { + case SND_CLICK: strcat(extra," Click"); break; + case SND_BELL: strcat(extra," Bell"); break; + } + } + break; + case EV_REP: type = "repeat"; break; + case EV_FF: type = "feedback"; break; + } + LOG5INPUT(priv, " Feature 0x%02x = %s%s%s%s\n", j, type, + extra[0] ? " [" : "", + extra[0] ? extra+1 : "", + extra[0] ? "]" : ""); + } + } +} + +/** Initialized \a pDev as a \a usbMouse, \a usbKeyboard, or \a usbOther +device. */ +void usbInit(DevicePtr pDev, usbType type) +{ + GETPRIV; + char name[64]; /* RATS: Only used in XmuSnprintf */ + int i, j, k; + char buf[256] = { 0, }; /* RATS: Use ok */ + int version; + unsigned char bits[KEY_MAX/8 + 1]; /* RATS: Use ok assuming that + * KEY_MAX is greater than + * REL_MAX, ABS_MAX, SND_MAX, and + * LED_MAX. */ + + if (priv->fd >=0) return; + + for (i = 0; i < 32; i++) { + XmuSnprintf(name, sizeof(name), "/dev/input/event%d", i); + if ((priv->fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) { + ioctl(priv->fd, EVIOCGVERSION, &version); + ioctl(priv->fd, EVIOCGNAME(sizeof(buf)), buf); + memset(priv->mask, 0, sizeof(priv->mask)); + ioctl(priv->fd, EVIOCGBIT(0, sizeof(priv->mask)), priv->mask); + + for (j = 0; j < EV_MAX; j++) { + if (test_bit(j)) { + switch(j) { + case EV_REL: + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_REL, sizeof(bits)), bits); + for (k = 0; k < REL_MAX; k++) { + if (test_bits(k)) { + if (k == REL_X) priv->relmap[k] = 0; + else if (k == REL_Y) priv->relmap[k] = 1; + else priv->relmap[k] = 2 + priv->numAbs; + ++priv->numRel; + } + } + break; + case EV_ABS: + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_ABS, sizeof(bits)), bits); + for (k = 0; k < ABS_MAX; k++) { + if (test_bits(k)) { + priv->absmap[k] = priv->numAbs; + ++priv->numAbs; + } + } + break; + case EV_LED: + memset(bits, 0, sizeof(bits)); + ioctl(priv->fd, EVIOCGBIT(EV_LED, sizeof(bits)), bits); + for (k = 0; k < LED_MAX; k++) { + if (test_bits(k)) ++priv->numLeds; + } + break; + } + } + } + switch (type) { + case usbMouse: + if (test_bit(EV_REL) && test_bit(EV_KEY)) + goto found; + break; + case usbKeyboard: + if (test_bit(EV_KEY) && test_bit(EV_LED) && !test_bit(EV_ABS)) + goto found; + break; + case usbOther: + if (!(test_bit(EV_REL) && test_bit(EV_KEY)) + && !(test_bit(EV_KEY) && test_bit(EV_LED) + && !test_bit(EV_ABS))) + goto found; + break; + } + close(priv->fd); + priv->fd = -1; + } + } + if (priv->fd < 0) + FATAL1("usbInit: Cannot open /dev/input/event* port (%s)\n" + " If you have not done so, you may need to:\n" + " rmmod mousedev; rmmod keybdev\n" + " modprobe evdev\n", + strerror(errno)); + found: + usbPrint(priv, name, buf, priv->fd); +} + +/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ +void usbOff(DevicePtr pDev) +{ + GETPRIV; + + if (priv->fd >= 0) close(priv->fd); + priv->fd = -1; +} + +/** Create a private structure for use within this file. */ +pointer usbCreatePrivate(DeviceIntPtr pDevice) +{ + myPrivate *priv = calloc(1, sizeof(*priv)); + priv->fd = -1; + priv->pDevice = pDevice; + return priv; +} + +/** Destroy a private structure. */ +void usbDestroyPrivate(pointer priv) +{ + free(priv); +} -- cgit v1.2.3