Allow a window manager to inherit keybindings from another window manager

Mutter shares most (currently all) its keybindings with Metacity, and uses
the same /apps/metacity GConf keys. For 2.28, the schemas stay in Metacity;
the eventual plan is to have a gnome-wm-data package.

This patch allows a window manager to put a _GNOME_WM_KEYBINDINGS property
on its _NET_SUPPORTING_WM_CHECK window to provide a comma separated list of
window manager names to use for keybinding lookup instead of _NET_WM_NAME.

http://bugzilla.gnome.org/show_bug.cgi?id=594066
This commit is contained in:
Owen W. Taylor 2009-09-03 14:36:12 -04:00
parent 1fce26d7e2
commit a01e8daa6d
3 changed files with 79 additions and 15 deletions

View file

@ -15,10 +15,10 @@ typedef struct _WMCallbackData
/* Our WM Window */ /* Our WM Window */
static Window wm_window = None; static Window wm_window = None;
char* static char *
wm_common_get_current_window_manager (void) wm_common_get_window_manager_property (Atom atom)
{ {
Atom utf8_string, atom, type; Atom utf8_string, type;
int result; int result;
char *retval; char *retval;
int format; int format;
@ -30,7 +30,6 @@ wm_common_get_current_window_manager (void)
return g_strdup (WM_COMMON_UNKNOWN); return g_strdup (WM_COMMON_UNKNOWN);
utf8_string = XInternAtom (GDK_DISPLAY (), "UTF8_STRING", False); utf8_string = XInternAtom (GDK_DISPLAY (), "UTF8_STRING", False);
atom = XInternAtom (GDK_DISPLAY (), "_NET_WM_NAME", False);
gdk_error_trap_push (); gdk_error_trap_push ();
@ -60,6 +59,49 @@ wm_common_get_current_window_manager (void)
return retval; return retval;
} }
char*
wm_common_get_current_window_manager (void)
{
Atom atom = XInternAtom (GDK_DISPLAY (), "_NET_WM_NAME", False);
char *result;
result = wm_common_get_window_manager_property (atom);
if (result)
return result;
else
return g_strdup (WM_COMMON_UNKNOWN);
}
char**
wm_common_get_current_keybindings (void)
{
Atom keybindings_atom = XInternAtom (GDK_DISPLAY (), "_GNOME_WM_KEYBINDINGS", False);
char *keybindings = wm_common_get_window_manager_property (keybindings_atom);
char **results;
if (keybindings)
{
char **p;
results = g_strsplit(keybindings, ",", -1);
for (p = results; *p; p++)
g_strstrip (*p);
g_free (keybindings);
}
else
{
Atom wm_atom = XInternAtom (GDK_DISPLAY (), "_NET_WM_NAME", False);
char *wm_name = wm_common_get_window_manager_property (wm_atom);
char *to_copy[] = { NULL, NULL };
to_copy[0] = wm_name;
results = g_strdupv (to_copy);
g_free (wm_name);
}
return results;
}
static void static void
update_wm_window (void) update_wm_window (void)
{ {

View file

@ -6,6 +6,10 @@
#define WM_COMMON_UNKNOWN "Unknown" #define WM_COMMON_UNKNOWN "Unknown"
gchar *wm_common_get_current_window_manager (void); gchar *wm_common_get_current_window_manager (void);
/* Returns a strv of keybinding names for the window manager;
* using _GNOME_WM_KEYBINDINGS if available, _NET_WM_NAME otherwise. */
char **wm_common_get_current_keybindings (void);
void wm_common_register_window_manager_change (GFunc func, void wm_common_register_window_manager_change (GFunc func,
gpointer data); gpointer data);

View file

@ -816,10 +816,22 @@ parse_start_tag (GMarkupParseContext *ctx,
g_array_append_val (keylist->entries, key); g_array_append_val (keylist->entries, key);
} }
static gboolean
strv_contains (char **strv,
char *str)
{
char **p = strv;
for (p = strv; *p; p++)
if (strcmp (*p, str) == 0)
return TRUE;
return FALSE;
}
static void static void
append_keys_to_tree_from_file (GtkBuilder *builder, append_keys_to_tree_from_file (GtkBuilder *builder,
const char *filename, const char *filename,
const char *wm_name) char **wm_keybindings)
{ {
GMarkupParseContext *ctx; GMarkupParseContext *ctx;
GMarkupParser parser = { parse_start_tag, NULL, NULL, NULL, NULL }; GMarkupParser parser = { parse_start_tag, NULL, NULL, NULL, NULL };
@ -860,7 +872,7 @@ append_keys_to_tree_from_file (GtkBuilder *builder,
/* If there's no keys to add, or the settings apply to a window manager /* If there's no keys to add, or the settings apply to a window manager
* that's not the one we're running */ * that's not the one we're running */
if (keylist->entries->len == 0 if (keylist->entries->len == 0
|| (keylist->wm_name != NULL && !g_str_equal (wm_name, keylist->wm_name)) || (keylist->wm_name != NULL && strv_contains (wm_keybindings, keylist->wm_name))
|| keylist->name == NULL) || keylist->name == NULL)
{ {
g_free (keylist->name); g_free (keylist->name);
@ -951,12 +963,15 @@ append_keys_to_tree_from_gconf (GtkBuilder *builder, const gchar *gconf_path)
} }
static void static void
reload_key_entries (gpointer wm_name, GtkBuilder *builder) reload_key_entries (GtkBuilder *builder)
{ {
gchar **wm_keybindings;
GDir *dir; GDir *dir;
const char *name; const char *name;
GList *list, *l; GList *list, *l;
wm_keybindings = wm_common_get_current_keybindings();
clear_old_model (builder); clear_old_model (builder);
dir = g_dir_open (GNOMECC_KEYBINDINGS_DIR, 0, NULL); dir = g_dir_open (GNOMECC_KEYBINDINGS_DIR, 0, NULL);
@ -979,7 +994,7 @@ reload_key_entries (gpointer wm_name, GtkBuilder *builder)
gchar *path; gchar *path;
path = g_build_filename (GNOMECC_KEYBINDINGS_DIR, l->data, NULL); path = g_build_filename (GNOMECC_KEYBINDINGS_DIR, l->data, NULL);
append_keys_to_tree_from_file (builder, path, wm_name); append_keys_to_tree_from_file (builder, path, wm_keybindings);
g_free (l->data); g_free (l->data);
g_free (path); g_free (path);
} }
@ -991,6 +1006,8 @@ reload_key_entries (gpointer wm_name, GtkBuilder *builder)
* such keys not show up in the custom section. * such keys not show up in the custom section.
*/ */
append_keys_to_tree_from_gconf (builder, GCONF_BINDING_DIR); append_keys_to_tree_from_gconf (builder, GCONF_BINDING_DIR);
g_strfreev (wm_keybindings);
} }
static void static void
@ -999,9 +1016,7 @@ key_entry_controlling_key_changed (GConfClient *client,
GConfEntry *entry, GConfEntry *entry,
gpointer user_data) gpointer user_data)
{ {
gchar *wm_name = wm_common_get_current_window_manager(); reload_key_entries (user_data);
reload_key_entries (wm_name, user_data);
g_free (wm_name);
} }
static gboolean static gboolean
@ -1795,7 +1810,6 @@ setup_dialog (GtkBuilder *builder)
GtkTreeViewColumn *column; GtkTreeViewColumn *column;
GtkWidget *widget; GtkWidget *widget;
GtkTreeView *treeview; GtkTreeView *treeview;
gchar *wm_name;
GtkTreeSelection *selection; GtkTreeSelection *selection;
GSList *allowed_keys; GSList *allowed_keys;
@ -1852,9 +1866,7 @@ setup_dialog (GtkBuilder *builder)
builder, NULL, NULL); builder, NULL, NULL);
/* set up the dialog */ /* set up the dialog */
wm_name = wm_common_get_current_window_manager();
reload_key_entries (wm_name, builder); reload_key_entries (wm_name, builder);
g_free (wm_name);
widget = _gtk_builder_get_widget (builder, "gnome-keybinding-dialog"); widget = _gtk_builder_get_widget (builder, "gnome-keybinding-dialog");
capplet_set_icon (widget, "preferences-desktop-keyboard-shortcuts"); capplet_set_icon (widget, "preferences-desktop-keyboard-shortcuts");
@ -1895,6 +1907,12 @@ setup_dialog (GtkBuilder *builder)
GTK_WINDOW (widget)); GTK_WINDOW (widget));
} }
static void
on_window_manager_change (const char *wm_name, GtkBuilder *builder)
{
reload_key_entries (builder);
}
int int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
@ -1916,7 +1934,7 @@ main (int argc, char *argv[])
if (!builder) /* Warning was already printed to console */ if (!builder) /* Warning was already printed to console */
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
wm_common_register_window_manager_change ((GFunc) reload_key_entries, builder); wm_common_register_window_manager_change ((GFunc) on_window_manager_change, dialog);
setup_dialog (builder); setup_dialog (builder);
gtk_main (); gtk_main ();