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 <christophe.curis@free.fr>
This commit is contained in:
parent
4379368290
commit
d83b160217
|
@ -23,6 +23,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/XF86keysym.h>
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue