From 0f834b91a4768673833ab4917e87d86c237bb1a6 Mon Sep 17 00:00:00 2001 From: marha Date: Fri, 23 Mar 2012 10:05:55 +0100 Subject: libX11 xserver fontconfig mesa pixman xkbcomp xkeyboard-config git update 23 Mar 2012 --- xorg-server/hw/dmx/input/dmxcommon.c | 1367 +++++++++++++++++----------------- 1 file changed, 698 insertions(+), 669 deletions(-) (limited to 'xorg-server/hw/dmx/input/dmxcommon.c') diff --git a/xorg-server/hw/dmx/input/dmxcommon.c b/xorg-server/hw/dmx/input/dmxcommon.c index 29c1958ad..5f25e8832 100644 --- a/xorg-server/hw/dmx/input/dmxcommon.c +++ b/xorg-server/hw/dmx/input/dmxcommon.c @@ -1,669 +1,698 @@ -/* - * 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 */ -} +/* + * 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 */ +} -- cgit v1.2.3