pnmixer
Volume mixer for the system tray
hotkey.c
Go to the documentation of this file.
1 /* hotkey.c
2  * PNmixer is written by Nick Lanham, a fork of OBmixer
3  * which was programmed by Lee Ferrett, derived
4  * from the program "AbsVolume" by Paul Sherman
5  * This program is free software; you can redistribute
6  * it and/or modify it under the terms of the GNU General
7  * Public License v3. source code is available at
8  * <http://github.com/nicklan/pnmixer>
9  */
10 
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 
22 #include <gtk/gtk.h>
23 #include <gdk/gdkx.h>
24 #include <X11/XKBlib.h>
25 
26 #include "support-log.h"
27 #include "hotkey.h"
28 
29 // `xmodmap -pm`
30 /* List of key modifiers which will be ignored whenever
31  * we check whether the defined hotkeys have been pressed.
32  */
33 static guint keymasks[] = {
34  0, /* No Modkey */
35  GDK_MOD2_MASK, /* Numlock */
36  GDK_LOCK_MASK, /* Capslock */
37  GDK_MOD2_MASK | GDK_LOCK_MASK /* Both */
38 };
39 
40 /* Error that may be set if grabbing hotkey fails. */
41 static char grab_error;
42 
43 /* Helpers */
44 
45 /* When an Xlib error occurs when grabbing the hotkey, this function is called.
46  * The error handler should not call any functions (directly or indirectly)
47  * on the display that will generate protocol requests or that will look for
48  * input events.
49  * Return value is ignored.
50  */
51 static int
52 grab_error_handler(G_GNUC_UNUSED Display *disp, G_GNUC_UNUSED XErrorEvent *ev)
53 {
54  WARN("Error while grabbing hotkey");
55  grab_error = 1;
56  return 0;
57 }
58 
59 /* Public functions */
60 
67 void
69 {
70  Display *disp;
71  guint i;
72 
73  g_return_if_fail(hotkey != NULL);
74 
75  DEBUG("Ungrabbing hotkey '%s'", hotkey->str);
76 
77  disp = gdk_x11_get_default_xdisplay();
78 
79  /* Ungrab the key */
80  for (i = 0; i < G_N_ELEMENTS(keymasks); i++)
81  XUngrabKey(disp, hotkey->code, hotkey->mods | keymasks[i],
82  GDK_ROOT_WINDOW());
83 }
84 
91 gboolean
93 {
94  Display *disp;
95  XErrorHandler old_hdlr;
96  guint i;
97 
98  g_return_val_if_fail(hotkey != NULL, FALSE);
99 
100  DEBUG("Grabbing hotkey '%s'", hotkey->str);
101 
102  disp = gdk_x11_get_default_xdisplay();
103 
104  /* Init error handling */
105  grab_error = 0;
106  old_hdlr = XSetErrorHandler(grab_error_handler);
107 
108  /* Grab the key */
109  for (i = 0; i < G_N_ELEMENTS(keymasks); i++)
110  XGrabKey(disp, hotkey->code, hotkey->mods | keymasks[i],
111  GDK_ROOT_WINDOW(), 1, GrabModeAsync, GrabModeAsync);
112 
113  /* Synchronize X */
114  XFlush(disp);
115  XSync(disp, False);
116 
117  /* Restore error handler */
118  (void) XSetErrorHandler(old_hdlr);
119 
120  /* Check for error */
121  if (grab_error)
122  return FALSE;
123 
124  return TRUE;
125 }
126 
137 gboolean
138 hotkey_matches(Hotkey *hotkey, guint code, GdkModifierType mods)
139 {
140  guint i;
141 
142  g_return_val_if_fail(hotkey != NULL, FALSE);
143 
144  if (code != hotkey->code)
145  return FALSE;
146 
147  for (i = 0; i < G_N_ELEMENTS(keymasks); i++)
148  if ((hotkey->mods | keymasks[i]) == mods)
149  return TRUE;
150 
151  return FALSE;
152 }
153 
159 void
161 {
162  if (hotkey == NULL)
163  return;
164 
166 
167  g_free(hotkey->str);
168  g_free(hotkey);
169 }
170 
178 Hotkey *
179 hotkey_new(guint code, GdkModifierType mods)
180 {
181  Hotkey *hotkey;
182  Display *disp;
183 
184  hotkey = g_new0(Hotkey, 1);
185  disp = gdk_x11_get_default_xdisplay();
186 
187  hotkey->code = code;
188  hotkey->mods = mods;
189  hotkey->sym = XkbKeycodeToKeysym(disp, hotkey->code, 0, 0);
190  hotkey->str = gtk_accelerator_name(hotkey->sym, hotkey->mods);
191 
192  if (hotkey_grab(hotkey) == FALSE) {
194  hotkey = NULL;
195  }
196 
197  return hotkey;
198 }
199 
207 gchar *
208 hotkey_code_to_accel(guint code, GdkModifierType mods)
209 {
210  Display *disp;
211  guint sym;
212  gchar *accel;
213 
214  disp = gdk_x11_get_default_xdisplay();
215 
216  sym = XkbKeycodeToKeysym(disp, code, 0, 0);
217  accel = gtk_accelerator_name(sym, mods);
218 
219  return accel;
220 }
221 
229 void
230 hotkey_accel_to_code(const gchar *accel, gint *code, GdkModifierType *mods)
231 {
232  Display *disp;
233  guint sym;
234 
235  disp = gdk_x11_get_default_xdisplay();
236 
237  gtk_accelerator_parse(accel, &sym, mods);
238  if (sym != 0)
239  *code = XKeysymToKeycode(disp, sym);
240  else
241  *code = -1;
242 }
unsigned long int sym
Definition: hotkey.h:28
void hotkey_ungrab(Hotkey *hotkey)
Definition: hotkey.c:68
Logging support.
gchar * hotkey_code_to_accel(guint code, GdkModifierType mods)
Definition: hotkey.c:208
void hotkey_accel_to_code(const gchar *accel, gint *code, GdkModifierType *mods)
Definition: hotkey.c:230
gboolean hotkey_matches(Hotkey *hotkey, guint code, GdkModifierType mods)
Definition: hotkey.c:138
#define DEBUG(...)
Definition: support-log.h:38
static guint keymasks[]
Definition: hotkey.c:33
gchar * str
Definition: hotkey.h:29
static char grab_error
Definition: hotkey.c:41
Header for hotkey.c.
gboolean hotkey_grab(Hotkey *hotkey)
Definition: hotkey.c:92
guint code
Definition: hotkey.h:26
Definition: hotkey.h:22
Hotkey * hotkey_new(guint code, GdkModifierType mods)
Definition: hotkey.c:179
GdkModifierType mods
Definition: hotkey.h:27
void hotkey_free(Hotkey *hotkey)
Definition: hotkey.c:160
static int grab_error_handler(G_GNUC_UNUSED Display *disp, G_GNUC_UNUSED XErrorEvent *ev)
Definition: hotkey.c:52
#define WARN(...)
Definition: support-log.h:37