From d83b1602178fc9743f5e5e95e06bcbeaf8d23ba6 Mon Sep 17 00:00:00 2001 From: Christophe CURIS Date: Sat, 7 Jun 2014 21:21:55 +0200 Subject: [PATCH] wmix: added error catch for XGrabKey on multimedia keys If another application has already set a grab on these keys then the call would fail (BadAccess) and wmix stop. With the X error handler, we can display a warning to user and continue anyway. Signed-off-by: Christophe CURIS --- wmix/mmkeys.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ wmix/wmix.1x | 4 ++++ 2 files changed, 59 insertions(+) diff --git a/wmix/mmkeys.c b/wmix/mmkeys.c index bc22625..2dae788 100644 --- a/wmix/mmkeys.c +++ b/wmix/mmkeys.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -59,8 +60,19 @@ typedef struct { unsigned int list[1 << lengthof(modifier_symbol)]; } modifier_masks; +/* The structure to track grab installation for errors */ +static struct mmkey_track { + XErrorHandler previous_handler; + struct { + const char *key_name; + unsigned long serial[1 << lengthof(modifier_symbol)]; + Bool displayed; + } request[lengthof(key_list)]; +} *track_install = NULL; + /* Local functions */ static void mmkey_build_modifier_list(Display *display, modifier_masks *result); +static int mmkey_catch_grab_error(Display *display, XErrorEvent *event); /* @@ -73,6 +85,7 @@ static void mmkey_build_modifier_list(Display *display, modifier_masks *result); void mmkey_install(Display *display) { modifier_masks mod_masks; + struct mmkey_track install_info; Window root_window; int i, j; @@ -80,6 +93,9 @@ void mmkey_install(Display *display) root_window = DefaultRootWindow(display); + memset(&install_info, 0, sizeof(install_info)); + install_info.previous_handler = XSetErrorHandler(mmkey_catch_grab_error); + track_install = &install_info; for (i = 0; i < lengthof(key_list); i++) { KeyCode key; @@ -89,13 +105,21 @@ void mmkey_install(Display *display) if (key == None) continue; + install_info.request[i].key_name = key_list[i].name; + install_info.request[i].displayed = False; for (j = 0; j < mod_masks.count; j++) { + install_info.request[i].serial[j] = NextRequest(display); XGrabKey(display, key, mod_masks.list[j], root_window, False, GrabModeAsync, GrabModeAsync); } if (config.verbose) printf("Found multimedia key: %s\n", key_list[i].name); } + + /* The grab may fail, so make sure it is reported now */ + XSync(display, False); + XSetErrorHandler(install_info.previous_handler); + track_install = NULL; } /* @@ -166,3 +190,34 @@ static void mmkey_build_modifier_list(Display *display, modifier_masks *result) } } } + +/* + * Callback when X11 reports an error + * + * We only track errors from XGrabKey and display them to user, instead of + * letting the default error handler exit + */ +static int mmkey_catch_grab_error(Display *display, XErrorEvent *event) +{ + int i, j; + + if ((event->error_code == BadAccess) && (event->request_code == X_GrabKey)) { + for (i = 0; i < lengthof(track_install->request); i++) { + for (j = 0; j < lengthof(track_install->request[i].serial); j++) { + if (track_install->request[i].serial[j] == 0L) + break; + if (event->serial == track_install->request[i].serial[j]) { + if (!track_install->request[i].displayed) { + fprintf(stderr, "wmix:warning: could not grab key %s, is another application using it?\n", + track_install->request[i].key_name); + track_install->request[i].displayed = True; + } + return 0; + } + } + } + } + + /* That's not an XGrabKey known issue, let the default handler manage this */ + return track_install->previous_handler(display, event); +} diff --git a/wmix/wmix.1x b/wmix/wmix.1x index 117f42e..8e4cf68 100644 --- a/wmix/wmix.1x +++ b/wmix/wmix.1x @@ -134,6 +134,10 @@ if you have other application controlling the volume, and possibly implementing mute in similar ways, because there is no way to know that a channel has been muted. .LP +The X server allows only one application at a time to place a grab on a key, +so if another application already claimed the volume control keys then \fBwmix\fP +will warn you about it and continue without the functionality. +.LP If you modify the configuration file, do not expect \fBwmix\fP to reload it automatically, this is considered a too costly feature for such a small application. -- 2.11.4.GIT