Fix the label int he sidebar
[gmpc.git] / src / Tools / mm-keys.c
blob60e677031488f5c45b713992e193232e313358e4
1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Borrowed from Lee Willis <lee@leewillis.co.uk> that
4 * Borrowed heavily from code by Jan Arne Petersen <jpetersen@uni-bonn.de>
5 * This projects' homepage is: http://gmpclient.org/
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include <config.h>
23 #ifdef ENABLE_MMKEYS
24 #define LOG_DOMAIN "Mmkeys"
25 #include <stdio.h>
26 #include "mm-keys.h"
28 static void mmkeys_class_init(MmKeysClass * klass);
29 static void mmkeys_init(MmKeys * object);
30 static void mmkeys_finalize(GObject * object);
32 static int grab_mmkey(int key_code, unsigned int mask, GdkWindow * root);
34 static GdkFilterReturn filter_mmkeys(GdkXEvent * xevent, GdkEvent * event, gpointer data);
36 #define FG_DEFAULT None
37 #define FG_ERROR "red"
39 /* Members of the treestore */
40 enum
42 MM_STORE_KEYNAME = 0,
43 MM_STORE_INDEX,
44 MM_STORE_KEYCODE,
45 MM_STORE_MASK,
46 MM_STORE_KEYVAL,
47 MM_STORE_FOREGROUND,
48 MM_STORE_COUNT,
51 enum
53 MM_PLAYPAUSE,
54 MM_NEXT,
55 MM_PREV,
56 MM_STOP,
57 MM_FASTFORWARD,
58 MM_FASTBACKWARD,
59 MM_REPEAT,
60 MM_RANDOM,
61 MM_RAISE,
62 MM_HIDE,
63 MM_TOGGLE_HIDDEN,
64 MM_VOLUME_UP,
65 MM_VOLUME_DOWN,
66 MM_SHOW_NOTIFICATION,
67 MM_TOGGLE_MUTE,
68 MM_SHOW_EASY_COMMAND,
69 MM_PLAY,
70 MM_PAUSE,
71 LAST_SIGNAL
74 const char *keynames[LAST_SIGNAL] = {
75 N_("PlayPause"), /** MM_PLAYPAUSE */
76 N_("Next"), /** MM_NEXT*/
77 N_("Previous"), /** MM_PREV */
78 N_("Stop"), /** MM_STOP */
79 N_("Fast Forward"), /** MM_FASTFORWARD */
80 N_("Fast Backward"), /** MM_FASTBACKWARD */
81 N_("Repeat"), /** MM_REPEAT */
82 N_("Random"), /** MM_RANDOM */
83 N_("Raise window"), /** MM_RAISE */
84 N_("Hide window"), /** MM_HIDE */
85 N_("Toggle window"), /** MM_TOGGLE_HIDDEN */
86 N_("Volume Up"), /** MM_VOLUME_UP */
87 N_("Volume Down"), /** MM_VOLUME_DOWN */
88 N_("Show song"), /** MM_SHOW_NOTIFICATION */
89 N_("Toggle Mute"), /** MM_TOGGLE_MUTE */
90 N_("Show easy command entry"),
91 N_("Play"), /** MM_PLAY */
92 N_("Pause"), /** MM_PAUSE */
95 static GObjectClass *parent_class;
96 static guint signals[LAST_SIGNAL];
97 static int keycodes[LAST_SIGNAL];
98 static unsigned int masks[LAST_SIGNAL];
99 static int keyerror[LAST_SIGNAL];
101 static GType type = 0;
103 static GType mmkeys_get_type(void)
105 if (!type)
107 static const GTypeInfo info = {
108 sizeof(MmKeysClass),
109 NULL, /* base_init */
110 NULL, /* base_finalize */
111 (GClassInitFunc) mmkeys_class_init,
112 NULL, /* class_finalize */
113 NULL, /* class_data */
114 sizeof(MmKeys),
116 (GInstanceInitFunc) mmkeys_init,
119 type = g_type_register_static(G_TYPE_OBJECT, "MmKeys", &info, 0);
122 return type;
125 static void mmkeys_class_init(MmKeysClass * klass)
127 GObjectClass *object_class;
129 parent_class = g_type_class_peek_parent(klass);
130 object_class = (GObjectClass *) klass;
132 object_class->finalize = mmkeys_finalize;
134 signals[MM_PLAYPAUSE] =
135 g_signal_new("mm_playpause",
136 G_TYPE_FROM_CLASS(klass),
137 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
138 signals[MM_PREV] =
139 g_signal_new("mm_prev",
140 G_TYPE_FROM_CLASS(klass),
141 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
142 signals[MM_NEXT] =
143 g_signal_new("mm_next",
144 G_TYPE_FROM_CLASS(klass),
145 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
146 signals[MM_STOP] =
147 g_signal_new("mm_stop",
148 G_TYPE_FROM_CLASS(klass),
149 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
150 signals[MM_FASTFORWARD] =
151 g_signal_new("mm_fastforward",
152 G_TYPE_FROM_CLASS(klass),
153 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
154 signals[MM_FASTBACKWARD] =
155 g_signal_new("mm_fastbackward",
156 G_TYPE_FROM_CLASS(klass),
157 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
158 signals[MM_REPEAT] =
159 g_signal_new("mm_repeat",
160 G_TYPE_FROM_CLASS(klass),
161 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
162 signals[MM_RANDOM] =
163 g_signal_new("mm_random",
164 G_TYPE_FROM_CLASS(klass),
165 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
166 signals[MM_RAISE] =
167 g_signal_new("mm_raise",
168 G_TYPE_FROM_CLASS(klass),
169 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
170 signals[MM_HIDE] =
171 g_signal_new("mm_hide",
172 G_TYPE_FROM_CLASS(klass),
173 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
174 signals[MM_TOGGLE_HIDDEN] =
175 g_signal_new("mm_toggle_hidden",
176 G_TYPE_FROM_CLASS(klass),
177 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
178 signals[MM_VOLUME_UP] =
179 g_signal_new("mm_volume_up",
180 G_TYPE_FROM_CLASS(klass),
181 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
183 signals[MM_VOLUME_DOWN] =
184 g_signal_new("mm_volume_down",
185 G_TYPE_FROM_CLASS(klass),
186 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
187 signals[MM_SHOW_NOTIFICATION] =
188 g_signal_new("mm_show_notification",
189 G_TYPE_FROM_CLASS(klass),
190 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
191 signals[MM_TOGGLE_MUTE] =
192 g_signal_new("mm_toggle_mute",
193 G_TYPE_FROM_CLASS(klass),
194 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
196 signals[MM_SHOW_EASY_COMMAND] =
197 g_signal_new("mm_show_easy_command",
198 G_TYPE_FROM_CLASS(klass),
199 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
201 signals[MM_PLAY] =
202 g_signal_new("mm_play",
203 G_TYPE_FROM_CLASS(klass),
204 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
205 signals[MM_PAUSE] =
206 g_signal_new("mm_pause",
207 G_TYPE_FROM_CLASS(klass),
208 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
211 static void mmkeys_finalize(GObject * object)
213 parent_class->finalize(G_OBJECT(object));
216 static gchar *convert_keysym_state_to_string(guint keysym, GdkModifierType mask, guint keycode)
218 gchar *name;
220 name = gtk_accelerator_name(keysym, mask);
221 if (keysym == 0)
223 gchar *tmp;
225 tmp = name;
226 name = g_strdup_printf("%s0x%02x", tmp, keycode);
227 g_free(tmp);
230 return name;
233 static void mmkeys_init(MmKeys * object)
235 GdkDisplay *display;
236 GdkScreen *screen;
237 GdkWindow *root;
238 gint i, j;
239 // int keycode = 0;
240 int anyKeybindsFailed = FALSE;
241 int anyDuplicatesFound = FALSE;
243 display = gdk_display_get_default();
245 /** Play Pause
246 keycode = XKeysymToKeycode (gdk_x11_get_default_xdisplay (), XF86XK_AudioPlay);
247 keycodes[MM_PLAYPAUSE] = cfg_get_single_value_as_int_with_default(config, "Keybindings", keynames[MM_PLAYPAUSE], keycode);
248 masks[MM_PLAYPAUSE] = cfg_get_single_value_as_int_with_default(config, "Keymasks", keynames[MM_PLAYPAUSE], 0);
251 * Previous
253 keycode = XKeysymToKeycode (gdk_x11_get_default_xdisplay (), XF86XK_AudioPrev);
254 keycodes[MM_PREV] = cfg_get_single_value_as_int_with_default(config, "Keybindings", keynames[MM_PREV], keycode);
255 masks[MM_PREV] = cfg_get_single_value_as_int_with_default(config, "Keymasks", keynames[MM_PREV], 0);
258 * Next
260 keycode = XKeysymToKeycode (gdk_x11_get_default_xdisplay (), XF86XK_AudioNext);
261 keycodes[MM_NEXT] = cfg_get_single_value_as_int_with_default(config, "Keybindings", keynames[MM_NEXT], keycode);
262 masks[MM_NEXT] = cfg_get_single_value_as_int_with_default(config, "Keymasks", keynames[MM_NEXT], 0);
265 * Stop
267 keycode = XKeysymToKeycode (gdk_x11_get_default_xdisplay (), XF86XK_AudioStop);
268 keycodes[MM_STOP] = cfg_get_single_value_as_int_with_default(config, "Keybindings", keynames[MM_STOP], keycode);
269 masks[MM_STOP] = cfg_get_single_value_as_int_with_default(config, "Keymasks", keynames[MM_STOP], 0);
271 for (i = 0; i < LAST_SIGNAL; i++)
273 keycodes[i] = cfg_get_single_value_as_int_with_default(config, "Keybindings", keynames[i], 0);
274 masks[i] = cfg_get_single_value_as_int_with_default(config, "Keymasks", keynames[i], 0);
275 keyerror[i] = FALSE;
276 /* Detect duplicates */
277 for (j = 0; j < i; j++)
279 if (keycodes[i] != 0 && keycodes[i] == keycodes[j] && masks[i] == masks[j])
281 anyDuplicatesFound = TRUE;
282 keycodes[i] = 0;
283 masks[i] = 0;
284 keyerror[i] = TRUE;
285 cfg_set_single_value_as_int(config, "Keybindings", keynames[i], 0);
286 cfg_set_single_value_as_int(config, "Keymasks", keynames[i], 0);
291 for (i = 0; i < gdk_display_get_n_screens(display); i++)
293 screen = gdk_display_get_screen(display, i);
294 if (screen != NULL)
296 root = gdk_screen_get_root_window(screen);
298 for (j = 0; j < LAST_SIGNAL; j++)
300 if (keycodes[j] > 0)
301 if (!grab_mmkey(keycodes[j], masks[j], root))
303 keyerror[j] = TRUE;
304 anyKeybindsFailed = TRUE;
308 gdk_window_add_filter(root, filter_mmkeys, object);
312 if (anyKeybindsFailed)
314 gchar *temp;
315 GString *message = g_string_new(_("Could not grab the following multimedia keys:\n\n"));
316 for (i = 0; i < LAST_SIGNAL; i++)
318 if (keyerror[i] && keycodes[i] != 0)
320 gchar *keysym = convert_keysym_state_to_string(XKeycodeToKeysym(gdk_x11_get_default_xdisplay(), keycodes[i], 0),
321 masks[i], keycodes[i]);
322 g_string_append_printf(message, "\t%s: %s\n", _(keynames[i]), keysym);
323 q_free(keysym);
326 g_string_append(message,
328 ("\nEnsure that your window manager (or other applications) have not already bound this key for some other function, then restart gmpc."));
329 temp = g_markup_escape_text(message->str, message->len);
330 playlist3_show_error_message(temp, ERROR_WARNING);
331 g_free(temp);
332 g_string_free(message, TRUE);
335 if (anyDuplicatesFound)
337 playlist3_show_error_message(_("Duplicate mapping(s) detected\n\n"
338 "Some duplicate multimedia key mappings were detected, and disabled. Please revisit the preferences and ensure your settings are now correct."),
339 ERROR_WARNING);
343 MmKeys *mmkeys_new(void)
345 return MMKEYS(g_object_new(TYPE_MMKEYS, NULL));
348 static int grab_mmkey(int key_code, unsigned int mask, GdkWindow * root)
350 gdk_error_trap_push();
352 XGrabKey(gdk_x11_get_default_xdisplay(), key_code, mask, GDK_WINDOW_XID(root), True, GrabModeAsync, GrabModeAsync);
353 XGrabKey(gdk_x11_get_default_xdisplay(), key_code, Mod2Mask | mask, GDK_WINDOW_XID(root), True, GrabModeAsync, GrabModeAsync);
354 XGrabKey(gdk_x11_get_default_xdisplay(), key_code, Mod5Mask | mask, GDK_WINDOW_XID(root), True, GrabModeAsync, GrabModeAsync);
355 XGrabKey(gdk_x11_get_default_xdisplay(), key_code, LockMask | mask, GDK_WINDOW_XID(root), True, GrabModeAsync, GrabModeAsync);
356 XGrabKey(gdk_x11_get_default_xdisplay(), key_code,
357 Mod2Mask | Mod5Mask | mask, GDK_WINDOW_XID(root), True, GrabModeAsync, GrabModeAsync);
358 XGrabKey(gdk_x11_get_default_xdisplay(), key_code,
359 Mod2Mask | LockMask | mask, GDK_WINDOW_XID(root), True, GrabModeAsync, GrabModeAsync);
360 XGrabKey(gdk_x11_get_default_xdisplay(), key_code,
361 Mod5Mask | LockMask | mask, GDK_WINDOW_XID(root), True, GrabModeAsync, GrabModeAsync);
362 XGrabKey(gdk_x11_get_default_xdisplay(), key_code,
363 Mod2Mask | Mod5Mask | LockMask | mask, GDK_WINDOW_XID(root), True, GrabModeAsync, GrabModeAsync);
365 gdk_flush();
366 if (gdk_error_trap_pop())
368 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Error grabbing key %d+%d, %p\n", key_code, mask, root);
369 return FALSE;
371 return TRUE;
374 static GdkFilterReturn filter_mmkeys(GdkXEvent * xevent, GdkEvent * event, gpointer data)
376 unsigned int i;
377 XEvent *xev;
378 XKeyEvent *key;
379 unsigned int keystate;
381 xev = (XEvent *) xevent;
382 if (xev->type != KeyPress)
384 return GDK_FILTER_CONTINUE;
387 key = (XKeyEvent *) xevent;
388 keystate = key->state & ~(Mod2Mask | Mod5Mask | LockMask);
389 for (i = 0; i < LAST_SIGNAL; i++)
391 if (keycodes[i] == (int)(key->keycode) && masks[i] == keystate)
393 g_signal_emit(data, signals[i], 0, 0);
394 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s pressed", keynames[i]);
395 return GDK_FILTER_REMOVE;
399 return GDK_FILTER_CONTINUE;
402 static void ungrab_mmkey(int key_code, int mask, GdkWindow * root)
404 gdk_error_trap_push();
406 XUngrabKey(gdk_x11_get_default_xdisplay(), key_code, mask, GDK_WINDOW_XID(root));
407 XUngrabKey(gdk_x11_get_default_xdisplay(), key_code, Mod2Mask | mask, GDK_WINDOW_XID(root));
408 XUngrabKey(gdk_x11_get_default_xdisplay(), key_code, Mod5Mask | mask, GDK_WINDOW_XID(root));
409 XUngrabKey(gdk_x11_get_default_xdisplay(), key_code, LockMask | mask, GDK_WINDOW_XID(root));
410 XUngrabKey(gdk_x11_get_default_xdisplay(), key_code, Mod2Mask | Mod5Mask | mask, GDK_WINDOW_XID(root));
411 XUngrabKey(gdk_x11_get_default_xdisplay(), key_code, Mod2Mask | LockMask | mask, GDK_WINDOW_XID(root));
412 XUngrabKey(gdk_x11_get_default_xdisplay(), key_code, Mod5Mask | LockMask | mask, GDK_WINDOW_XID(root));
413 XUngrabKey(gdk_x11_get_default_xdisplay(), key_code, Mod2Mask | Mod5Mask | LockMask | mask, GDK_WINDOW_XID(root));
415 gdk_flush();
416 if (gdk_error_trap_pop())
418 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Error ungrabbing key %d+%d, %p\n", key_code, mask, root);
422 void grab_key(int key, int keycode, unsigned int mask)
424 GdkDisplay *display;
425 GdkScreen *screen;
426 GdkWindow *root;
427 gint i;
428 display = gdk_display_get_default();
430 /* remove old key */
431 if (keycodes[key] > 0)
433 for (i = 0; i < gdk_display_get_n_screens(display); i++)
435 screen = gdk_display_get_screen(display, i);
436 if (screen != NULL)
438 root = gdk_screen_get_root_window(screen);
439 ungrab_mmkey(keycodes[key], masks[key], root);
443 keycodes[key] = 0;
444 masks[key] = 0;
445 keyerror[key] = FALSE;
446 if (keycode > 0)
448 keycodes[key] = keycode;
449 masks[key] = mask;
451 for (i = 0; i < gdk_display_get_n_screens(display); i++)
453 screen = gdk_display_get_screen(display, i);
454 if (screen != NULL)
456 root = gdk_screen_get_root_window(screen);
457 if (!grab_mmkey(keycodes[key], masks[key], root))
459 /* Grab failed */
460 keyerror[key] = TRUE;
465 cfg_set_single_value_as_int(config, "Keybindings", keynames[key], keycodes[key]);
466 cfg_set_single_value_as_int(config, "Keymasks", keynames[key], masks[key]);
469 /*****
470 * Multimedia key plugin for config panel
472 void mmkeys_pref_destroy(GtkWidget * container);
473 void mmkeys_pref_construct(GtkWidget * container);
474 static GtkBuilder *mmkeys_pref_xml = NULL;
476 gmpcPrefPlugin mmkeys_gpp = {
477 .construct = mmkeys_pref_construct,
478 .destroy = mmkeys_pref_destroy
481 gmpcPlugin mmkeys_plug = {
482 .name = N_("Multimedia Keys"),
483 .version = {1, 1, 1},
484 .plugin_type = GMPC_INTERNALL,
485 .pref = &mmkeys_gpp /* preferences */
488 static void accel_cleared_callback(GtkCellRendererText * cell, const char *path_string, gpointer data)
490 GtkTreeModel *model = (GtkTreeModel *) data;
491 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
492 GtkTreeIter iter;
493 int key;
495 gtk_tree_model_get_iter(model, &iter, path);
497 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
498 MM_STORE_KEYCODE, 0, MM_STORE_MASK, 0, MM_STORE_KEYVAL, 0, MM_STORE_FOREGROUND, FG_DEFAULT, -1);
499 gtk_tree_path_free(path);
500 gtk_tree_model_get(model, &iter, 1, &key, -1);
501 grab_key(key, 0, 0);
504 static void
505 accel_edited_callback(GtkCellRendererText * cell,
506 const char *path_string,
507 guint keyval,
508 GdkModifierType mask,
509 guint hardware_keycode,
510 gpointer data)
512 GtkTreeModel *model = (GtkTreeModel *) data;
513 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
514 GtkTreeIter iter;
515 int key;
516 int i;
518 gtk_tree_model_get_iter(model, &iter, path);
520 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "EggCellRenderKeys grabbed %d %u", mask, hardware_keycode);
521 if (hardware_keycode == 22)
523 hardware_keycode = 0;
526 gtk_tree_model_get(model, &iter, 1, &key, -1);
529 // Translate virtual (aka super, hyper, meta) to the X-used key.
530 gdk_keymap_map_virtual_modifiers(gdk_keymap_get_default(), &mask);
531 // Mask off the special Super.
532 mask &= 0xFFFF;
534 /* Check for duplicates */
535 for (i = 0; i < LAST_SIGNAL; i++)
537 if (i == key)
538 continue;
539 if (hardware_keycode != 0 && keycodes[i] == (int)hardware_keycode && masks[i] == mask)
541 gchar *message;
542 gchar *keysym = convert_keysym_state_to_string(XKeycodeToKeysym(gdk_x11_get_default_xdisplay(), hardware_keycode, 0),
543 mask, hardware_keycode);
544 message = g_markup_printf_escaped(_("Duplicate mapping detected\n\n"
545 "%s is already mapped to %s"), keysym, _(keynames[i]));
546 q_free(keysym);
547 playlist3_show_error_message(message, ERROR_CRITICAL);
548 q_free(message);
550 /* Clear the duplicate entry */
551 accel_cleared_callback(cell, path_string, data);
552 return;
556 grab_key(key, hardware_keycode, mask);
557 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
558 MM_STORE_KEYCODE, hardware_keycode,
559 MM_STORE_MASK, mask,
560 MM_STORE_KEYVAL, keyval, MM_STORE_FOREGROUND, keyerror[key] ? FG_ERROR : FG_DEFAULT, -1);
561 gtk_tree_path_free(path);
562 if (keyerror[key])
564 gchar *message;
565 gchar *keysym = convert_keysym_state_to_string(XKeycodeToKeysym(gdk_x11_get_default_xdisplay(), keycodes[key], 0),
566 masks[key], keycodes[key]);
568 message = g_markup_printf_escaped(_("Could not grab multimedia key:\n\n"
569 "\t%s: %s\n\n"
570 "Ensure that your window manager (or other applications) have not already bound this key for some other function, then restart gmpc."),
571 _(keynames[key]), keysym);
572 q_free(keysym);
573 playlist3_show_error_message(message, ERROR_CRITICAL);
574 q_free(message);
578 void mmkeys_pref_destroy(GtkWidget * container)
580 if (mmkeys_pref_xml)
582 GtkWidget *vbox = (GtkWidget *) gtk_builder_get_object(mmkeys_pref_xml, "mmkeys-vbox");
583 gtk_container_remove(GTK_CONTAINER(container), vbox);
584 g_object_unref(mmkeys_pref_xml);
585 mmkeys_pref_xml = NULL;
589 void mmkeys_pref_construct(GtkWidget * container)
591 gchar *path = gmpc_get_full_glade_path("preferences-mmkeys.ui");
592 GError *error = NULL;
593 mmkeys_pref_xml = gtk_builder_new();
594 gtk_builder_add_from_file(mmkeys_pref_xml, path, &error);
595 if (error)
597 g_log(LOG_DOMAIN, G_LOG_LEVEL_ERROR, "Problems loading ui: %s\n", error->message);
598 g_error_free(error);
599 g_object_unref(mmkeys_pref_xml);
600 return;
602 q_free(path);
603 if (mmkeys_pref_xml)
605 int i = 0;
606 GtkWidget *vbox = (GtkWidget *) gtk_builder_get_object(mmkeys_pref_xml, "mmkeys-vbox");
607 GtkTreeViewColumn *column = NULL;
608 GtkListStore *store = gtk_list_store_new(MM_STORE_COUNT,
609 G_TYPE_STRING, /* MM_STORE_KEYNAME */
610 G_TYPE_INT, /* MM_STORE_INDEX */
611 G_TYPE_UINT, /* MM_STORE_KEYCODE */
612 G_TYPE_UINT, /* MM_STORE_MASK */
613 G_TYPE_UINT, /* MM_STORE_KEYVAL */
614 G_TYPE_STRING /* MM_STORE_FOREGROUND */
616 GtkCellRenderer *rend = gtk_cell_renderer_text_new();
617 gtk_tree_view_set_model(GTK_TREE_VIEW(gtk_builder_get_object(mmkeys_pref_xml, "mmkeys-tree")),
618 GTK_TREE_MODEL(store));
620 column = gtk_tree_view_column_new();
621 gtk_tree_view_column_pack_start(column, rend, TRUE);
622 gtk_tree_view_column_add_attribute(column, rend, "text", MM_STORE_KEYNAME);
623 gtk_tree_view_column_set_title(column, _("Action"));
624 gtk_tree_view_append_column(GTK_TREE_VIEW(gtk_builder_get_object(mmkeys_pref_xml, "mmkeys-tree")), column);
626 rend = gtk_cell_renderer_accel_new();
627 column = gtk_tree_view_column_new();
629 g_object_set(G_OBJECT(rend), "editable", TRUE, "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER, NULL);
631 g_signal_connect(G_OBJECT(rend), "accel_edited", G_CALLBACK(accel_edited_callback), store);
633 g_signal_connect(G_OBJECT(rend), "accel_cleared", G_CALLBACK(accel_cleared_callback), store);
634 gtk_tree_view_column_pack_start(column, rend, TRUE);
635 gtk_tree_view_column_set_title(column, _("Shortcut"));
636 gtk_tree_view_column_set_attributes(column, rend,
637 "keycode", MM_STORE_KEYCODE,
638 "accel_mods", MM_STORE_MASK,
639 "accel_key", MM_STORE_KEYVAL, "foreground", MM_STORE_FOREGROUND, NULL);
640 gtk_tree_view_append_column(GTK_TREE_VIEW(gtk_builder_get_object(mmkeys_pref_xml, "mmkeys-tree")), column);
642 gtk_container_add(GTK_CONTAINER(container), vbox);
643 for (i = 0; i < LAST_SIGNAL; i++)
645 GtkTreeIter iter;
646 gtk_list_store_append(store, &iter);
647 gtk_list_store_set(store, &iter,
648 MM_STORE_KEYNAME, _(keynames[i]),
649 MM_STORE_INDEX, i,
650 MM_STORE_KEYCODE, keycodes[i],
651 MM_STORE_MASK, masks[i],
652 MM_STORE_KEYVAL, XKeycodeToKeysym(gdk_x11_get_default_xdisplay(), keycodes[i], 0),
653 MM_STORE_FOREGROUND, keyerror[i] ? FG_ERROR : FG_DEFAULT, -1);
659 #endif