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 <string.h>
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xproto.h>
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <X11/XF86keysym.h>
|
#include <X11/XF86keysym.h>
|
||||||
|
|
||||||
|
@ -59,8 +60,19 @@ typedef struct {
|
||||||
unsigned int list[1 << lengthof(modifier_symbol)];
|
unsigned int list[1 << lengthof(modifier_symbol)];
|
||||||
} modifier_masks;
|
} 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 */
|
/* Local functions */
|
||||||
static void mmkey_build_modifier_list(Display *display, modifier_masks *result);
|
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)
|
void mmkey_install(Display *display)
|
||||||
{
|
{
|
||||||
modifier_masks mod_masks;
|
modifier_masks mod_masks;
|
||||||
|
struct mmkey_track install_info;
|
||||||
Window root_window;
|
Window root_window;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
|
@ -80,6 +93,9 @@ void mmkey_install(Display *display)
|
||||||
|
|
||||||
root_window = DefaultRootWindow(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++) {
|
for (i = 0; i < lengthof(key_list); i++) {
|
||||||
KeyCode key;
|
KeyCode key;
|
||||||
|
|
||||||
|
@ -89,13 +105,21 @@ void mmkey_install(Display *display)
|
||||||
if (key == None)
|
if (key == None)
|
||||||
continue;
|
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++) {
|
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,
|
XGrabKey(display, key, mod_masks.list[j], root_window,
|
||||||
False, GrabModeAsync, GrabModeAsync);
|
False, GrabModeAsync, GrabModeAsync);
|
||||||
}
|
}
|
||||||
if (config.verbose)
|
if (config.verbose)
|
||||||
printf("Found multimedia key: %s\n", key_list[i].name);
|
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
|
implementing mute in similar ways, because there is no way to know
|
||||||
that a channel has been muted.
|
that a channel has been muted.
|
||||||
.LP
|
.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
|
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
|
it automatically, this is considered a too costly feature for such a
|
||||||
small application.
|
small application.
|
||||||
|
|
Loading…
Reference in a new issue