xserver-multidpi/hw/xfree86/common/xf86Events.c

1158 lines
28 KiB
C
Raw Normal View History

2003-11-14 16:54:54 +01:00
/*
* Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Thomas Roell not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Thomas Roell makes no representations
* about the suitability of this software for any purpose. It is provided
* "as is" without express or implied warranty.
*
* THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
*/
/*
* Copyright (c) 1994-2003 by The XFree86 Project, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
*
* Except as contained in this notice, the name of the copyright holder(s)
* and author(s) shall not be used in advertising or otherwise to promote
* the sale, use or other dealings in this Software without prior written
* authorization from the copyright holder(s) and author(s).
*/
2003-11-14 16:54:54 +01:00
/* [JCH-96/01/21] Extended std reverse map to four buttons. */
#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif
#ifdef __UNIXOS2__
#define I_NEED_OS2_H
#endif
#include <X11/X.h>
#include <X11/Xpoll.h>
#include <X11/Xproto.h>
#include "misc.h"
2003-11-14 16:54:54 +01:00
#include "compiler.h"
2003-11-14 17:49:22 +01:00
#include "xf86.h"
#include "xf86Priv.h"
#define XF86_OS_PRIVS
2003-11-14 16:54:54 +01:00
#include "xf86_OSlib.h"
#include "atKeynames.h"
#ifdef XFreeXDGA
2003-11-14 17:49:22 +01:00
#include "dgaproc.h"
2003-11-14 16:54:54 +01:00
#endif
#ifdef XINPUT
#include <X11/extensions/XI.h>
#include <X11/extensions/XIproto.h>
2003-11-14 17:49:22 +01:00
#else
#include "inputstr.h"
2003-11-14 16:54:54 +01:00
#endif
2003-11-14 17:49:22 +01:00
#include "xf86Xinput.h"
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
#include "mi.h"
2003-11-14 16:54:54 +01:00
#include "mipointer.h"
2003-11-14 17:49:22 +01:00
#ifdef XF86BIGFONT
#define _XF86BIGFONT_SERVER_
#include <X11/extensions/xf86bigfont.h>
2003-11-14 16:54:54 +01:00
#endif
#ifdef XKB
extern Bool noXkbExtension;
#endif
#ifdef DPMSExtension
#define DPMS_SERVER
#include <X11/extensions/dpms.h>
#include "dpmsproc.h"
#endif
2003-11-14 16:54:54 +01:00
#define XE_POINTER 1
#define XE_KEYBOARD 2
#define EqEnqueue(pDev, ev) { \
2003-11-14 17:49:22 +01:00
int __sigstate = xf86BlockSIGIO (); \
mieqEnqueue (pDev, ev); \
2003-11-14 17:49:22 +01:00
xf86UnblockSIGIO(__sigstate); \
}
2003-11-14 16:54:54 +01:00
/*
2003-11-14 17:49:22 +01:00
* The first of many hacks to get VT switching to work under
2003-11-14 16:54:54 +01:00
* Solaris 2.1 for x86. The basic problem is that Solaris is supposed
* to be SVR4. It is for the most part, except where the video interface
* is concerned. These hacks work around those problems.
2003-11-14 17:49:22 +01:00
* See the comments for Linux, and SCO.
2003-11-14 16:54:54 +01:00
*
2003-11-14 17:49:22 +01:00
* This is a toggling variable:
2003-11-14 16:54:54 +01:00
* FALSE = No VT switching keys have been pressed last time around
* TRUE = Possible VT switch Pending
* (DWH - 12/2/93)
*
* This has been generalised to work with Linux and *BSD+syscons (DHD)
*/
#ifdef USE_VT_SYSREQ
2003-11-14 17:49:22 +01:00
Bool VTSysreqToggle = FALSE;
2003-11-14 16:54:54 +01:00
#endif /* !USE_VT_SYSREQ */
2003-11-14 17:49:22 +01:00
Bool VTSwitchEnabled = TRUE; /* Allows run-time disabling for
*BSD and for avoiding VT
switches when using the DRI
automatic full screen mode.*/
2003-11-14 16:54:54 +01:00
extern fd_set EnabledDevices;
#ifdef XF86PM
2003-11-14 17:49:22 +01:00
extern void (*xf86OSPMClose)(void);
#endif
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
static void xf86VTSwitch(void);
2003-11-14 16:54:54 +01:00
/*
2003-11-14 17:49:22 +01:00
* Allow arbitrary drivers or other XFree86 code to register with our main
* Wakeup handler.
2003-11-14 16:54:54 +01:00
*/
2003-11-14 17:49:22 +01:00
typedef struct x_IHRec {
int fd;
InputHandlerProc ihproc;
pointer data;
Bool enabled;
struct x_IHRec * next;
} IHRec, *IHPtr;
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
static IHPtr InputHandlers = NULL;
2003-11-14 16:54:54 +01:00
Bool
LegalModifier(unsigned int key, DeviceIntPtr pDev)
{
return TRUE;
}
2003-11-14 16:54:54 +01:00
/*
* TimeSinceLastInputEvent --
2003-11-14 17:49:22 +01:00
* Function used for screensaver purposes by the os module. Returns the
2003-11-14 16:54:54 +01:00
* time in milliseconds since there last was any input.
*/
int
TimeSinceLastInputEvent()
{
if (xf86Info.lastEventTime == 0) {
xf86Info.lastEventTime = GetTimeInMillis();
}
return GetTimeInMillis() - xf86Info.lastEventTime;
}
/*
* SetTimeSinceLastInputEvent --
* Set the lastEventTime to now.
*/
_X_EXPORT void
2003-11-14 16:54:54 +01:00
SetTimeSinceLastInputEvent()
{
xf86Info.lastEventTime = GetTimeInMillis();
}
/*
* ProcessInputEvents --
* Retrieve all waiting input events and pass them to DIX in their
* correct chronological order. Only reads from the system pointer
* and keyboard.
*/
void
ProcessInputEvents ()
{
int x, y;
#ifdef INHERIT_LOCK_STATE
static int generation = 0;
#endif
/*
* With INHERIT_LOCK_STATE defined, the initial state of CapsLock, NumLock
* and ScrollLock will be set to match that of the VT the server is
* running on.
*/
#ifdef INHERIT_LOCK_STATE
if (generation != serverGeneration) {
xEvent kevent;
DevicePtr pKeyboard = xf86Info.pKeyboard;
extern unsigned int xf86InitialCaps, xf86InitialNum, xf86InitialScroll;
generation = serverGeneration;
kevent.u.keyButtonPointer.time = GetTimeInMillis();
kevent.u.keyButtonPointer.rootX = 0;
kevent.u.keyButtonPointer.rootY = 0;
kevent.u.u.type = KeyPress;
if (xf86InitialCaps) {
kevent.u.u.detail = xf86InitialCaps;
(* pKeyboard->processInputProc)(&kevent, (DeviceIntPtr)pKeyboard, 1);
xf86InitialCaps = 0;
}
if (xf86InitialNum) {
kevent.u.u.detail = xf86InitialNum;
(* pKeyboard->processInputProc)(&kevent, (DeviceIntPtr)pKeyboard, 1);
xf86InitialNum = 0;
}
if (xf86InitialScroll) {
kevent.u.u.detail = xf86InitialScroll;
(* pKeyboard->processInputProc)(&kevent, (DeviceIntPtr)pKeyboard, 1);
xf86InitialScroll = 0;
}
}
#endif
xf86Info.inputPending = FALSE;
mieqProcessInputEvents();
miPointerUpdateSprite(inputInfo.pointer);
2003-11-14 16:54:54 +01:00
miPointerGetPosition(inputInfo.pointer, &x, &y);
2003-11-14 16:54:54 +01:00
xf86SetViewport(xf86Info.currentScreen, x, y);
}
2003-11-14 17:49:22 +01:00
void
xf86GrabServerCallback(CallbackListPtr *callbacks, pointer data, pointer args)
{
ServerGrabInfoRec *grab = (ServerGrabInfoRec*)args;
xf86Info.grabInfo.server.client = grab->client;
xf86Info.grabInfo.server.grabstate = grab->grabstate;
}
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
/*
* Handle keyboard events that cause some kind of "action"
* (i.e., server termination, video mode changes, VT switches, etc.)
*/
void
xf86ProcessActionEvent(ActionEvent action, void *arg)
{
#ifdef DEBUG
ErrorF("ProcessActionEvent(%d,%x)\n", (int) action, arg);
#endif
switch (action) {
case ACTION_TERMINATE:
if (!xf86Info.dontZap) {
#ifdef XFreeXDGA
DGAShutdown();
#endif
GiveUp(0);
}
break;
case ACTION_NEXT_MODE:
if (!xf86Info.dontZoom)
xf86ZoomViewport(xf86Info.currentScreen, 1);
break;
case ACTION_PREV_MODE:
if (!xf86Info.dontZoom)
xf86ZoomViewport(xf86Info.currentScreen, -1);
break;
case ACTION_DISABLEGRAB:
if (!xf86Info.grabInfo.disabled && xf86Info.grabInfo.allowDeactivate) {
if (inputInfo.pointer && inputInfo.pointer->grab != NULL &&
inputInfo.pointer->DeactivateGrab)
inputInfo.pointer->DeactivateGrab(inputInfo.pointer);
if (inputInfo.keyboard && inputInfo.keyboard->grab != NULL &&
inputInfo.keyboard->DeactivateGrab)
inputInfo.keyboard->DeactivateGrab(inputInfo.keyboard);
}
break;
case ACTION_CLOSECLIENT:
if (!xf86Info.grabInfo.disabled && xf86Info.grabInfo.allowClosedown) {
ClientPtr pointer, keyboard, server;
pointer = keyboard = server = NULL;
if (inputInfo.pointer && inputInfo.pointer->grab != NULL)
pointer = clients[CLIENT_ID(inputInfo.pointer->grab->resource)];
if (inputInfo.keyboard && inputInfo.keyboard->grab != NULL) {
keyboard = clients[CLIENT_ID(inputInfo.keyboard->grab->resource)];
if (keyboard == pointer)
keyboard = NULL;
}
if ((xf86Info.grabInfo.server.grabstate == SERVER_GRABBED) &&
(((server = xf86Info.grabInfo.server.client) == pointer) ||
(server == keyboard)))
server = NULL;
if (pointer)
CloseDownClient(pointer);
if (keyboard)
CloseDownClient(keyboard);
if (server)
CloseDownClient(server);
}
break;
#if !defined(__SOL8__) && !defined(__UNIXOS2__) && !defined(sgi) && \
2003-12-04 23:03:38 +01:00
(!defined(sun) || defined(i386)) && defined(VT_ACTIVATE)
2003-11-14 17:49:22 +01:00
case ACTION_SWITCHSCREEN:
if (VTSwitchEnabled && !xf86Info.dontVTSwitch && arg) {
int vtno = *((int *) arg);
#if defined(__SCO__) || defined(__UNIXWARE__)
vtno--;
#endif
2003-11-14 17:49:22 +01:00
#if defined(QNX4)
xf86Info.vtRequestsPending = vtno;
#else
if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, vtno) < 0)
ErrorF("Failed to switch consoles (%s)\n", strerror(errno));
#endif
}
break;
case ACTION_SWITCHSCREEN_NEXT:
if (VTSwitchEnabled && !xf86Info.dontVTSwitch) {
/* Shouldn't this be true for (sun) && (i386) && (SVR4) ? */
#if defined(__SCO__) || defined(__UNIXWARE__)
if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, xf86Info.vtno) < 0)
#else
2003-11-14 17:49:22 +01:00
if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, xf86Info.vtno + 1) < 0)
#endif
#if defined (__SCO__) || (defined(sun) && defined (i386) && defined (SVR4)) || defined(__UNIXWARE__)
2003-11-14 17:49:22 +01:00
if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, 0) < 0)
#else
if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, 1) < 0)
#endif
ErrorF("Failed to switch consoles (%s)\n", strerror(errno));
}
break;
case ACTION_SWITCHSCREEN_PREV:
if (VTSwitchEnabled && !xf86Info.dontVTSwitch && xf86Info.vtno > 0) {
2003-11-14 17:49:22 +01:00
if (ioctl(xf86Info.consoleFd, VT_ACTIVATE, xf86Info.vtno - 1) < 0)
ErrorF("Failed to switch consoles (%s)\n", strerror(errno));
}
break;
#endif
case ACTION_MESSAGE:
{
char *retstr, *message = (char *) arg;
ScrnInfoPtr pScr = XF86SCRNINFO(xf86Info.currentScreen);
#ifdef DEBUG
ErrorF("ActionMessage: '%s'\n", message);
#endif
/* Okay the message made it to the ddx. The common layer */
/* can check for relevant messages here and react to any */
/* that have a global effect. For example: */
/* */
/* if (!strcmp(message, "foo") { */
/* do_foo(); break */
/* } */
/* */
/* otherwise fallback to sending a key event message to */
/* the current screen's driver: */
2004-04-23 21:54:30 +02:00
if (*pScr->HandleMessage != NULL) {
(void) (*pScr->HandleMessage)(pScr->scrnIndex,
"KeyEventMessage", message, &retstr);
}
}
break;
2003-11-14 17:49:22 +01:00
default:
break;
}
}
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
#define ModifierIsSet(k) ((modifiers & (k)) == (k))
2003-11-14 16:54:54 +01:00
_X_EXPORT Bool
2003-11-14 17:49:22 +01:00
xf86CommonSpecialKey(int key, Bool down, int modifiers)
2003-11-14 16:54:54 +01:00
{
if ((!ModifierIsSet(ShiftMask)) &&
(((ModifierIsSet(ControlMask | AltMask)) ||
(ModifierIsSet(ControlMask | AltLangMask))))) {
2003-11-14 17:49:22 +01:00
switch (key) {
case KEY_BackSpace:
xf86ProcessActionEvent(ACTION_TERMINATE, NULL);
break;
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
/*
* Check grabs
*/
case KEY_KP_Divide:
xf86ProcessActionEvent(ACTION_DISABLEGRAB, NULL);
break;
case KEY_KP_Multiply:
xf86ProcessActionEvent(ACTION_CLOSECLIENT, NULL);
break;
/*
* The idea here is to pass the scancode down to a list of
* registered routines. There should be some standard conventions
* for processing certain keys.
*/
case KEY_KP_Minus: /* Keypad - */
if (down) xf86ProcessActionEvent(ACTION_PREV_MODE, NULL);
if (!xf86Info.dontZoom) return TRUE;
break;
case KEY_KP_Plus: /* Keypad + */
if (down) xf86ProcessActionEvent(ACTION_NEXT_MODE, NULL);
if (!xf86Info.dontZoom) return TRUE;
break;
}
}
return FALSE;
2003-11-14 16:54:54 +01:00
}
2003-11-14 17:49:22 +01:00
/*
* xf86Wakeup --
* Os wakeup handler.
2003-11-14 16:54:54 +01:00
*/
2003-11-14 17:49:22 +01:00
/* ARGSUSED */
2003-11-14 16:54:54 +01:00
void
2003-11-14 17:49:22 +01:00
xf86Wakeup(pointer blockData, int err, pointer pReadmask)
2003-11-14 16:54:54 +01:00
{
2003-11-14 17:49:22 +01:00
#if !defined(__UNIXOS2__) && !defined(__QNX__)
fd_set* LastSelectMask = (fd_set*)pReadmask;
fd_set devicesWithInput;
InputInfoPtr pInfo;
if (err >= 0) {
XFD_ANDSET(&devicesWithInput, LastSelectMask, &EnabledDevices);
if (XFD_ANYSET(&devicesWithInput)) {
pInfo = xf86InputDevs;
while (pInfo) {
if (pInfo->read_input && pInfo->fd >= 0 &&
(FD_ISSET(pInfo->fd, &devicesWithInput) != 0)) {
2003-11-14 17:49:22 +01:00
int sigstate = xf86BlockSIGIO();
pInfo->read_input(pInfo);
xf86UnblockSIGIO(sigstate);
/*
* Remove the descriptior from the set because more than one
* device may share the same file descriptor.
2003-11-14 17:49:22 +01:00
*/
FD_CLR(pInfo->fd, &devicesWithInput);
2003-11-14 17:49:22 +01:00
}
pInfo = pInfo->next;
}
2003-11-14 16:54:54 +01:00
}
}
2003-11-14 17:49:22 +01:00
#else /* __UNIXOS2__ and __QNX__ */
InputInfoPtr pInfo;
pInfo = xf86InputDevs;
while (pInfo) {
if (pInfo->read_input && pInfo->fd >= 0) {
int sigstate = xf86BlockSIGIO();
pInfo->read_input(pInfo);
xf86UnblockSIGIO(sigstate);
/*
* Must break here because more than one device may share
* the same file descriptor.
*/
break;
}
pInfo = pInfo->next;
2003-11-14 16:54:54 +01:00
}
2003-11-14 17:49:22 +01:00
#endif /* __UNIXOS2__ and __QNX__ */
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
if (err >= 0) { /* we don't want the handlers called if select() */
IHPtr ih; /* returned with an error condition, do we? */
for (ih = InputHandlers; ih; ih = ih->next) {
if (ih->enabled && ih->fd >= 0 && ih->ihproc &&
(FD_ISSET(ih->fd, ((fd_set *)pReadmask)) != 0)) {
ih->ihproc(ih->fd, ih->data);
2003-11-14 16:54:54 +01:00
}
}
}
2003-11-14 17:49:22 +01:00
if (xf86VTSwitchPending()) xf86VTSwitch();
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
if (xf86Info.inputPending) ProcessInputEvents();
}
2003-11-14 16:54:54 +01:00
/*
2003-11-14 17:49:22 +01:00
* xf86SigioReadInput --
* signal handler for the SIGIO signal.
2003-11-14 16:54:54 +01:00
*/
2003-11-14 17:49:22 +01:00
static void
xf86SigioReadInput(int fd,
void *closure)
2003-11-14 16:54:54 +01:00
{
2003-11-14 17:49:22 +01:00
int sigstate = xf86BlockSIGIO();
InputInfoPtr pInfo = (InputInfoPtr) closure;
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
pInfo->read_input(pInfo);
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
xf86UnblockSIGIO(sigstate);
}
2003-11-14 16:54:54 +01:00
/*
2003-11-14 17:49:22 +01:00
* xf86AddEnabledDevice --
*
2003-11-14 16:54:54 +01:00
*/
_X_EXPORT void
2003-11-14 17:49:22 +01:00
xf86AddEnabledDevice(InputInfoPtr pInfo)
2003-11-14 16:54:54 +01:00
{
2003-11-14 17:49:22 +01:00
if (!xf86InstallSIGIOHandler (pInfo->fd, xf86SigioReadInput, pInfo)) {
AddEnabledDevice(pInfo->fd);
}
}
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
/*
* xf86RemoveEnabledDevice --
*
*/
_X_EXPORT void
2003-11-14 17:49:22 +01:00
xf86RemoveEnabledDevice(InputInfoPtr pInfo)
{
if (!xf86RemoveSIGIOHandler (pInfo->fd)) {
RemoveEnabledDevice(pInfo->fd);
}
2003-11-14 16:54:54 +01:00
}
2003-11-14 17:49:22 +01:00
static int *xf86SignalIntercept = NULL;
2003-11-14 16:54:54 +01:00
_X_EXPORT void
2003-11-14 17:49:22 +01:00
xf86InterceptSignals(int *signo)
{
if ((xf86SignalIntercept = signo))
*signo = -1;
}
2003-11-14 16:54:54 +01:00
static void (*xf86SigIllHandler)(void) = NULL;
_X_EXPORT void
xf86InterceptSigIll(void (*sigillhandler)(void))
{
xf86SigIllHandler = sigillhandler;
}
#ifdef HAVE_BACKTRACE
#include <execinfo.h>
2005-07-03 05:28:27 +02:00
static __inline__ void xorg_backtrace(void)
{
void *array[32]; /* deeper nesting than this means something's wrong */
size_t size, i;
char **strings;
ErrorF("\nBacktrace:\n");
size = backtrace(array, 32);
strings = backtrace_symbols(array, size);
for (i = 0; i < size; i++)
ErrorF("%d: %s\n", i, strings[i]);
free(strings);
}
#else /* not glibc or glibc < 2.1 */
# if defined(sun) && defined(__SVR4)
# define HAVE_PSTACK
# endif
# if defined(HAVE_WALKCONTEXT) /* Solaris 9 & later */
# include <ucontext.h>
# include <signal.h>
# include <dlfcn.h>
# include <sys/elf.h>
#ifdef _LP64
# define ElfSym Elf64_Sym
#else
# define ElfSym Elf32_Sym
#endif
/* Called for each frame on the stack to print it's contents */
static int xorg_backtrace_frame(uintptr_t pc, int signo, void *arg)
{
Dl_info dlinfo;
ElfSym *dlsym;
char header[32];
int depth = *((int *) arg);
if (signo) {
char signame[SIG2STR_MAX];
if (sig2str(signo, signame) != 0) {
strcpy(signame, "unknown");
}
ErrorF("** Signal %d (%s)\n", signo, signame);
}
snprintf(header, sizeof(header), "%d: 0x%lx", depth, pc);
*((int *) arg) = depth + 1;
/* Ask system dynamic loader for info on the address */
if (dladdr1((void *) pc, &dlinfo, (void **) &dlsym, RTLD_DL_SYMENT)) {
unsigned long offset = pc - (uintptr_t) dlinfo.dli_saddr;
const char *symname;
if (offset < dlsym->st_size) { /* inside a function */
symname = dlinfo.dli_sname;
} else { /* found which file it was in, but not which function */
symname = "<section start>";
offset = pc - (uintptr_t)dlinfo.dli_fbase;
}
ErrorF("%s: %s:%s+0x%lx\n", header, dlinfo.dli_fname,
symname, offset);
} else {
/* Couldn't find symbol info from system dynamic loader, should
* probably poke elfloader here, but haven't written that code yet,
* so we just print the pc.
*/
ErrorF("%s\n", header);
}
return 0;
}
# endif /* HAVE_WALKCONTEXT */
# ifdef HAVE_PSTACK
static int xorg_backtrace_pstack(void) {
pid_t kidpid;
int pipefd[2];
if (pipe(pipefd) != 0) {
return -1;
}
kidpid = fork1();
if (kidpid == -1) {
/* ERROR */
return -1;
} else if (kidpid == 0) {
/* CHILD */
char parent[16];
seteuid(0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
dup2(pipefd[1],STDOUT_FILENO);
closefrom(STDERR_FILENO);
snprintf(parent, sizeof(parent), "%d", getppid());
execle("/usr/bin/pstack", "pstack", parent, NULL);
exit(1);
} else {
/* PARENT */
char btline[256];
int kidstat;
int bytesread;
int done = 0;
close(pipefd[1]);
while (!done) {
bytesread = read(pipefd[0], btline, sizeof(btline) - 1);
if (bytesread > 0) {
btline[bytesread] = 0;
ErrorF("%s", btline);
}
else if ((bytesread < 0) ||
((errno != EINTR) && (errno != EAGAIN)))
done = 1;
}
close(pipefd[0]);
waitpid(kidpid, &kidstat, 0);
if (kidstat != 0)
return -1;
}
return 0;
}
# endif /* HAVE_PSTACK */
# if defined(HAVE_PSTACK) || defined(HAVE_WALKCONTEXT)
static __inline__ void xorg_backtrace(void) {
ErrorF("\nBacktrace:\n");
# ifdef HAVE_PSTACK
/* First try fork/exec of pstack - otherwise fall back to walkcontext
pstack is preferred since it can print names of non-exported functions */
if (xorg_backtrace_pstack() < 0)
# endif
{
# ifdef HAVE_WALKCONTEXT
ucontext_t u;
int depth = 1;
if (getcontext(&u) == 0)
walkcontext(&u, xorg_backtrace_frame, &depth);
else
# endif
Error("Failed to get backtrace info");
}
ErrorF("\n");
}
# else
/* Default fallback if we can't find any way to get a backtrace */
2005-07-03 05:28:27 +02:00
static __inline__ void xorg_backtrace(void) { return; }
# endif
#endif
2003-11-14 16:54:54 +01:00
/*
* xf86SigHandler --
2003-11-14 17:49:22 +01:00
* Catch unexpected signals and exit or continue cleanly.
2003-11-14 16:54:54 +01:00
*/
void
2003-11-14 17:49:22 +01:00
xf86SigHandler(int signo)
2003-11-14 16:54:54 +01:00
{
if ((signo == SIGILL) && xf86SigIllHandler) {
(*xf86SigIllHandler)();
/* Re-arm handler just in case we unexpectedly return here */
(void) signal(signo, xf86SigHandler);
return;
}
2003-11-14 17:49:22 +01:00
if (xf86SignalIntercept && (*xf86SignalIntercept < 0)) {
*xf86SignalIntercept = signo;
2003-11-14 17:49:22 +01:00
/* Re-arm handler just in case */
(void) signal(signo, xf86SigHandler);
return;
}
2003-11-14 16:54:54 +01:00
signal(signo,SIG_IGN);
xf86Info.caughtSignal = TRUE;
2003-11-14 17:49:22 +01:00
#ifdef XF86BIGFONT
XF86BigfontCleanup();
#endif
xorg_backtrace();
2003-11-14 16:54:54 +01:00
FatalError("Caught signal %d. Server aborting\n", signo);
}
2003-11-14 17:49:22 +01:00
#ifdef MEMDEBUG
void
xf86SigMemDebug(int signo)
{
CheckMemory();
(void) signal(signo, xf86SigMemDebug);
return;
}
#endif
static void
xf86ReleaseKeys(DeviceIntPtr pDev)
{
KeyClassPtr keyc = NULL;
KeySym *map = NULL;
xEvent ke;
int i = 0, j = 0, nevents = 0;
ErrorF("releasekeys: called on device %s (%d)\n", pDev->name, pDev->id);
if (!pDev || !pDev->key)
return;
keyc = pDev->key;
map = keyc->curKeySyms.map;
/*
* Hmm... here is the biggest hack of every time !
* It may be possible that a switch-vt procedure has finished BEFORE
* you released all keys neccessary to do this. That peculiar behavior
* can fool the X-server pretty much, cause it assumes that some keys
* were not released. TWM may stuck alsmost completly....
* OK, what we are doing here is after returning from the vt-switch
* exeplicitely unrelease all keyboard keys before the input-devices
* are reenabled.
*/
for (i = keyc->curKeySyms.minKeyCode, map = keyc->curKeySyms.map;
i < keyc->curKeySyms.maxKeyCode;
i++, map += keyc->curKeySyms.mapWidth) {
if (KeyPressed(i)) {
switch (*map) {
/* Don't release the lock keys */
case XK_Caps_Lock:
case XK_Shift_Lock:
case XK_Num_Lock:
case XK_Scroll_Lock:
case XK_Kana_Lock:
break;
default:
if (pDev == inputInfo.keyboard) {
ke.u.keyButtonPointer.time = GetTimeInMillis();
ke.u.keyButtonPointer.rootX = 0;
ke.u.keyButtonPointer.rootY = 0;
ke.u.u.type = KeyRelease;
ke.u.u.detail = i;
(*pDev->public.processInputProc) (&ke, pDev, 1);
}
else {
nevents = GetKeyboardEvents(xf86Events, pDev, KeyRelease, i);
for (j = 0; j < nevents; j++)
EqEnqueue(pDev, xf86Events + i);
}
break;
}
}
}
}
2003-11-14 16:54:54 +01:00
/*
* xf86VTSwitch --
* Handle requests for switching the vt.
*/
static void
xf86VTSwitch()
{
2003-11-14 17:49:22 +01:00
int i, prevSIGIO;
InputInfoPtr pInfo;
IHPtr ih;
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
#ifdef DEBUG
ErrorF("xf86VTSwitch()\n");
#endif
2003-11-14 16:54:54 +01:00
#ifdef XFreeXDGA
2003-11-14 17:49:22 +01:00
if(!DGAVTSwitch())
return;
#endif
2003-11-14 16:54:54 +01:00
/*
2003-11-14 17:49:22 +01:00
* Since all screens are currently all in the same state it is sufficient
* check the first. This might change in future.
2003-11-14 16:54:54 +01:00
*/
2003-11-14 17:49:22 +01:00
if (xf86Screens[0]->vtSema) {
#ifdef DEBUG
ErrorF("xf86VTSwitch: Leaving, xf86Exiting is %s\n",
BOOLTOSTRING((dispatchException & DE_TERMINATE) ? TRUE : FALSE));
#endif
#ifdef DPMSExtension
if (DPMSPowerLevel != DPMSModeOn)
DPMSSet(DPMSModeOn);
2003-11-14 16:54:54 +01:00
#endif
2003-11-14 17:49:22 +01:00
for (i = 0; i < xf86NumScreens; i++) {
if (!(dispatchException & DE_TERMINATE))
if (xf86Screens[i]->EnableDisableFBAccess)
(*xf86Screens[i]->EnableDisableFBAccess) (i, FALSE);
}
#if !defined(__UNIXOS2__)
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
/*
* Keep the order: Disable Device > LeaveVT
* EnterVT > EnableDevice
*/
pInfo = xf86InputDevs;
while (pInfo) {
DisableDevice(pInfo->dev);
pInfo = pInfo->next;
}
#endif /* !__UNIXOS2__ */
xf86EnterServerState(SETUP);
for (i = 0; i < xf86NumScreens; i++)
xf86Screens[i]->LeaveVT(i, 0);
2003-11-14 17:49:22 +01:00
for (ih = InputHandlers; ih; ih = ih->next)
xf86DisableInputHandler(ih);
xf86AccessLeave(); /* We need this here, otherwise */
xf86AccessLeaveState(); /* console won't be restored */
2003-11-14 16:54:54 +01:00
if (!xf86VTSwitchAway()) {
/*
* switch failed
*/
2003-11-14 17:49:22 +01:00
#ifdef DEBUG
ErrorF("xf86VTSwitch: Leave failed\n");
2003-11-14 16:54:54 +01:00
#endif
2003-11-14 17:49:22 +01:00
prevSIGIO = xf86BlockSIGIO();
xf86AccessEnter();
xf86EnterServerState(SETUP);
for (i = 0; i < xf86NumScreens; i++) {
if (!xf86Screens[i]->EnterVT(i, 0))
FatalError("EnterVT failed for screen %d\n", i);
}
xf86EnterServerState(OPERATING);
if (!(dispatchException & DE_TERMINATE)) {
for (i = 0; i < xf86NumScreens; i++) {
if (xf86Screens[i]->EnableDisableFBAccess)
(*xf86Screens[i]->EnableDisableFBAccess) (i, TRUE);
}
}
SaveScreens(SCREEN_SAVER_FORCER, ScreenSaverReset);
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
#if !defined(__UNIXOS2__)
pInfo = xf86InputDevs;
while (pInfo) {
xf86ReleaseKeys(pInfo->dev);
2003-11-14 17:49:22 +01:00
EnableDevice(pInfo->dev);
pInfo = pInfo->next;
}
/* XXX HACK */
xf86ReleaseKeys(inputInfo.keyboard);
2003-11-14 17:49:22 +01:00
#endif /* !__UNIXOS2__ */
for (ih = InputHandlers; ih; ih = ih->next)
xf86EnableInputHandler(ih);
xf86UnblockSIGIO(prevSIGIO);
2003-11-14 16:54:54 +01:00
} else {
#ifdef XF86PM
2003-11-14 17:49:22 +01:00
if (xf86OSPMClose)
xf86OSPMClose();
xf86OSPMClose = NULL;
#endif
2003-11-14 17:49:22 +01:00
for (i = 0; i < xf86NumScreens; i++) {
/*
* zero all access functions to
* trap calls when switched away.
*/
xf86Screens[i]->vtSema = FALSE;
xf86Screens[i]->access = NULL;
xf86Screens[i]->busAccess = NULL;
}
if (xorgHWAccess)
xf86DisableIO();
2003-11-14 16:54:54 +01:00
}
} else {
2003-11-14 17:49:22 +01:00
#ifdef DEBUG
ErrorF("xf86VTSwitch: Entering\n");
#endif
2003-11-14 16:54:54 +01:00
if (!xf86VTSwitchTo()) return;
2003-11-14 17:49:22 +01:00
prevSIGIO = xf86BlockSIGIO();
#ifdef XF86PM
2003-11-14 17:49:22 +01:00
xf86OSPMClose = xf86OSPMOpen();
#endif
2003-11-14 17:49:22 +01:00
if (xorgHWAccess)
xf86EnableIO();
2003-11-14 17:49:22 +01:00
xf86AccessEnter();
xf86EnterServerState(SETUP);
for (i = 0; i < xf86NumScreens; i++) {
xf86Screens[i]->vtSema = TRUE;
if (!xf86Screens[i]->EnterVT(i, 0))
FatalError("EnterVT failed for screen %d\n", i);
}
xf86EnterServerState(OPERATING);
for (i = 0; i < xf86NumScreens; i++) {
if (xf86Screens[i]->EnableDisableFBAccess)
(*xf86Screens[i]->EnableDisableFBAccess)(i, TRUE);
}
2003-11-14 16:54:54 +01:00
/* Turn screen saver off when switching back */
SaveScreens(SCREEN_SAVER_FORCER,ScreenSaverReset);
2003-11-14 17:49:22 +01:00
#if !defined(__UNIXOS2__)
pInfo = xf86InputDevs;
while (pInfo) {
xf86ReleaseKeys(pInfo->dev);
2003-11-14 17:49:22 +01:00
EnableDevice(pInfo->dev);
pInfo = pInfo->next;
}
/* XXX HACK */
xf86ReleaseKeys(inputInfo.keyboard);
2003-11-14 17:49:22 +01:00
#endif /* !__UNIXOS2__ */
for (ih = InputHandlers; ih; ih = ih->next)
xf86EnableInputHandler(ih);
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
xf86UnblockSIGIO(prevSIGIO);
2003-11-14 16:54:54 +01:00
}
}
2003-11-14 17:49:22 +01:00
/* Input handler registration */
_X_EXPORT pointer
2003-11-14 17:49:22 +01:00
xf86AddInputHandler(int fd, InputHandlerProc proc, pointer data)
{
IHPtr ih;
if (fd < 0 || !proc)
return NULL;
ih = xcalloc(sizeof(*ih), 1);
if (!ih)
return NULL;
ih->fd = fd;
ih->ihproc = proc;
ih->data = data;
ih->enabled = TRUE;
ih->next = InputHandlers;
InputHandlers = ih;
AddEnabledDevice(fd);
return ih;
}
_X_EXPORT int
2003-11-14 17:49:22 +01:00
xf86RemoveInputHandler(pointer handler)
{
IHPtr ih, p;
int fd;
if (!handler)
return -1;
ih = handler;
fd = ih->fd;
if (ih->fd >= 0)
RemoveEnabledDevice(ih->fd);
if (ih == InputHandlers)
InputHandlers = ih->next;
else {
p = InputHandlers;
while (p && p->next != ih)
p = p->next;
if (ih)
p->next = ih->next;
}
xfree(ih);
return fd;
}
_X_EXPORT void
2003-11-14 17:49:22 +01:00
xf86DisableInputHandler(pointer handler)
{
IHPtr ih;
if (!handler)
return;
ih = handler;
ih->enabled = FALSE;
if (ih->fd >= 0)
RemoveEnabledDevice(ih->fd);
}
_X_EXPORT void
2003-11-14 17:49:22 +01:00
xf86EnableInputHandler(pointer handler)
{
IHPtr ih;
if (!handler)
return;
ih = handler;
ih->enabled = TRUE;
if (ih->fd >= 0)
AddEnabledDevice(ih->fd);
}
/*
* As used currently by the DRI, the return value is ignored.
*/
_X_EXPORT Bool
2003-11-14 17:49:22 +01:00
xf86EnableVTSwitch(Bool new)
{
static Bool def = TRUE;
Bool old;
old = VTSwitchEnabled;
if (!new) {
/* Disable VT switching */
def = VTSwitchEnabled;
VTSwitchEnabled = FALSE;
} else {
/* Restore VT switching to default */
VTSwitchEnabled = def;
}
return old;
}
void
xf86ReloadInputDevs(int sig)
{
InputInfoPtr pInfo;
signal(sig, (void(*)(int))xf86ReloadInputDevs);
pInfo = xf86InputDevs;
while (pInfo) {
DisableDevice(pInfo->dev);
EnableDevice(pInfo->dev);
pInfo = pInfo->next;
}
return;
}
2003-11-14 17:49:22 +01:00
#ifdef WSCONS_SUPPORT
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
/* XXX Currently XKB is mandatory. */
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
extern int WSKbdToKeycode(int);
2003-11-14 16:54:54 +01:00
2003-11-14 17:49:22 +01:00
void
xf86PostWSKbdEvent(struct wscons_event *event)
2003-11-14 16:54:54 +01:00
{
2003-11-14 17:49:22 +01:00
int type = event->type;
int value = event->value;
unsigned int keycode;
int blocked;
if (type == WSCONS_EVENT_KEY_UP || type == WSCONS_EVENT_KEY_DOWN) {
Bool down = (type == WSCONS_EVENT_KEY_DOWN ? TRUE : FALSE);
/* map the scancodes to standard XFree86 scancode */
keycode = WSKbdToKeycode(value);
if (!down) keycode |= 0x80;
/* It seems better to block SIGIO there */
blocked = xf86BlockSIGIO();
xf86PostKbdEvent(keycode);
xf86UnblockSIGIO(blocked);
2003-11-14 16:54:54 +01:00
}
}
2003-11-14 17:49:22 +01:00
#endif /* WSCONS_SUPPORT */