xserver-multidpi/hw/dmx/input/dmxinputinit.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

1391 lines
43 KiB
C

/*
* 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 <faith@redhat.com>
*
*/
/** \file
* This file provides generic input support. Functions here set up
* input and lead to the calling of low-level device drivers for
* input. */
#ifdef HAVE_DMX_CONFIG_H
#include <dmx-config.h>
#endif
#define DMX_WINDOW_DEBUG 0
#include "dmxinputinit.h"
#include "dmxextension.h" /* For dmxInputCount */
#include "dmxdummy.h"
#include "dmxbackend.h"
#include "dmxconsole.h"
#include "dmxcommon.h"
#include "dmxevents.h"
#include "dmxmotion.h"
#include "dmxprop.h"
#include "config/dmxconfig.h"
#include "dmxcursor.h"
#include "lnx-keyboard.h"
#include "lnx-ms.h"
#include "lnx-ps2.h"
#include "usb-keyboard.h"
#include "usb-mouse.h"
#include "usb-other.h"
#include "usb-common.h"
#include "dmxsigio.h"
#include "dmxarg.h"
#include "inputstr.h"
#include "input.h"
#include "mipointer.h"
#include "windowstr.h"
#include "mi.h"
#include "xkbsrv.h"
#include <X11/extensions/XI.h>
#include <X11/extensions/XIproto.h>
#include "exevents.h"
#include "extinit.h"
DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard;
static DMXLocalInputInfoRec DMXDummyMou = {
"dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo
};
static DMXLocalInputInfoRec DMXDummyKbd = {
"dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo
};
static DMXLocalInputInfoRec DMXBackendMou = {
"backend-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_BACKEND, 2,
dmxBackendCreatePrivate, dmxBackendDestroyPrivate,
dmxBackendInit, NULL, dmxBackendLateReInit, dmxBackendMouGetInfo,
dmxCommonMouOn, dmxCommonMouOff, dmxBackendUpdatePosition,
NULL, NULL, NULL,
dmxBackendCollectEvents, dmxBackendProcessInput, dmxBackendFunctions, NULL,
dmxCommonMouCtrl
};
static DMXLocalInputInfoRec DMXBackendKbd = {
"backend-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_BACKEND,
1, /* With backend-mou or console-mou */
dmxCommonCopyPrivate, NULL,
dmxBackendInit, NULL, NULL, dmxBackendKbdGetInfo,
dmxCommonKbdOn, dmxCommonKbdOff, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, dmxCommonKbdCtrl, dmxCommonKbdBell
};
static DMXLocalInputInfoRec DMXConsoleMou = {
"console-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_CONSOLE, 2,
dmxConsoleCreatePrivate, dmxConsoleDestroyPrivate,
dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleMouGetInfo,
dmxCommonMouOn, dmxCommonMouOff, dmxConsoleUpdatePosition,
NULL, NULL, NULL,
dmxConsoleCollectEvents, NULL, dmxConsoleFunctions, dmxConsoleUpdateInfo,
dmxCommonMouCtrl
};
static DMXLocalInputInfoRec DMXConsoleKbd = {
"console-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_CONSOLE,
1, /* With backend-mou or console-mou */
dmxCommonCopyPrivate, NULL,
dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleKbdGetInfo,
dmxCommonKbdOn, dmxCommonKbdOff, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, dmxCommonKbdCtrl, dmxCommonKbdBell
};
static DMXLocalInputInfoRec DMXLocalDevices[] = {
/* Dummy drivers that can compile on any OS */
#ifdef __linux__
/* Linux-specific drivers */
{
"kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
kbdLinuxCreatePrivate, kbdLinuxDestroyPrivate,
kbdLinuxInit, NULL, NULL, kbdLinuxGetInfo,
kbdLinuxOn, kbdLinuxOff, NULL,
kbdLinuxVTPreSwitch, kbdLinuxVTPostSwitch, kbdLinuxVTSwitch,
kbdLinuxRead, NULL, NULL, NULL,
NULL, kbdLinuxCtrl, kbdLinuxBell},
{
"ms", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
msLinuxCreatePrivate, msLinuxDestroyPrivate,
msLinuxInit, NULL, NULL, msLinuxGetInfo,
msLinuxOn, msLinuxOff, NULL,
msLinuxVTPreSwitch, msLinuxVTPostSwitch, NULL,
msLinuxRead},
{
"ps2", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
ps2LinuxCreatePrivate, ps2LinuxDestroyPrivate,
ps2LinuxInit, NULL, NULL, ps2LinuxGetInfo,
ps2LinuxOn, ps2LinuxOff, NULL,
ps2LinuxVTPreSwitch, ps2LinuxVTPostSwitch, NULL,
ps2LinuxRead},
#endif
#ifdef __linux__
/* USB drivers, currently only for
Linux, but relatively easy to port to
other OSs */
{
"usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
usbCreatePrivate, usbDestroyPrivate,
kbdUSBInit, NULL, NULL, kbdUSBGetInfo,
kbdUSBOn, usbOff, NULL,
NULL, NULL, NULL,
kbdUSBRead, NULL, NULL, NULL,
NULL, kbdUSBCtrl},
{
"usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
usbCreatePrivate, usbDestroyPrivate,
mouUSBInit, NULL, NULL, mouUSBGetInfo,
mouUSBOn, usbOff, NULL,
NULL, NULL, NULL,
mouUSBRead},
{
"usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1,
usbCreatePrivate, usbDestroyPrivate,
othUSBInit, NULL, NULL, othUSBGetInfo,
othUSBOn, usbOff, NULL,
NULL, NULL, NULL,
othUSBRead},
#endif
{
"dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo},
{
"dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo},
{NULL} /* Must be last */
};
#if 11 /*BP*/
void
DDXRingBell(int volume, int pitch, int duration)
{
/* NO-OP */
}
/* taken from kdrive/src/kinput.c: */
static void
dmxKbdCtrl(DeviceIntPtr pDevice, KeybdCtrl * ctrl)
{
#if 0
KdKeyboardInfo *ki;
for (ki = kdKeyboards; ki; ki = ki->next) {
if (ki->dixdev && ki->dixdev->id == pDevice->id)
break;
}
if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver)
return;
KdSetLeds(ki, ctrl->leds);
ki->bellPitch = ctrl->bell_pitch;
ki->bellDuration = ctrl->bell_duration;
#endif
}
/* taken from kdrive/src/kinput.c: */
static void
dmxBell(int volume, DeviceIntPtr pDev, pointer arg, int something)
{
#if 0
KeybdCtrl *ctrl = arg;
KdKeyboardInfo *ki = NULL;
for (ki = kdKeyboards; ki; ki = ki->next) {
if (ki->dixdev && ki->dixdev->id == pDev->id)
break;
}
if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver)
return;
KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration);
#endif
}
#endif /*BP*/
static void
_dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal, PtrCtrl * ctrl)
{
if (!dmxLocal)
return;
dmxLocal->mctrl = *ctrl;
if (dmxLocal->mCtrl)
dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl);
}
/** Change the pointer control information for the \a pDevice. If the
* device sends core events, then also change the control information
* for all of the pointer devices that send core events. */
void
dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl * ctrl)
{
GETDMXLOCALFROMPDEVICE;
int i, j;
if (dmxLocal->sendsCore) { /* Do for all core devices */
for (i = 0; i < dmxNumInputs; i++) {
DMXInputInfo *dmxInput = &dmxInputs[i];
if (dmxInput->detached)
continue;
for (j = 0; j < dmxInput->numDevs; j++)
if (dmxInput->devs[j]->sendsCore)
_dmxChangePointerControl(dmxInput->devs[j], ctrl);
}
}
else { /* Do for this device only */
_dmxChangePointerControl(dmxLocal, ctrl);
}
}
static void
_dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal, KeybdCtrl * ctrl)
{
dmxLocal->kctrl = *ctrl;
if (dmxLocal->kCtrl) {
dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl);
if (dmxLocal->pDevice->kbdfeed) {
XkbEventCauseRec cause;
XkbSetCauseUnknown(&cause);
/* Generate XKB events, as necessary */
XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False,
NULL, &cause);
}
}
}
/** Change the keyboard control information for the \a pDevice. If the
* device sends core events, then also change the control information
* for all of the keyboard devices that send core events. */
void
dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl * ctrl)
{
GETDMXLOCALFROMPDEVICE;
int i, j;
if (dmxLocal->sendsCore) { /* Do for all core devices */
for (i = 0; i < dmxNumInputs; i++) {
DMXInputInfo *dmxInput = &dmxInputs[i];
if (dmxInput->detached)
continue;
for (j = 0; j < dmxInput->numDevs; j++)
if (dmxInput->devs[j]->sendsCore)
_dmxKeyboardKbdCtrlProc(dmxInput->devs[j], ctrl);
}
}
else { /* Do for this device only */
_dmxKeyboardKbdCtrlProc(dmxLocal, ctrl);
}
}
static void
_dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent)
{
if (dmxLocal->kBell)
dmxLocal->kBell(&dmxLocal->pDevice->public,
percent,
dmxLocal->kctrl.bell,
dmxLocal->kctrl.bell_pitch,
dmxLocal->kctrl.bell_duration);
}
/** Sound the bell on the device. If the device send core events, then
* sound the bell on all of the devices that send core events. */
void
dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice,
pointer ctrl, int unknown)
{
GETDMXLOCALFROMPDEVICE;
int i, j;
if (dmxLocal->sendsCore) { /* Do for all core devices */
for (i = 0; i < dmxNumInputs; i++) {
DMXInputInfo *dmxInput = &dmxInputs[i];
if (dmxInput->detached)
continue;
for (j = 0; j < dmxInput->numDevs; j++)
if (dmxInput->devs[j]->sendsCore)
_dmxKeyboardBellProc(dmxInput->devs[j], percent);
}
}
else { /* Do for this device only */
_dmxKeyboardBellProc(dmxLocal, percent);
}
}
static void
dmxKeyboardFreeNames(XkbComponentNamesPtr names)
{
if (names->keycodes)
XFree(names->keycodes);
if (names->types)
XFree(names->types);
if (names->compat)
XFree(names->compat);
if (names->symbols)
XFree(names->symbols);
if (names->geometry)
XFree(names->geometry);
}
static int
dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo * info)
{
GETDMXINPUTFROMPDEVICE;
XkbRMLVOSet rmlvo;
rmlvo.rules = dmxConfigGetXkbRules();
rmlvo.model = dmxConfigGetXkbModel();
rmlvo.layout = dmxConfigGetXkbLayout();
rmlvo.variant = dmxConfigGetXkbVariant();
rmlvo.options = dmxConfigGetXkbOptions();
XkbSetRulesDflts(&rmlvo);
if (!info->force && (dmxInput->keycodes
|| dmxInput->symbols || dmxInput->geometry)) {
if (info->freenames)
dmxKeyboardFreeNames(&info->names);
info->freenames = 0;
info->names.keycodes = dmxInput->keycodes;
info->names.types = NULL;
info->names.compat = NULL;
info->names.symbols = dmxInput->symbols;
info->names.geometry = dmxInput->geometry;
dmxLogInput(dmxInput, "XKEYBOARD: From command line: %s",
info->names.keycodes);
if (info->names.symbols && *info->names.symbols)
dmxLogInputCont(dmxInput, " %s", info->names.symbols);
if (info->names.geometry && *info->names.geometry)
dmxLogInputCont(dmxInput, " %s", info->names.geometry);
dmxLogInputCont(dmxInput, "\n");
}
else if (info->names.keycodes) {
dmxLogInput(dmxInput, "XKEYBOARD: From device: %s",
info->names.keycodes);
if (info->names.symbols && *info->names.symbols)
dmxLogInputCont(dmxInput, " %s", info->names.symbols);
if (info->names.geometry && *info->names.geometry)
dmxLogInputCont(dmxInput, " %s", info->names.geometry);
dmxLogInputCont(dmxInput, "\n");
}
else {
dmxLogInput(dmxInput, "XKEYBOARD: Defaults: %s %s %s %s %s\n",
dmxConfigGetXkbRules(),
dmxConfigGetXkbLayout(),
dmxConfigGetXkbModel(), dmxConfigGetXkbVariant()
? dmxConfigGetXkbVariant() : "", dmxConfigGetXkbOptions()
? dmxConfigGetXkbOptions() : "");
}
InitKeyboardDeviceStruct(pDevice, &rmlvo,
dmxKeyboardBellProc, dmxKeyboardKbdCtrlProc);
if (info->freenames)
dmxKeyboardFreeNames(&info->names);
return Success;
}
static int
dmxDeviceOnOff(DeviceIntPtr pDevice, int what)
{
GETDMXINPUTFROMPDEVICE;
int fd;
DMXLocalInitInfo info;
int i;
Atom btn_labels[MAX_BUTTONS] = { 0 }; /* FIXME */
Atom axis_labels[MAX_VALUATORS] = { 0 }; /* FIXME */
if (dmxInput->detached)
return Success;
memset(&info, 0, sizeof(info));
switch (what) {
case DEVICE_INIT:
if (dmxLocal->init)
dmxLocal->init(pDev);
if (dmxLocal->get_info)
dmxLocal->get_info(pDev, &info);
if (info.keyboard) { /* XKEYBOARD makes this a special case */
dmxKeyboardOn(pDevice, &info);
break;
}
if (info.keyClass) {
XkbRMLVOSet rmlvo;
rmlvo.rules = dmxConfigGetXkbRules();
rmlvo.model = dmxConfigGetXkbModel();
rmlvo.layout = dmxConfigGetXkbLayout();
rmlvo.variant = dmxConfigGetXkbVariant();
rmlvo.options = dmxConfigGetXkbOptions();
InitKeyboardDeviceStruct(pDevice, &rmlvo, dmxBell, dmxKbdCtrl);
}
if (info.buttonClass) {
InitButtonClassDeviceStruct(pDevice, info.numButtons,
btn_labels, info.map);
}
if (info.valuatorClass) {
if (info.numRelAxes && dmxLocal->sendsCore) {
InitValuatorClassDeviceStruct(pDevice, info.numRelAxes,
axis_labels,
GetMaximumEventsNum(), Relative);
for (i = 0; i < info.numRelAxes; i++)
InitValuatorAxisStruct(pDevice, i, axis_labels[i],
info.minval[i], info.maxval[i],
info.res[i],
info.minres[i], info.maxres[i],
Relative);
}
else if (info.numRelAxes) {
InitValuatorClassDeviceStruct(pDevice, info.numRelAxes,
axis_labels,
dmxPointerGetMotionBufferSize(),
Relative);
for (i = 0; i < info.numRelAxes; i++)
InitValuatorAxisStruct(pDevice, i, axis_labels[i],
info.minval[i],
info.maxval[i], info.res[i],
info.minres[i], info.maxres[i],
Relative);
}
else if (info.numAbsAxes) {
InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes,
axis_labels,
dmxPointerGetMotionBufferSize(),
Absolute);
for (i = 0; i < info.numAbsAxes; i++)
InitValuatorAxisStruct(pDevice, i,
axis_labels[i],
info.minval[i], info.maxval[i],
info.res[i], info.minres[i],
info.maxres[i], Absolute);
}
}
if (info.focusClass)
InitFocusClassDeviceStruct(pDevice);
if (info.proximityClass)
InitProximityClassDeviceStruct(pDevice);
if (info.ptrFeedbackClass)
InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl);
if (info.intFeedbackClass || info.strFeedbackClass)
dmxLog(dmxWarning,
"Integer and string feedback not supported for %s\n",
pDevice->name);
if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass))
dmxLog(dmxWarning,
"Led and bel feedback not supported for non-keyboard %s\n",
pDevice->name);
break;
case DEVICE_ON:
if (!pDev->on) {
if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0)
dmxSigioRegister(dmxInput, fd);
pDev->on = TRUE;
}
break;
case DEVICE_OFF:
case DEVICE_CLOSE:
/* This can get called twice consecutively: once for a
* detached screen (DEVICE_OFF), and then again at server
* generation time (DEVICE_CLOSE). */
if (pDev->on) {
dmxSigioUnregister(dmxInput);
if (dmxLocal->off)
dmxLocal->off(pDev);
pDev->on = FALSE;
}
break;
}
if (info.keySyms.map && info.freemap) {
XFree(info.keySyms.map);
info.keySyms.map = NULL;
}
if (info.xkb)
XkbFreeKeyboard(info.xkb, 0, True);
return Success;
}
static void
dmxProcessInputEvents(DMXInputInfo * dmxInput)
{
int i;
mieqProcessInputEvents();
#if 00 /*BP*/
miPointerUpdate();
#endif
if (dmxInput->detached)
return;
for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding)
if (dmxInput->devs[i]->process_input) {
dmxInput->devs[i]->process_input(dmxInput->devs[i]->private);
}
#if 11 /*BP*/
mieqProcessInputEvents();
#endif
}
static void
dmxUpdateWindowInformation(DMXInputInfo * dmxInput,
DMXUpdateType type, WindowPtr pWindow)
{
int i;
#ifdef PANORAMIX
if (!noPanoramiXExtension && pWindow &&
pWindow->parent != screenInfo.screens[0]->root)
return;
#endif
#if DMX_WINDOW_DEBUG
{
const char *name = "Unknown";
switch (type) {
case DMX_UPDATE_REALIZE:
name = "Realize";
break;
case DMX_UPDATE_UNREALIZE:
name = "Unrealize";
break;
case DMX_UPDATE_RESTACK:
name = "Restack";
break;
case DMX_UPDATE_COPY:
name = "Copy";
break;
case DMX_UPDATE_RESIZE:
name = "Resize";
break;
case DMX_UPDATE_REPARENT:
name = "Repaint";
break;
}
dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name);
}
#endif
if (dmxInput->detached)
return;
for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding)
if (dmxInput->devs[i]->update_info)
dmxInput->devs[i]->update_info(dmxInput->devs[i]->private,
type, pWindow);
}
static void
dmxCollectAll(DMXInputInfo * dmxInput)
{
int i;
if (dmxInput->detached)
return;
for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding)
if (dmxInput->devs[i]->collect_events)
dmxInput->devs[i]->collect_events(&dmxInput->devs[i]->pDevice->
public, dmxMotion, dmxEnqueue,
dmxCheckSpecialKeys, DMX_BLOCK);
}
static void
dmxBlockHandler(pointer blockData, OSTimePtr pTimeout, pointer pReadMask)
{
DMXInputInfo *dmxInput = &dmxInputs[(uintptr_t) blockData];
static unsigned long generation = 0;
if (generation != serverGeneration) {
generation = serverGeneration;
dmxCollectAll(dmxInput);
}
}
static void
dmxSwitchReturn(pointer p)
{
DMXInputInfo *dmxInput = p;
int i;
dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched);
if (!dmxInput->vt_switched)
dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n");
dmxSigioEnableInput();
for (i = 0; i < dmxInput->numDevs; i++)
if (dmxInput->devs[i]->vt_post_switch)
dmxInput->devs[i]->vt_post_switch(dmxInput->devs[i]->private);
dmxInput->vt_switched = 0;
}
static void
dmxWakeupHandler(pointer blockData, int result, pointer pReadMask)
{
DMXInputInfo *dmxInput = &dmxInputs[(uintptr_t) blockData];
int i;
if (dmxInput->vt_switch_pending) {
dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending);
for (i = 0; i < dmxInput->numDevs; i++)
if (dmxInput->devs[i]->vt_pre_switch)
dmxInput->devs[i]->vt_pre_switch(dmxInput->devs[i]->private);
dmxInput->vt_switched = dmxInput->vt_switch_pending;
dmxInput->vt_switch_pending = 0;
for (i = 0; i < dmxInput->numDevs; i++) {
if (dmxInput->devs[i]->vt_switch) {
dmxSigioDisableInput();
if (!dmxInput->devs[i]->vt_switch(dmxInput->devs[i]->private,
dmxInput->vt_switched,
dmxSwitchReturn, dmxInput))
dmxSwitchReturn(dmxInput);
break; /* Only call one vt_switch routine */
}
}
}
dmxCollectAll(dmxInput);
}
static char *
dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal)
{
static int k = 0;
static int m = 0;
static int o = 0;
static unsigned long dmxGeneration = 0;
#define LEN 32
char *buf = malloc(LEN);
if (dmxGeneration != serverGeneration) {
k = m = o = 0;
dmxGeneration = serverGeneration;
}
switch (dmxLocal->type) {
case DMX_LOCAL_KEYBOARD:
snprintf(buf, LEN, "Keyboard%d", k++);
break;
case DMX_LOCAL_MOUSE:
snprintf(buf, LEN, "Mouse%d", m++);
break;
default:
snprintf(buf, LEN, "Other%d", o++);
break;
}
return buf;
}
static DeviceIntPtr
dmxAddDevice(DMXLocalInputInfoPtr dmxLocal)
{
DeviceIntPtr pDevice;
Atom atom;
const char *name = NULL;
char *devname;
DMXInputInfo *dmxInput;
if (!dmxLocal)
return NULL;
dmxInput = &dmxInputs[dmxLocal->inputIdx];
if (dmxLocal->sendsCore) {
if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) {
dmxLocal->isCore = 1;
dmxLocalCoreKeyboard = dmxLocal;
name = "keyboard";
}
if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) {
dmxLocal->isCore = 1;
dmxLocalCorePointer = dmxLocal;
name = "pointer";
}
}
if (!name) {
name = "extension";
}
if (!name)
dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name);
pDevice = AddInputDevice(serverClient, dmxDeviceOnOff, TRUE);
if (!pDevice) {
dmxLog(dmxError, "Too many devices -- cannot add device %s\n",
dmxLocal->name);
return NULL;
}
pDevice->public.devicePrivate = dmxLocal;
dmxLocal->pDevice = pDevice;
devname = dmxMakeUniqueDeviceName(dmxLocal);
atom = MakeAtom((char *) devname, strlen(devname), TRUE);
pDevice->type = atom;
pDevice->name = devname;
if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE) {
#if 00 /*BP*/
miRegisterPointerDevice(screenInfo.screens[0], pDevice);
#else
/* Nothing? dmxDeviceOnOff() should get called to init, right? */
#endif
}
if (dmxLocal->create_private)
dmxLocal->private = dmxLocal->create_private(pDevice);
dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n",
dmxLocal->name, name, devname,
dmxLocal->isCore
? " [core]"
: (dmxLocal->sendsCore ? " [sends core events]" : ""));
return pDevice;
}
static DMXLocalInputInfoPtr
dmxLookupLocal(const char *name)
{
DMXLocalInputInfoPtr pt;
for (pt = &DMXLocalDevices[0]; pt->name; ++pt)
if (!strcmp(pt->name, name))
return pt; /* search for device name */
return NULL;
}
/** Copy the local input information from \a s into a new \a devs slot
* in \a dmxInput. */
DMXLocalInputInfoPtr
dmxInputCopyLocal(DMXInputInfo * dmxInput, DMXLocalInputInfoPtr s)
{
DMXLocalInputInfoPtr dmxLocal = malloc(sizeof(*dmxLocal));
if (!dmxLocal)
dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n");
memcpy(dmxLocal, s, sizeof(*dmxLocal));
dmxLocal->inputIdx = dmxInput->inputIdx;
dmxLocal->sendsCore = dmxInput->core;
dmxLocal->savedSendsCore = dmxInput->core;
dmxLocal->deviceId = -1;
++dmxInput->numDevs;
dmxInput->devs = realloc(dmxInput->devs,
dmxInput->numDevs * sizeof(*dmxInput->devs));
dmxInput->devs[dmxInput->numDevs - 1] = dmxLocal;
return dmxLocal;
}
static void
dmxPopulateLocal(DMXInputInfo * dmxInput, dmxArg a)
{
int i;
int help = 0;
DMXLocalInputInfoRec *pt;
for (i = 1; i < dmxArgC(a); i++) {
const char *name = dmxArgV(a, i);
if ((pt = dmxLookupLocal(name))) {
dmxInputCopyLocal(dmxInput, pt);
}
else {
if (strlen(name))
dmxLog(dmxWarning, "Could not find a driver called %s\n", name);
++help;
}
}
if (help) {
dmxLog(dmxInfo, "Available local device drivers:\n");
for (pt = &DMXLocalDevices[0]; pt->name; ++pt) {
const char *type;
switch (pt->type) {
case DMX_LOCAL_KEYBOARD:
type = "keyboard";
break;
case DMX_LOCAL_MOUSE:
type = "pointer";
break;
default:
type = "unknown";
break;
}
dmxLog(dmxInfo, " %s (%s)\n", pt->name, type);
}
dmxLog(dmxFatal, "Must have valid local device driver\n");
}
}
int
dmxInputExtensionErrorHandler(Display * dsp, _Xconst char *name,
_Xconst char *reason)
{
return 0;
}
static void
dmxInputScanForExtensions(DMXInputInfo * dmxInput, int doXI)
{
XExtensionVersion *ext;
XDeviceInfo *devices;
Display *display;
int num;
int i, j;
XextErrorHandler handler;
if (!(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) {
dmxLogInput(dmxInput, "%s is not available\n", INAME);
}
else {
dmxLogInput(dmxInput, "Locating devices on %s (%s version %d.%d)\n",
dmxInput->name, INAME,
ext->major_version, ext->minor_version);
devices = XListInputDevices(display, &num);
XFree(ext);
ext = NULL;
/* Print a list of all devices */
for (i = 0; i < num; i++) {
const char *use = "Unknown";
switch (devices[i].use) {
case IsXPointer:
use = "XPointer";
break;
case IsXKeyboard:
use = "XKeyboard";
break;
case IsXExtensionDevice:
use = "XExtensionDevice";
break;
case IsXExtensionPointer:
use = "XExtensionPointer";
break;
case IsXExtensionKeyboard:
use = "XExtensionKeyboard";
break;
}
dmxLogInput(dmxInput, " %2d %-10.10s %-16.16s\n",
devices[i].id,
devices[i].name ? devices[i].name : "", use);
}
/* Search for extensions */
for (i = 0; i < num; i++) {
switch (devices[i].use) {
case IsXKeyboard:
for (j = 0; j < dmxInput->numDevs; j++) {
DMXLocalInputInfoPtr dmxL = dmxInput->devs[j];
if (dmxL->type == DMX_LOCAL_KEYBOARD && dmxL->deviceId < 0) {
dmxL->deviceId = devices[i].id;
dmxL->deviceName = (devices[i].name
? strdup(devices[i].name)
: NULL);
}
}
break;
case IsXPointer:
for (j = 0; j < dmxInput->numDevs; j++) {
DMXLocalInputInfoPtr dmxL = dmxInput->devs[j];
if (dmxL->type == DMX_LOCAL_MOUSE && dmxL->deviceId < 0) {
dmxL->deviceId = devices[i].id;
dmxL->deviceName = (devices[i].name
? xstrdup(devices[i].name)
: NULL);
}
}
break;
}
}
XFreeDeviceList(devices);
}
XCloseDisplay(display);
}
/** Re-initialize all the devices described in \a dmxInput. Called from
#dmxAdjustCursorBoundaries before the cursor is redisplayed. */
void
dmxInputReInit(DMXInputInfo * dmxInput)
{
int i;
for (i = 0; i < dmxInput->numDevs; i++) {
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
if (dmxLocal->reinit)
dmxLocal->reinit(&dmxLocal->pDevice->public);
}
}
/** Re-initialize all the devices described in \a dmxInput. Called from
#dmxAdjustCursorBoundaries after the cursor is redisplayed. */
void
dmxInputLateReInit(DMXInputInfo * dmxInput)
{
int i;
for (i = 0; i < dmxInput->numDevs; i++) {
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
if (dmxLocal->latereinit)
dmxLocal->latereinit(&dmxLocal->pDevice->public);
}
}
/** Initialize all of the devices described in \a dmxInput. */
void
dmxInputInit(DMXInputInfo * dmxInput)
{
DeviceIntPtr pPointer = NULL, pKeyboard = NULL;
dmxArg a;
const char *name;
int i;
int doXI = 1; /* Include by default */
int forceConsole = 0;
int doWindows = 1; /* On by default */
int hasXkb = 0;
a = dmxArgParse(dmxInput->name);
for (i = 1; i < dmxArgC(a); i++) {
switch (hasXkb) {
case 1:
dmxInput->keycodes = xstrdup(dmxArgV(a, i));
++hasXkb;
break;
case 2:
dmxInput->symbols = xstrdup(dmxArgV(a, i));
++hasXkb;
break;
case 3:
dmxInput->geometry = xstrdup(dmxArgV(a, i));
hasXkb = 0;
break;
case 0:
if (!strcmp(dmxArgV(a, i), "noxi"))
doXI = 0;
else if (!strcmp(dmxArgV(a, i), "xi"))
doXI = 1;
else if (!strcmp(dmxArgV(a, i), "console"))
forceConsole = 1;
else if (!strcmp(dmxArgV(a, i), "noconsole"))
forceConsole = 0;
else if (!strcmp(dmxArgV(a, i), "windows"))
doWindows = 1;
else if (!strcmp(dmxArgV(a, i), "nowindows"))
doWindows = 0;
else if (!strcmp(dmxArgV(a, i), "xkb"))
hasXkb = 1;
else {
dmxLog(dmxFatal, "Unknown input argument: %s\n", dmxArgV(a, i));
}
}
}
name = dmxArgV(a, 0);
if (!strcmp(name, "local")) {
dmxPopulateLocal(dmxInput, a);
}
else if (!strcmp(name, "dummy")) {
dmxInputCopyLocal(dmxInput, &DMXDummyMou);
dmxInputCopyLocal(dmxInput, &DMXDummyKbd);
dmxLogInput(dmxInput, "Using dummy input\n");
}
else {
int found;
for (found = 0, i = 0; i < dmxNumScreens; i++) {
if (dmxPropertySameDisplay(&dmxScreens[i], name)) {
if (dmxScreens[i].shared)
dmxLog(dmxFatal,
"Cannot take input from shared backend (%s)\n",
name);
if (!dmxInput->core) {
dmxLog(dmxWarning,
"Cannot use core devices on a backend (%s)"
" as XInput devices\n", name);
}
else {
char *pt;
for (pt = (char *) dmxInput->name; pt && *pt; pt++)
if (*pt == ',')
*pt = '\0';
dmxInputCopyLocal(dmxInput, &DMXBackendMou);
dmxInputCopyLocal(dmxInput, &DMXBackendKbd);
dmxInput->scrnIdx = i;
dmxLogInput(dmxInput,
"Using backend input from %s\n", name);
}
++found;
break;
}
}
if (!found || forceConsole) {
char *pt;
if (found)
dmxInput->console = TRUE;
for (pt = (char *) dmxInput->name; pt && *pt; pt++)
if (*pt == ',')
*pt = '\0';
dmxInputCopyLocal(dmxInput, &DMXConsoleMou);
dmxInputCopyLocal(dmxInput, &DMXConsoleKbd);
if (doWindows) {
dmxInput->windows = TRUE;
dmxInput->updateWindowInfo = dmxUpdateWindowInformation;
}
dmxLogInput(dmxInput,
"Using console input from %s (%s windows)\n",
name, doWindows ? "with" : "without");
}
}
dmxArgFree(a);
/* Locate extensions we may be interested in */
dmxInputScanForExtensions(dmxInput, doXI);
for (i = 0; i < dmxInput->numDevs; i++) {
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
dmxLocal->pDevice = dmxAddDevice(dmxLocal);
if (dmxLocal->isCore) {
if (dmxLocal->type == DMX_LOCAL_MOUSE)
pPointer = dmxLocal->pDevice;
if (dmxLocal->type == DMX_LOCAL_KEYBOARD)
pKeyboard = dmxLocal->pDevice;
}
}
dmxInput->processInputEvents = dmxProcessInputEvents;
dmxInput->detached = False;
RegisterBlockAndWakeupHandlers(dmxBlockHandler, dmxWakeupHandler,
(void *) (uintptr_t) dmxInput->inputIdx);
}
static void
dmxInputFreeLocal(DMXLocalInputInfoRec * local)
{
if (!local)
return;
if (local->isCore && local->type == DMX_LOCAL_MOUSE)
dmxLocalCorePointer = NULL;
if (local->isCore && local->type == DMX_LOCAL_KEYBOARD)
dmxLocalCoreKeyboard = NULL;
if (local->destroy_private)
local->destroy_private(local->private);
free(local->history);
free(local->valuators);
free(local->deviceName);
local->private = NULL;
local->history = NULL;
local->deviceName = NULL;
free(local);
}
/** Free all of the memory associated with \a dmxInput */
void
dmxInputFree(DMXInputInfo * dmxInput)
{
int i;
if (!dmxInput)
return;
free(dmxInput->keycodes);
free(dmxInput->symbols);
free(dmxInput->geometry);
for (i = 0; i < dmxInput->numDevs; i++) {
dmxInputFreeLocal(dmxInput->devs[i]);
dmxInput->devs[i] = NULL;
}
free(dmxInput->devs);
dmxInput->devs = NULL;
dmxInput->numDevs = 0;
if (dmxInput->freename)
free(dmxInput->name);
dmxInput->name = NULL;
}
/** Log information about all of the known devices using #dmxLog(). */
void
dmxInputLogDevices(void)
{
int i, j;
dmxLog(dmxInfo, "%d devices:\n", dmxGetInputCount());
dmxLog(dmxInfo, " Id Name Classes\n");
for (j = 0; j < dmxNumInputs; j++) {
DMXInputInfo *dmxInput = &dmxInputs[j];
const char *pt = strchr(dmxInput->name, ',');
int len = (pt ? (size_t) (pt - dmxInput->name)
: strlen(dmxInput->name));
for (i = 0; i < dmxInput->numDevs; i++) {
DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice;
if (pDevice) {
dmxLog(dmxInfo, " %2d%c %-20.20s",
pDevice->id,
dmxInput->detached ? 'D' : ' ', pDevice->name);
if (pDevice->key)
dmxLogCont(dmxInfo, " key");
if (pDevice->valuator)
dmxLogCont(dmxInfo, " val");
if (pDevice->button)
dmxLogCont(dmxInfo, " btn");
if (pDevice->focus)
dmxLogCont(dmxInfo, " foc");
if (pDevice->kbdfeed)
dmxLogCont(dmxInfo, " fb/kbd");
if (pDevice->ptrfeed)
dmxLogCont(dmxInfo, " fb/ptr");
if (pDevice->intfeed)
dmxLogCont(dmxInfo, " fb/int");
if (pDevice->stringfeed)
dmxLogCont(dmxInfo, " fb/str");
if (pDevice->bell)
dmxLogCont(dmxInfo, " fb/bel");
if (pDevice->leds)
dmxLogCont(dmxInfo, " fb/led");
if (!pDevice->key && !pDevice->valuator && !pDevice->button
&& !pDevice->focus && !pDevice->kbdfeed
&& !pDevice->ptrfeed && !pDevice->intfeed
&& !pDevice->stringfeed && !pDevice->bell && !pDevice->leds)
dmxLogCont(dmxInfo, " (none)");
dmxLogCont(dmxInfo, "\t[i%d/%*.*s",
dmxInput->inputIdx, len, len, dmxInput->name);
if (dmxInput->devs[i]->deviceId >= 0)
dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId);
if (dmxInput->devs[i]->deviceName)
dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName);
dmxLogCont(dmxInfo, "] %s\n",
dmxInput->devs[i]->isCore
? "core"
: (dmxInput->devs[i]->sendsCore
? "extension (sends core events)" : "extension"));
}
}
}
}
/** Detach an input */
int
dmxInputDetach(DMXInputInfo * dmxInput)
{
int i;
if (dmxInput->detached)
return BadAccess;
for (i = 0; i < dmxInput->numDevs; i++) {
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n",
dmxLocal->pDevice->id,
dmxLocal->pDevice->name,
dmxLocal->isCore
? " [core]"
: (dmxLocal->sendsCore ? " [sends core events]" : ""));
DisableDevice(dmxLocal->pDevice, TRUE);
}
dmxInput->detached = True;
dmxInputLogDevices();
return 0;
}
/** Search for input associated with \a dmxScreen, and detach. */
void
dmxInputDetachAll(DMXScreenInfo * dmxScreen)
{
int i;
for (i = 0; i < dmxNumInputs; i++) {
DMXInputInfo *dmxInput = &dmxInputs[i];
if (dmxInput->scrnIdx == dmxScreen->index)
dmxInputDetach(dmxInput);
}
}
/** Search for input associated with \a deviceId, and detach. */
int
dmxInputDetachId(int id)
{
DMXInputInfo *dmxInput = dmxInputLocateId(id);
if (!dmxInput)
return BadValue;
return dmxInputDetach(dmxInput);
}
DMXInputInfo *
dmxInputLocateId(int id)
{
int i, j;
for (i = 0; i < dmxNumInputs; i++) {
DMXInputInfo *dmxInput = &dmxInputs[i];
for (j = 0; j < dmxInput->numDevs; j++) {
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j];
if (dmxLocal->pDevice->id == id)
return dmxInput;
}
}
return NULL;
}
static int
dmxInputAttachNew(DMXInputInfo * dmxInput, int *id)
{
dmxInputInit(dmxInput);
InitAndStartDevices();
if (id && dmxInput->devs)
*id = dmxInput->devs[0]->pDevice->id;
dmxInputLogDevices();
return 0;
}
static int
dmxInputAttachOld(DMXInputInfo * dmxInput, int *id)
{
int i;
dmxInput->detached = False;
for (i = 0; i < dmxInput->numDevs; i++) {
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
if (id)
*id = dmxLocal->pDevice->id;
dmxLogInput(dmxInput,
"Attaching device id %d: %s%s\n",
dmxLocal->pDevice->id,
dmxLocal->pDevice->name,
dmxLocal->isCore
? " [core]"
: (dmxLocal->sendsCore ? " [sends core events]" : ""));
EnableDevice(dmxLocal->pDevice, TRUE);
}
dmxInputLogDevices();
return 0;
}
int
dmxInputAttachConsole(const char *name, int isCore, int *id)
{
DMXInputInfo *dmxInput;
int i;
for (i = 0; i < dmxNumInputs; i++) {
dmxInput = &dmxInputs[i];
if (dmxInput->scrnIdx == -1
&& dmxInput->detached && !strcmp(dmxInput->name, name)) {
/* Found match */
dmxLogInput(dmxInput, "Reattaching detached console input\n");
return dmxInputAttachOld(dmxInput, id);
}
}
/* No match found */
dmxInput = dmxConfigAddInput(xstrdup(name), isCore);
dmxInput->freename = TRUE;
dmxLogInput(dmxInput, "Attaching new console input\n");
return dmxInputAttachNew(dmxInput, id);
}
int
dmxInputAttachBackend(int physicalScreen, int isCore, int *id)
{
DMXInputInfo *dmxInput;
DMXScreenInfo *dmxScreen;
int i;
if (physicalScreen < 0 || physicalScreen >= dmxNumScreens)
return BadValue;
for (i = 0; i < dmxNumInputs; i++) {
dmxInput = &dmxInputs[i];
if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) {
/* Found match */
if (!dmxInput->detached)
return BadAccess; /* Already attached */
dmxScreen = &dmxScreens[physicalScreen];
if (!dmxScreen->beDisplay)
return BadAccess; /* Screen detached */
dmxLogInput(dmxInput, "Reattaching detached backend input\n");
return dmxInputAttachOld(dmxInput, id);
}
}
/* No match found */
dmxScreen = &dmxScreens[physicalScreen];
if (!dmxScreen->beDisplay)
return BadAccess; /* Screen detached */
dmxInput = dmxConfigAddInput(dmxScreen->name, isCore);
dmxLogInput(dmxInput, "Attaching new backend input\n");
return dmxInputAttachNew(dmxInput, id);
}