wmclock: Bump to version 1.0.15.
[dockapps.git] / wmix / mmkeys.c
blob2dae788a0a4ee47cafef3878cf4906d304554236
1 /* WMix -- a mixer using the OSS mixer API.
2 * Copyright (C) 2014 Christophe CURIS for the WindowMaker Team
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 * mmkeys.c: functions related to grabing the Multimedia Keys on keyboard
22 #include <stdio.h>
23 #include <string.h>
25 #include <X11/Xlib.h>
26 #include <X11/Xproto.h>
27 #include <X11/keysym.h>
28 #include <X11/XF86keysym.h>
30 #include "include/common.h"
31 #include "include/config.h"
32 #include "include/mmkeys.h"
35 /* The global configuration */
36 struct multimedia_keys mmkeys;
38 /* The list of keys we're interrested in */
39 static const struct {
40 KeySym symbol;
41 KeyCode *store;
42 const char *name;
43 } key_list[] = {
44 { XF86XK_AudioRaiseVolume, &mmkeys.raise_volume, "AudioRaiseVolume" },
45 { XF86XK_AudioLowerVolume, &mmkeys.lower_volume, "AudioLowerVolume" },
46 { XF86XK_AudioMute, &mmkeys.mute, "AudioMute" }
49 /* The modifiers that should not have impact on the key grabbed */
50 static const struct {
51 KeySym symbol;
52 const char *name;
53 } modifier_symbol[] = {
54 { XK_Caps_Lock, "CapsLock" },
55 { XK_Num_Lock, "NumLock" }
58 typedef struct {
59 int count;
60 unsigned int list[1 << lengthof(modifier_symbol)];
61 } modifier_masks;
63 /* The structure to track grab installation for errors */
64 static struct mmkey_track {
65 XErrorHandler previous_handler;
66 struct {
67 const char *key_name;
68 unsigned long serial[1 << lengthof(modifier_symbol)];
69 Bool displayed;
70 } request[lengthof(key_list)];
71 } *track_install = NULL;
73 /* Local functions */
74 static void mmkey_build_modifier_list(Display *display, modifier_masks *result);
75 static int mmkey_catch_grab_error(Display *display, XErrorEvent *event);
79 * Grab the multimedia keys on the X server
81 * That basically means that whenever these keys are pressed
82 * the events will be sent to us instead of the application
83 * that has current focus.
85 void mmkey_install(Display *display)
87 modifier_masks mod_masks;
88 struct mmkey_track install_info;
89 Window root_window;
90 int i, j;
92 mmkey_build_modifier_list(display, &mod_masks);
94 root_window = DefaultRootWindow(display);
96 memset(&install_info, 0, sizeof(install_info));
97 install_info.previous_handler = XSetErrorHandler(mmkey_catch_grab_error);
98 track_install = &install_info;
99 for (i = 0; i < lengthof(key_list); i++) {
100 KeyCode key;
102 key = XKeysymToKeycode(display, key_list[i].symbol);
103 *(key_list[i].store) = key;
105 if (key == None)
106 continue;
108 install_info.request[i].key_name = key_list[i].name;
109 install_info.request[i].displayed = False;
110 for (j = 0; j < mod_masks.count; j++) {
111 install_info.request[i].serial[j] = NextRequest(display);
112 XGrabKey(display, key, mod_masks.list[j], root_window,
113 False, GrabModeAsync, GrabModeAsync);
115 if (config.verbose)
116 printf("Found multimedia key: %s\n", key_list[i].name);
119 /* The grab may fail, so make sure it is reported now */
120 XSync(display, False);
121 XSetErrorHandler(install_info.previous_handler);
122 track_install = NULL;
126 * Build the list of bit-masks for all the modifiers we want to not have impact on our grab
128 static void mmkey_build_modifier_list(Display *display, modifier_masks *result)
130 XModifierKeymap *mods;
131 KeyCode mod_code[lengthof(modifier_symbol)];
132 unsigned int mod_mask[lengthof(modifier_symbol)];
133 char buffer[256];
134 int nb_modifiers;
135 int i, j, k;
137 /* Get the bitmask associated with the modifiers */
138 for (i = 0; i < lengthof(modifier_symbol); i++) {
139 mod_code[i] = XKeysymToKeycode(display, modifier_symbol[i].symbol);
140 mod_mask[i] = 0L;
143 mods = XGetModifierMapping(display);
144 for (i = 0; i < 8; i++) {
145 for (j = 0; j < mods->max_keypermod; j++) {
146 KeyCode key_mod;
148 key_mod = mods->modifiermap[i * mods->max_keypermod + j];
149 for (k = 0; k < lengthof(mod_code); k++) {
150 if ((mod_code[k] != None) && (key_mod == mod_code[k]))
151 mod_mask[k] |= 1 << i;
155 XFreeModifiermap(mods);
157 /* Count the number of modifiers found (and display the list to the user) */
158 if (config.verbose)
159 strcpy(buffer, "Found key modifiers: ");
161 nb_modifiers = 0;
162 for (i = 0; i < lengthof(modifier_symbol); i++) {
163 if (mod_mask[i] != 0) {
164 if (config.verbose) {
165 if (nb_modifiers > 0)
166 strcat(buffer, ", ");
167 strcat(buffer, modifier_symbol[i].name);
169 nb_modifiers++;
172 if (config.verbose) {
173 if (nb_modifiers == 0)
174 strcat(buffer, "None");
175 puts(buffer);
178 /* Build the list of possible combinations of modifiers */
179 result->count = 1 << nb_modifiers;
180 for (i = 0; i < lengthof(result->list); i++)
181 result->list[i] = 0L;
182 k = 1;
183 for (i = 0; i < lengthof(mod_mask); i++) {
184 if (mod_mask[i] != 0) {
185 for (j = 1; j < result->count; j++)
186 if (j & k)
187 result->list[j] |= mod_mask[i];
189 k <<= 1;
195 * Callback when X11 reports an error
197 * We only track errors from XGrabKey and display them to user, instead of
198 * letting the default error handler exit
200 static int mmkey_catch_grab_error(Display *display, XErrorEvent *event)
202 int i, j;
204 if ((event->error_code == BadAccess) && (event->request_code == X_GrabKey)) {
205 for (i = 0; i < lengthof(track_install->request); i++) {
206 for (j = 0; j < lengthof(track_install->request[i].serial); j++) {
207 if (track_install->request[i].serial[j] == 0L)
208 break;
209 if (event->serial == track_install->request[i].serial[j]) {
210 if (!track_install->request[i].displayed) {
211 fprintf(stderr, "wmix:warning: could not grab key %s, is another application using it?\n",
212 track_install->request[i].key_name);
213 track_install->request[i].displayed = True;
215 return 0;
221 /* That's not an XGrabKey known issue, let the default handler manage this */
222 return track_install->previous_handler(display, event);