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.
24 #define LOG_DOMAIN "Mmkeys"
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 */
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)
107 static const GTypeInfo info
= {
109 NULL
, /* base_init */
110 NULL
, /* base_finalize */
111 (GClassInitFunc
) mmkeys_class_init
,
112 NULL
, /* class_finalize */
113 NULL
, /* class_data */
116 (GInstanceInitFunc
) mmkeys_init
,
119 type
= g_type_register_static(G_TYPE_OBJECT
, "MmKeys", &info
, 0);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
)
220 name
= gtk_accelerator_name(keysym
, mask
);
226 name
= g_strdup_printf("%s0x%02x", tmp
, keycode
);
233 static void mmkeys_init(MmKeys
* object
)
240 int anyKeybindsFailed
= FALSE
;
241 int anyDuplicatesFound
= FALSE
;
243 display
= gdk_display_get_default();
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);
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);
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);
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);
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
;
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
);
296 root
= gdk_screen_get_root_window(screen
);
298 for (j
= 0; j
< LAST_SIGNAL
; j
++)
301 if (!grab_mmkey(keycodes
[j
], masks
[j
], root
))
304 anyKeybindsFailed
= TRUE
;
308 gdk_window_add_filter(root
, filter_mmkeys
, object
);
312 if (anyKeybindsFailed
)
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
);
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
);
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."),
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
);
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
);
374 static GdkFilterReturn
filter_mmkeys(GdkXEvent
* xevent
, GdkEvent
* event
, gpointer data
)
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
));
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
)
428 display
= gdk_display_get_default();
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
);
438 root
= gdk_screen_get_root_window(screen
);
439 ungrab_mmkey(keycodes
[key
], masks
[key
], root
);
445 keyerror
[key
] = FALSE
;
448 keycodes
[key
] = keycode
;
451 for (i
= 0; i
< gdk_display_get_n_screens(display
); i
++)
453 screen
= gdk_display_get_screen(display
, i
);
456 root
= gdk_screen_get_root_window(screen
);
457 if (!grab_mmkey(keycodes
[key
], masks
[key
], root
))
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
]);
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
);
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);
505 accel_edited_callback(GtkCellRendererText
* cell
,
506 const char *path_string
,
508 GdkModifierType mask
,
509 guint hardware_keycode
,
512 GtkTreeModel
*model
= (GtkTreeModel
*) data
;
513 GtkTreePath
*path
= gtk_tree_path_new_from_string(path_string
);
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.
534 /* Check for duplicates */
535 for (i
= 0; i
< LAST_SIGNAL
; i
++)
539 if (hardware_keycode
!= 0 && keycodes
[i
] == (int)hardware_keycode
&& masks
[i
] == mask
)
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
]));
547 playlist3_show_error_message(message
, ERROR_CRITICAL
);
550 /* Clear the duplicate entry */
551 accel_cleared_callback(cell
, path_string
, data
);
556 grab_key(key
, hardware_keycode
, mask
);
557 gtk_list_store_set(GTK_LIST_STORE(model
), &iter
,
558 MM_STORE_KEYCODE
, hardware_keycode
,
560 MM_STORE_KEYVAL
, keyval
, MM_STORE_FOREGROUND
, keyerror
[key
] ? FG_ERROR
: FG_DEFAULT
, -1);
561 gtk_tree_path_free(path
);
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"
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
);
573 playlist3_show_error_message(message
, ERROR_CRITICAL
);
578 void mmkeys_pref_destroy(GtkWidget
* container
)
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
);
597 g_log(LOG_DOMAIN
, G_LOG_LEVEL_ERROR
, "Problems loading ui: %s\n", error
->message
);
599 g_object_unref(mmkeys_pref_xml
);
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
++)
646 gtk_list_store_append(store
, &iter
);
647 gtk_list_store_set(store
, &iter
,
648 MM_STORE_KEYNAME
, _(keynames
[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);