diff --git a/src/ChangeLog b/src/ChangeLog index 65f65e678..df39c5c4c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2005-03-10 Roland Illig + + * x11conn.c: Separated X11 connection handling from key.c. Added + error handling for X11 errors and connection errors. + * x11conn.h: The interface for x11conn.h. + * key.c: Now using the x11conn code. + * Makefile.am: Added x11conn.{h,c}. + 2005-02-26 Miguel de Icaza * screen.c (chdir_other_panel): Restored original functionality. diff --git a/src/Makefile.am b/src/Makefile.am index 9ccd0ed5b..f3fcd0f6b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -59,7 +59,8 @@ SRCS = achown.c achown.h background.c background.h boxes.c boxes.h \ slint.c subshell.c subshell.h textconf.c textconf.h \ tree.c tree.h treestore.c treestore.h tty.h user.c user.h \ util.c util.h utilunix.c view.c view.h vfsdummy.h widget.c \ - widget.h win.c win.h wtools.c wtools.h unixcompat.h + widget.h win.c win.h wtools.c wtools.h unixcompat.h \ + x11conn.h x11conn.c if CHARSET mc_SOURCES = $(SRCS) $(CHARSET_SRC) diff --git a/src/key.c b/src/key.c index e74fada3a..f518b44e7 100644 --- a/src/key.c +++ b/src/key.c @@ -45,10 +45,7 @@ #endif #ifdef HAVE_TEXTMODE_X11_SUPPORT -#ifdef HAVE_GMODULE -#include -#endif /* HAVE_GMODULE */ -#include +# include "x11conn.h" #endif #ifdef __linux__ @@ -406,52 +403,16 @@ define_sequences (key_define_t *kd) #ifdef HAVE_TEXTMODE_X11_SUPPORT -#ifdef HAVE_GMODULE -static int (*func_XCloseDisplay) (Display *); -static Bool (*func_XQueryPointer) (Display *, Window, Window *, Window *, - int *, int *, int *, int *, - unsigned int *); - -static GModule *x11_module; -#endif /* HAVE_GMODULE */ - static Display *x11_display; static Window x11_window; static void init_key_x11 (void) { -#ifdef HAVE_GMODULE - static Display *(*func_XOpenDisplay) (_Xconst char *); - gchar *x11_module_fname; -#endif /* HAVE_GMODULE */ - if (!getenv ("DISPLAY")) return; -#ifdef HAVE_GMODULE - x11_module_fname = g_module_build_path (NULL, "X11"); - - if (!x11_module_fname) - return; - - x11_module = g_module_open (x11_module_fname, G_MODULE_BIND_LAZY); - g_free (x11_module_fname); - - if (!x11_module) - return; - - if (g_module_symbol - (x11_module, "XOpenDisplay", (void *) &func_XOpenDisplay) - && g_module_symbol (x11_module, "XCloseDisplay", - (void *) &func_XCloseDisplay) - && g_module_symbol (x11_module, "XQueryPointer", - (void *) &func_XQueryPointer)) { - x11_display = (*func_XOpenDisplay) (0); - } -#else - x11_display = XOpenDisplay (0); -#endif /* HAVE_GMODULE */ + x11_display = mc_XOpenDisplay (0); if (x11_display) x11_window = DefaultRootWindow (x11_display); @@ -1324,13 +1285,8 @@ get_modifier (void) int win_x, win_y; unsigned int mask; -#ifdef HAVE_GMODULE - (*func_XQueryPointer) (x11_display, x11_window, &root, &child, - &root_x, &root_y, &win_x, &win_y, &mask); -#else - XQueryPointer (x11_display, x11_window, &root, &child, &root_x, + mc_XQueryPointer (x11_display, x11_window, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask); -#endif /* HAVE_GMODULE */ if (mask & ShiftMask) result |= KEY_M_SHIFT; @@ -1440,14 +1396,7 @@ void done_key () s_dispose (select_list); #ifdef HAVE_TEXTMODE_X11_SUPPORT -#ifdef HAVE_GMODULE if (x11_display) - (*func_XCloseDisplay) (x11_display); - if (x11_module) - g_module_close (x11_module); -#else - if (x11_display) - XCloseDisplay (x11_display); -#endif /* HAVE_GMODULE */ -#endif /* HAVE_TEXTMODE_X11_SUPPORT */ + mc_XCloseDisplay (x11_display); +#endif } diff --git a/src/x11conn.c b/src/x11conn.c new file mode 100644 index 000000000..872d94525 --- /dev/null +++ b/src/x11conn.c @@ -0,0 +1,232 @@ +/* + X11 support for the Midnight Commander. + + Copyright (C) 2005 The Free Software Foundation + + Written by: + Roland Illig , 2005. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + !!! WARNING !!! + + This code uses setjmp() and longjmp(). Before you modify _anything_ + here, please read the relevant sections of the C standard. +*/ + +#include + +#ifndef HAVE_TEXTMODE_X11_SUPPORT +typedef int dummy; /* C99 forbids empty compilation unit */ +#else + +#include + +#include + +#include "../src/global.h" + +#ifdef HAVE_GMODULE +# include +#endif + +#include "x11conn.h" + +/*** file scope type declarations **************************************/ + +typedef int (*mc_XErrorHandler_callback) (Display *, XErrorEvent *); +typedef int (*mc_XIOErrorHandler_callback) (Display *); + +/*** file scope variables **********************************************/ + +#ifdef HAVE_GMODULE + +static Display * (*func_XOpenDisplay) (_Xconst char *); +static int (*func_XCloseDisplay) (Display *); +static mc_XErrorHandler_callback (*func_XSetErrorHandler) + (mc_XErrorHandler_callback); +static mc_XIOErrorHandler_callback (*func_XSetIOErrorHandler) + (mc_XIOErrorHandler_callback); +static Bool (*func_XQueryPointer) (Display *, Window, Window *, Window *, + int *, int *, int *, int *, unsigned int *); + +static GModule *x11_module; + +#else + +#define func_XOpenDisplay XOpenDisplay +#define func_XCloseDisplay XCloseDisplay +#define func_XSetErrorHandler XSetErrorHandler +#define func_XSetIOErrorHandler XSetIOErrorHandler +#define func_XQueryPointer XQueryPointer + +#endif + +static gboolean handlers_installed = FALSE; + +/* This flag is set as soon as an X11 error is reported. Usually that + * means that the DISPLAY is not available anymore. We do not try to + * reconnect, as that would violate the X11 protocol. */ +static gboolean lost_connection = FALSE; + +static jmp_buf x11_exception; /* FIXME: get a better name */ +static gboolean longjmp_allowed = FALSE; + +/*** file private functions ********************************************/ + +static int x_io_error_handler (Display *dpy) +{ + (void) dpy; + + lost_connection = TRUE; + if (longjmp_allowed) { + longjmp_allowed = FALSE; + longjmp(x11_exception, 1); + } + return 0; +} + +static int x_error_handler (Display *dpy, XErrorEvent *ee) +{ + (void) ee; + return x_io_error_handler (dpy); +} + +static void install_error_handlers(void) +{ + if (handlers_installed) return; + + (void) func_XSetErrorHandler (x_error_handler); + (void) func_XSetIOErrorHandler (x_io_error_handler); + handlers_installed = TRUE; +} + +static gboolean x11_available(void) +{ +#ifdef HAVE_GMODULE + gchar *x11_module_fname; + + if (lost_connection) + return FALSE; + + if (x11_module != NULL) + return TRUE; + + x11_module_fname = g_module_build_path (NULL, "X11"); + + if (x11_module_fname == NULL) + return FALSE; + + x11_module = g_module_open (x11_module_fname, G_MODULE_BIND_LAZY); + g_free (x11_module_fname); + + if (x11_module == NULL) + return FALSE; + + if (!g_module_symbol (x11_module, "XOpenDisplay", + (void *) &func_XOpenDisplay)) + goto cleanup; + if (!g_module_symbol (x11_module, "XCloseDisplay", + (void *) &func_XCloseDisplay)) + goto cleanup; + if (!g_module_symbol (x11_module, "XQueryPointer", + (void *) &func_XQueryPointer)) + goto cleanup; + if (!g_module_symbol (x11_module, "XSetErrorHandler", + (void *) &func_XSetErrorHandler)) + goto cleanup; + if (!g_module_symbol (x11_module, "XSetIOErrorHandler", + (void *) &func_XSetIOErrorHandler)) + goto cleanup; + + install_error_handlers(); + return TRUE; + +cleanup: + func_XOpenDisplay = 0; + func_XCloseDisplay = 0; + func_XQueryPointer = 0; + func_XSetErrorHandler = 0; + func_XSetIOErrorHandler = 0; + g_module_close (x11_module); + x11_module = NULL; + return FALSE; +#else + install_error_handlers(); + return !(lost_connection); +#endif +} + +/*** public functions **************************************************/ + +Display *mc_XOpenDisplay (const char *displayname) +{ + Display *retval; + + if (x11_available()) { + if (setjmp(x11_exception) == 0) { + longjmp_allowed = TRUE; + retval = func_XOpenDisplay (displayname); + longjmp_allowed = FALSE; + return retval; + } + } + return NULL; +} + +int mc_XCloseDisplay (Display *display) +{ + int retval; + + if (x11_available()) { + if (setjmp(x11_exception) == 0) { + longjmp_allowed = TRUE; + retval = func_XCloseDisplay (display); + longjmp_allowed = FALSE; + return retval; + } + } + return 0; +} + +Bool mc_XQueryPointer (Display *display, Window win, Window *root_return, + Window *child_return, int *root_x_return, int *root_y_return, + int *win_x_return, int *win_y_return, unsigned int *mask_return) +{ + Bool retval; + + if (x11_available()) { + if (setjmp(x11_exception) == 0) { + longjmp_allowed = TRUE; + retval = func_XQueryPointer (display, win, root_return, + child_return, root_x_return, root_y_return, + win_x_return, win_y_return, mask_return); + longjmp_allowed = FALSE; + return retval; + } + } + *root_return = None; + *child_return = None; + *root_x_return = 0; + *root_y_return = 0; + *win_x_return = 0; + *win_y_return = 0; + *mask_return = 0; + return False; +} + +#endif /* HAVE_TEXTMODE_X11_SUPPORT */ diff --git a/src/x11conn.h b/src/x11conn.h new file mode 100644 index 000000000..01be52925 --- /dev/null +++ b/src/x11conn.h @@ -0,0 +1,21 @@ +#ifndef MC_X11CONN_H +#define MC_X11CONN_H + +/* + This module provides support for some X11 functions. The functions + are loaded dynamically if GModule is available, and statically if + not. X11 session handling is somewhat robust. If there is an X11 + error or a connection error, all further traffic to the X server + will be suppressed, and the functions will return reasonable default + values. +*/ + +#include + +extern Display *mc_XOpenDisplay (const char *); +extern int mc_XCloseDisplay (Display *); + +extern Bool mc_XQueryPointer (Display *, Window, Window *, Window *, + int *, int *, int *, int *, unsigned int *); + +#endif