diff options
Diffstat (limited to 'lib/tty/x11conn.c')
-rw-r--r-- | lib/tty/x11conn.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/lib/tty/x11conn.c b/lib/tty/x11conn.c new file mode 100644 index 0000000..20e201b --- /dev/null +++ b/lib/tty/x11conn.c @@ -0,0 +1,266 @@ +/* + X11 support for the Midnight Commander. + + Copyright (C) 2005-2023 + Free Software Foundation, Inc. + + Written by: + Roland Illig <roland.illig@gmx.de>, 2005. + + This file is part of the Midnight Commander. + + The Midnight Commander 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 3 of the License, + or (at your option) any later version. + + The Midnight Commander 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, see <http://www.gnu.org/licenses/>. + */ + +/** \file x11conn.c + * \brief Source: X11 support + * \warning This code uses setjmp() and longjmp(). Before you modify _anything_ here, + * please read the relevant sections of the C standard. + */ + +#include <config.h> + +#include <setjmp.h> +#include <X11/Xlib.h> +#ifdef HAVE_GMODULE +#include <gmodule.h> +#endif + +#include "lib/global.h" +#include "x11conn.h" + +/*** global variables ****************************************************************************/ + +/*** file scope macro definitions ****************************************************************/ + +#ifndef HAVE_GMODULE +#define func_XOpenDisplay XOpenDisplay +#define func_XCloseDisplay XCloseDisplay +#define func_XSetErrorHandler XSetErrorHandler +#define func_XSetIOErrorHandler XSetIOErrorHandler +#define func_XQueryPointer XQueryPointer +#endif + +/*** file scope type declarations ****************************************************************/ + +typedef int (*mc_XErrorHandler_callback) (Display *, XErrorEvent *); +typedef int (*mc_XIOErrorHandler_callback) (Display *); + +/*** forward declarations (file scope functions) *************************************************/ + +/*** 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; +#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 scope 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; + (void) func_XCloseDisplay (dpy); + 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"); + x11_module = g_module_open (x11_module_fname, G_MODULE_BIND_LAZY); + if (x11_module == NULL) + x11_module = g_module_open ("libX11.so.6", 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) +{ + if (x11_available ()) + { + if (setjmp (x11_exception) == 0) + { + Display *retval; + + /* cppcheck-suppress redundantAssignment */ + longjmp_allowed = TRUE; + + retval = func_XOpenDisplay (displayname); + + /* cppcheck-suppress redundantAssignment */ + longjmp_allowed = FALSE; + return retval; + } + } + return NULL; +} + +/* --------------------------------------------------------------------------------------------- */ + +int +mc_XCloseDisplay (Display * display) +{ + if (x11_available ()) + { + if (setjmp (x11_exception) == 0) + { + int retval; + + /* cppcheck-suppress redundantAssignment */ + longjmp_allowed = TRUE; + + retval = func_XCloseDisplay (display); + + /* cppcheck-suppress redundantAssignment */ + 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) + { + /* cppcheck-suppress redundantAssignment */ + 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); + + /* cppcheck-suppress redundantAssignment */ + 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; +} + +/* --------------------------------------------------------------------------------------------- */ |