9838b7032e
This is strictly the application of the script 'x-indent-all.sh' from util/modular. Compared to the patch that Daniel posted in January, I've added a few indent flags: -bap -psl -T PrivatePtr -T pmWait -T _XFUNCPROTOBEGIN -T _XFUNCPROTOEND -T _X_EXPORT The typedefs were needed to make the output of sdksyms.sh match the previous output, otherwise, the code is formatted badly enough that sdksyms.sh generates incorrect output. The generated code was compared with the previous version and found to be essentially identical -- "assert" line numbers and BUILD_TIME were the only differences found. The comparison was done with this script: dir1=$1 dir2=$2 for dir in $dir1 $dir2; do (cd $dir && find . -name '*.o' | while read file; do dir=`dirname $file` base=`basename $file .o` dump=$dir/$base.dump objdump -d $file > $dump done) done find $dir1 -name '*.dump' | while read dump; do otherdump=`echo $dump | sed "s;$dir1;$dir2;"` diff -u $dump $otherdump done Signed-off-by: Keith Packard <keithp@keithp.com> Acked-by: Daniel Stone <daniel@fooishbar.org> Acked-by: Alan Coopersmith <alan.coopersmith@oracle.com>
699 lines
22 KiB
C
699 lines
22 KiB
C
/*
|
|
* Copyright 2001-2003 Red Hat Inc., Durham, North Carolina.
|
|
*
|
|
* All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation on the rights to use, copy, modify, merge,
|
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
* and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the
|
|
* next paragraph) shall be included in all copies or substantial
|
|
* portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
/*
|
|
* Authors:
|
|
* David H. Dawes <dawes@xfree86.org>
|
|
* Kevin E. Martin <kem@redhat.com>
|
|
* Rickard E. (Rik) Faith <faith@redhat.com>
|
|
*/
|
|
|
|
/** \file
|
|
*
|
|
* This file implements common routines used by the backend and console
|
|
* input devices.
|
|
*/
|
|
|
|
#ifdef HAVE_DMX_CONFIG_H
|
|
#include <dmx-config.h>
|
|
#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 <X11/keysym.h>
|
|
#include "mipointer.h"
|
|
#include "scrnintstr.h"
|
|
|
|
#include <unistd.h> /* 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 */
|
|
}
|