xserver-multidpi/hw/dmx/input/dmxcommon.c
Keith Packard 9838b7032e Introduce a consistent coding style
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>
2012-03-21 13:54:42 -07:00

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 */
}