Allow any keybinding pref to be specified either with <foo>, a string, or

2004-04-17  Thomas Thurman <thomas@thurman.org.uk>

        * keybindings.c (count_bindings, rebuild_binding_table):
        * prefs.c (change_notify, screen_bindings,
        window_bindings, init_bindings, update_binding,
        find_and_update_list_binding, update_list_binding,
        meta_prefs_get_window_binding): Allow any keybinding pref
        to be specified either with <foo>, a string, or <foo>_list,
        a list of strings, or both. Fixes #164831.
This commit is contained in:
Thomas Thurman 2006-04-17 17:23:09 +00:00 committed by Thomas James Alexander Thurman
parent 83d21b97c4
commit fee1fb094a
4 changed files with 480 additions and 158 deletions

View File

@ -1,3 +1,13 @@
2004-04-17 Thomas Thurman <thomas@thurman.org.uk>
* keybindings.c (count_bindings, rebuild_binding_table):
* prefs.c (change_notify, screen_bindings,
window_bindings, init_bindings, update_binding,
find_and_update_list_binding, update_list_binding,
meta_prefs_get_window_binding): Allow any keybinding pref
to be specified either with <foo>, a string, or <foo>_list,
a list of strings, or both. Fixes #164831.
2006-04-16 Elijah Newren <newren gmail com> 2006-04-16 Elijah Newren <newren gmail com>
Patch from Dan Sanders to fix #334899. Patch from Dan Sanders to fix #334899.

View File

@ -639,15 +639,24 @@ count_bindings (const MetaKeyPref *prefs,
i = 0; i = 0;
while (i < n_prefs) while (i < n_prefs)
{ {
if (prefs[i].keysym != None) GSList *tmp = prefs[i].bindings;
while (tmp)
{
MetaKeyCombo *combo = tmp->data;
if (combo && combo->keysym != None)
{ {
count += 1; count += 1;
if (prefs[i].add_shift && if (prefs[i].add_shift &&
(prefs[i].modifiers & META_VIRTUAL_SHIFT_MASK) == 0) (combo->modifiers & META_VIRTUAL_SHIFT_MASK) == 0)
count += 1; count += 1;
} }
tmp = tmp->next;
}
++i; ++i;
} }
@ -672,26 +681,32 @@ rebuild_binding_table (MetaDisplay *display,
dest = 0; dest = 0;
while (src < n_prefs) while (src < n_prefs)
{ {
if (prefs[src].keysym != None) GSList *tmp = prefs[src].bindings;
while (tmp)
{
MetaKeyCombo *combo = tmp->data;
if (combo && combo->keysym != None)
{ {
(*bindings_p)[dest].name = prefs[src].name; (*bindings_p)[dest].name = prefs[src].name;
(*bindings_p)[dest].keysym = prefs[src].keysym; (*bindings_p)[dest].keysym = combo->keysym;
(*bindings_p)[dest].modifiers = prefs[src].modifiers; (*bindings_p)[dest].modifiers = combo->modifiers;
(*bindings_p)[dest].mask = 0; (*bindings_p)[dest].mask = 0;
(*bindings_p)[dest].keycode = 0; (*bindings_p)[dest].keycode = 0;
++dest; ++dest;
if (prefs[src].add_shift && if (prefs[src].add_shift &&
(prefs[src].modifiers & META_VIRTUAL_SHIFT_MASK) == 0) (combo->modifiers & META_VIRTUAL_SHIFT_MASK) == 0)
{ {
meta_topic (META_DEBUG_KEYBINDINGS, meta_topic (META_DEBUG_KEYBINDINGS,
"Binding %s also needs Shift grabbed\n", "Binding %s also needs Shift grabbed\n",
prefs[src].name); prefs[src].name);
(*bindings_p)[dest].name = prefs[src].name; (*bindings_p)[dest].name = prefs[src].name;
(*bindings_p)[dest].keysym = prefs[src].keysym; (*bindings_p)[dest].keysym = combo->keysym;
(*bindings_p)[dest].modifiers = prefs[src].modifiers | (*bindings_p)[dest].modifiers = combo->modifiers |
META_VIRTUAL_SHIFT_MASK; META_VIRTUAL_SHIFT_MASK;
(*bindings_p)[dest].mask = 0; (*bindings_p)[dest].mask = 0;
(*bindings_p)[dest].keycode = 0; (*bindings_p)[dest].keycode = 0;
@ -700,6 +715,9 @@ rebuild_binding_table (MetaDisplay *display,
} }
} }
tmp = tmp->next;
}
++src; ++src;
} }

View File

@ -63,6 +63,7 @@
#define KEY_SCREEN_BINDINGS_PREFIX "/apps/metacity/global_keybindings" #define KEY_SCREEN_BINDINGS_PREFIX "/apps/metacity/global_keybindings"
#define KEY_WINDOW_BINDINGS_PREFIX "/apps/metacity/window_keybindings" #define KEY_WINDOW_BINDINGS_PREFIX "/apps/metacity/window_keybindings"
#define KEY_LIST_BINDINGS_SUFFIX "_list"
#define KEY_WORKSPACE_NAME_PREFIX "/apps/metacity/workspace_names/name_" #define KEY_WORKSPACE_NAME_PREFIX "/apps/metacity/workspace_names/name_"
@ -146,6 +147,13 @@ static gboolean update_window_binding (const char *name,
const char *value); const char *value);
static gboolean update_screen_binding (const char *name, static gboolean update_screen_binding (const char *name,
const char *value); const char *value);
static gboolean find_and_update_list_binding (MetaKeyPref *bindings,
const char *name,
GSList *value);
static gboolean update_window_list_binding (const char *name,
GSList *value);
static gboolean update_screen_list_binding (const char *name,
GSList *value);
static gboolean update_command (const char *name, static gboolean update_command (const char *name,
const char *value); const char *value);
static gboolean update_terminal_command (const char *value); static gboolean update_terminal_command (const char *value);
@ -169,6 +177,16 @@ static void queue_changed (MetaPreference pref);
static gboolean update_binding (MetaKeyPref *binding, static gboolean update_binding (MetaKeyPref *binding,
const char *value); const char *value);
typedef enum
{
META_LIST_OF_STRINGS,
META_LIST_OF_GCONFVALUE_STRINGS
} MetaStringListType;
static gboolean update_list_binding (MetaKeyPref *binding,
GSList *value,
MetaStringListType type_of_value);
static void init_bindings (void); static void init_bindings (void);
static void init_commands (void); static void init_commands (void);
static void init_workspace_names (void); static void init_workspace_names (void);
@ -712,6 +730,24 @@ change_notify (GConfClient *client,
queue_changed (META_PREF_DISABLE_WORKAROUNDS); queue_changed (META_PREF_DISABLE_WORKAROUNDS);
} }
else if (g_str_has_prefix (key, KEY_WINDOW_BINDINGS_PREFIX)) else if (g_str_has_prefix (key, KEY_WINDOW_BINDINGS_PREFIX))
{
if (g_str_has_suffix (key, KEY_LIST_BINDINGS_SUFFIX))
{
GSList *list;
if (value && value->type != GCONF_VALUE_LIST)
{
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
key);
goto out;
}
list = value ? gconf_value_get_list (value) : NULL;
if (update_window_list_binding (key, list))
queue_changed (META_PREF_WINDOW_KEYBINDINGS);
}
else
{ {
const char *str; const char *str;
@ -727,7 +763,26 @@ change_notify (GConfClient *client,
if (update_window_binding (key, str)) if (update_window_binding (key, str))
queue_changed (META_PREF_WINDOW_KEYBINDINGS); queue_changed (META_PREF_WINDOW_KEYBINDINGS);
} }
}
else if (g_str_has_prefix (key, KEY_SCREEN_BINDINGS_PREFIX)) else if (g_str_has_prefix (key, KEY_SCREEN_BINDINGS_PREFIX))
{
if (g_str_has_suffix (key, KEY_LIST_BINDINGS_SUFFIX))
{
GSList *list;
if (value && value->type != GCONF_VALUE_LIST)
{
meta_warning (_("GConf key \"%s\" is set to an invalid type\n"),
key);
goto out;
}
list = value ? gconf_value_get_list (value) : NULL;
if (update_screen_list_binding (key, list))
queue_changed (META_PREF_SCREEN_KEYBINDINGS);
}
else
{ {
const char *str; const char *str;
@ -743,6 +798,7 @@ change_notify (GConfClient *client,
if (update_screen_binding (key, str)) if (update_screen_binding (key, str))
queue_changed (META_PREF_SCREEN_KEYBINDINGS); queue_changed (META_PREF_SCREEN_KEYBINDINGS);
} }
}
else if (strcmp (key, KEY_ACTION_DOUBLE_CLICK_TITLEBAR) == 0) else if (strcmp (key, KEY_ACTION_DOUBLE_CLICK_TITLEBAR) == 0)
{ {
const char *str; const char *str;
@ -1737,110 +1793,110 @@ meta_prefs_set_num_workspaces (int n_workspaces)
/* Indexes must correspond to MetaKeybindingAction */ /* Indexes must correspond to MetaKeybindingAction */
static MetaKeyPref screen_bindings[] = { static MetaKeyPref screen_bindings[] = {
{ META_KEYBINDING_WORKSPACE_1, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_1, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_2, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_2, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_3, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_3, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_4, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_4, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_5, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_5, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_6, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_6, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_7, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_7, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_8, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_8, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_9, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_9, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_10, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_10, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_11, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_11, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_12, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_12, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_LEFT, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_LEFT, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_RIGHT, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_RIGHT, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_UP, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_UP, NULL, FALSE },
{ META_KEYBINDING_WORKSPACE_DOWN, 0, 0, FALSE }, { META_KEYBINDING_WORKSPACE_DOWN, NULL, FALSE },
{ META_KEYBINDING_SWITCH_GROUP, 0, 0, TRUE }, { META_KEYBINDING_SWITCH_GROUP, NULL, TRUE },
{ META_KEYBINDING_SWITCH_GROUP_BACKWARD, 0, 0, TRUE }, { META_KEYBINDING_SWITCH_GROUP_BACKWARD, NULL, TRUE },
{ META_KEYBINDING_SWITCH_WINDOWS, 0, 0, TRUE }, { META_KEYBINDING_SWITCH_WINDOWS, NULL, TRUE },
{ META_KEYBINDING_SWITCH_WINDOWS_BACKWARD, 0, 0, TRUE }, { META_KEYBINDING_SWITCH_WINDOWS_BACKWARD, NULL, TRUE },
{ META_KEYBINDING_SWITCH_PANELS, 0, 0, TRUE }, { META_KEYBINDING_SWITCH_PANELS, NULL, TRUE },
{ META_KEYBINDING_SWITCH_PANELS_BACKWARD, 0, 0, TRUE }, { META_KEYBINDING_SWITCH_PANELS_BACKWARD, NULL, TRUE },
{ META_KEYBINDING_CYCLE_GROUP, 0, 0, TRUE }, { META_KEYBINDING_CYCLE_GROUP, NULL, TRUE },
{ META_KEYBINDING_CYCLE_GROUP_BACKWARD, 0, 0, TRUE }, { META_KEYBINDING_CYCLE_GROUP_BACKWARD, NULL, TRUE },
{ META_KEYBINDING_CYCLE_WINDOWS, 0, 0, TRUE }, { META_KEYBINDING_CYCLE_WINDOWS, NULL, TRUE },
{ META_KEYBINDING_CYCLE_WINDOWS_BACKWARD, 0, 0, TRUE }, { META_KEYBINDING_CYCLE_WINDOWS_BACKWARD, NULL, TRUE },
{ META_KEYBINDING_CYCLE_PANELS, 0, 0, TRUE }, { META_KEYBINDING_CYCLE_PANELS, NULL, TRUE },
{ META_KEYBINDING_CYCLE_PANELS_BACKWARD, 0, 0, TRUE }, { META_KEYBINDING_CYCLE_PANELS_BACKWARD, NULL, TRUE },
{ META_KEYBINDING_SHOW_DESKTOP, 0, 0, FALSE }, { META_KEYBINDING_SHOW_DESKTOP, NULL, FALSE },
{ META_KEYBINDING_PANEL_MAIN_MENU, 0, 0, FALSE }, { META_KEYBINDING_PANEL_MAIN_MENU, NULL, FALSE },
{ META_KEYBINDING_PANEL_RUN_DIALOG, 0, 0, FALSE }, { META_KEYBINDING_PANEL_RUN_DIALOG, NULL, FALSE },
{ META_KEYBINDING_COMMAND_1, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_1, NULL, FALSE },
{ META_KEYBINDING_COMMAND_2, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_2, NULL, FALSE },
{ META_KEYBINDING_COMMAND_3, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_3, NULL, FALSE },
{ META_KEYBINDING_COMMAND_4, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_4, NULL, FALSE },
{ META_KEYBINDING_COMMAND_5, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_5, NULL, FALSE },
{ META_KEYBINDING_COMMAND_6, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_6, NULL, FALSE },
{ META_KEYBINDING_COMMAND_7, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_7, NULL, FALSE },
{ META_KEYBINDING_COMMAND_8, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_8, NULL, FALSE },
{ META_KEYBINDING_COMMAND_9, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_9, NULL, FALSE },
{ META_KEYBINDING_COMMAND_10, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_10, NULL, FALSE },
{ META_KEYBINDING_COMMAND_11, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_11, NULL, FALSE },
{ META_KEYBINDING_COMMAND_12, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_12, NULL, FALSE },
{ META_KEYBINDING_COMMAND_13, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_13, NULL, FALSE },
{ META_KEYBINDING_COMMAND_14, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_14, NULL, FALSE },
{ META_KEYBINDING_COMMAND_15, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_15, NULL, FALSE },
{ META_KEYBINDING_COMMAND_16, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_16, NULL, FALSE },
{ META_KEYBINDING_COMMAND_17, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_17, NULL, FALSE },
{ META_KEYBINDING_COMMAND_18, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_18, NULL, FALSE },
{ META_KEYBINDING_COMMAND_19, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_19, NULL, FALSE },
{ META_KEYBINDING_COMMAND_20, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_20, NULL, FALSE },
{ META_KEYBINDING_COMMAND_21, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_21, NULL, FALSE },
{ META_KEYBINDING_COMMAND_22, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_22, NULL, FALSE },
{ META_KEYBINDING_COMMAND_23, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_23, NULL, FALSE },
{ META_KEYBINDING_COMMAND_24, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_24, NULL, FALSE },
{ META_KEYBINDING_COMMAND_25, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_25, NULL, FALSE },
{ META_KEYBINDING_COMMAND_26, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_26, NULL, FALSE },
{ META_KEYBINDING_COMMAND_27, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_27, NULL, FALSE },
{ META_KEYBINDING_COMMAND_28, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_28, NULL, FALSE },
{ META_KEYBINDING_COMMAND_29, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_29, NULL, FALSE },
{ META_KEYBINDING_COMMAND_30, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_30, NULL, FALSE },
{ META_KEYBINDING_COMMAND_31, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_31, NULL, FALSE },
{ META_KEYBINDING_COMMAND_32, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_32, NULL, FALSE },
{ META_KEYBINDING_COMMAND_SCREENSHOT, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_SCREENSHOT, NULL, FALSE },
{ META_KEYBINDING_COMMAND_WIN_SCREENSHOT, 0, 0, FALSE }, { META_KEYBINDING_COMMAND_WIN_SCREENSHOT, NULL, FALSE },
{ META_KEYBINDING_RUN_COMMAND_TERMINAL, 0, 0, FALSE }, { META_KEYBINDING_RUN_COMMAND_TERMINAL, NULL, FALSE },
{ NULL, 0, 0, FALSE} { NULL, NULL, FALSE}
}; };
static MetaKeyPref window_bindings[] = { static MetaKeyPref window_bindings[] = {
{ META_KEYBINDING_WINDOW_MENU, 0, 0, FALSE }, { META_KEYBINDING_WINDOW_MENU, NULL, FALSE },
{ META_KEYBINDING_TOGGLE_FULLSCREEN, 0, 0, FALSE }, { META_KEYBINDING_TOGGLE_FULLSCREEN, NULL, FALSE },
{ META_KEYBINDING_TOGGLE_MAXIMIZE, 0, 0, FALSE }, { META_KEYBINDING_TOGGLE_MAXIMIZE, NULL, FALSE },
{ META_KEYBINDING_TOGGLE_ABOVE, 0, 0, FALSE }, { META_KEYBINDING_TOGGLE_ABOVE, NULL, FALSE },
{ META_KEYBINDING_MAXIMIZE, 0, 0, FALSE }, { META_KEYBINDING_MAXIMIZE, NULL, FALSE },
{ META_KEYBINDING_UNMAXIMIZE, 0, 0, FALSE }, { META_KEYBINDING_UNMAXIMIZE, NULL, FALSE },
{ META_KEYBINDING_TOGGLE_SHADE, 0, 0, FALSE }, { META_KEYBINDING_TOGGLE_SHADE, NULL, FALSE },
{ META_KEYBINDING_MINIMIZE, 0, 0, FALSE }, { META_KEYBINDING_MINIMIZE, NULL, FALSE },
{ META_KEYBINDING_CLOSE, 0, 0, FALSE }, { META_KEYBINDING_CLOSE, NULL, FALSE },
{ META_KEYBINDING_BEGIN_MOVE, 0, 0, FALSE }, { META_KEYBINDING_BEGIN_MOVE, NULL, FALSE },
{ META_KEYBINDING_BEGIN_RESIZE, 0, 0, FALSE }, { META_KEYBINDING_BEGIN_RESIZE, NULL, FALSE },
{ META_KEYBINDING_TOGGLE_STICKY, 0, 0, FALSE }, { META_KEYBINDING_TOGGLE_STICKY, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_1, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_1, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_2, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_2, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_3, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_3, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_4, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_4, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_5, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_5, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_6, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_6, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_7, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_7, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_8, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_8, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_9, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_9, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_10, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_10, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_11, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_11, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_12, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_12, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_LEFT, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_LEFT, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_RIGHT, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_RIGHT, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_UP, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_UP, NULL, FALSE },
{ META_KEYBINDING_MOVE_WORKSPACE_DOWN, 0, 0, FALSE }, { META_KEYBINDING_MOVE_WORKSPACE_DOWN, NULL, FALSE },
{ META_KEYBINDING_RAISE_OR_LOWER, 0, 0, FALSE }, { META_KEYBINDING_RAISE_OR_LOWER, NULL, FALSE },
{ META_KEYBINDING_RAISE, 0, 0, FALSE }, { META_KEYBINDING_RAISE, NULL, FALSE },
{ META_KEYBINDING_LOWER, 0, 0, FALSE }, { META_KEYBINDING_LOWER, NULL, FALSE },
{ META_KEYBINDING_MAXIMIZE_VERTICALLY, 0, 0, FALSE }, { META_KEYBINDING_MAXIMIZE_VERTICALLY, NULL, FALSE },
{ META_KEYBINDING_MAXIMIZE_HORIZONTALLY, 0, 0, FALSE }, { META_KEYBINDING_MAXIMIZE_HORIZONTALLY, NULL, FALSE },
{ NULL, 0, 0, FALSE } { NULL, NULL, FALSE }
}; };
#ifndef HAVE_GCONF #ifndef HAVE_GCONF
@ -1900,6 +1956,7 @@ init_bindings (void)
i = 0; i = 0;
while (window_bindings[i].name) while (window_bindings[i].name)
{ {
GSList *list_val, *tmp;
char *str_val; char *str_val;
char *key; char *key;
@ -1915,12 +1972,33 @@ init_bindings (void)
g_free (str_val); g_free (str_val);
g_free (key); g_free (key);
key = g_strconcat (KEY_WINDOW_BINDINGS_PREFIX, "/",
window_bindings[i].name,
KEY_LIST_BINDINGS_SUFFIX, NULL);
err = NULL;
list_val = gconf_client_get_list (default_client, key, GCONF_VALUE_STRING, &err);
cleanup_error (&err);
update_list_binding (&window_bindings[i], list_val, META_LIST_OF_STRINGS);
tmp = list_val;
while (tmp)
{
g_free (tmp->data);
tmp = tmp->next;
}
g_slist_free (list_val);
g_free (key);
++i; ++i;
} }
i = 0; i = 0;
while (screen_bindings[i].name) while (screen_bindings[i].name)
{ {
GSList *list_val, *tmp;
char *str_val; char *str_val;
char *key; char *key;
@ -1936,6 +2014,26 @@ init_bindings (void)
g_free (str_val); g_free (str_val);
g_free (key); g_free (key);
key = g_strconcat (KEY_SCREEN_BINDINGS_PREFIX, "/",
screen_bindings[i].name,
KEY_LIST_BINDINGS_SUFFIX, NULL);
err = NULL;
list_val = gconf_client_get_list (default_client, key, GCONF_VALUE_STRING, &err);
cleanup_error (&err);
update_list_binding (&screen_bindings[i], list_val, META_LIST_OF_STRINGS);
tmp = list_val;
while (tmp)
{
g_free (tmp->data);
tmp = tmp->next;
}
g_slist_free (list_val);
g_free (key);
++i; ++i;
} }
#else /* HAVE_GCONF */ #else /* HAVE_GCONF */
@ -2054,6 +2152,7 @@ update_binding (MetaKeyPref *binding,
{ {
unsigned int keysym; unsigned int keysym;
MetaVirtualModifier mods; MetaVirtualModifier mods;
MetaKeyCombo *combo;
gboolean changed; gboolean changed;
meta_topic (META_DEBUG_KEYBINDINGS, meta_topic (META_DEBUG_KEYBINDINGS,
@ -2075,6 +2174,16 @@ update_binding (MetaKeyPref *binding,
} }
} }
/* If there isn't already a first element, make one. */
if (!binding->bindings)
{
MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
binding->bindings = g_slist_alloc();
binding->bindings->data = blank;
}
combo = binding->bindings->data;
/* Bug 329676: Bindings which can be shifted must not have no modifiers, /* Bug 329676: Bindings which can be shifted must not have no modifiers,
* nor only SHIFT as a modifier. * nor only SHIFT as a modifier.
*/ */
@ -2093,8 +2202,8 @@ update_binding (MetaKeyPref *binding,
value); value);
old_setting = meta_ui_accelerator_name( old_setting = meta_ui_accelerator_name(
binding->keysym, combo->keysym,
binding->modifiers); combo->modifiers);
if (!strcmp(old_setting, value)) if (!strcmp(old_setting, value))
{ {
@ -2136,17 +2245,17 @@ update_binding (MetaKeyPref *binding,
} }
changed = FALSE; changed = FALSE;
if (keysym != binding->keysym || if (keysym != combo->keysym ||
mods != binding->modifiers) mods != combo->modifiers)
{ {
changed = TRUE; changed = TRUE;
binding->keysym = keysym; combo->keysym = keysym;
binding->modifiers = mods; combo->modifiers = mods;
meta_topic (META_DEBUG_KEYBINDINGS, meta_topic (META_DEBUG_KEYBINDINGS,
"New keybinding for \"%s\" is keysym = 0x%x mods = 0x%x\n", "New keybinding for \"%s\" is keysym = 0x%x mods = 0x%x\n",
binding->name, binding->keysym, binding->modifiers); binding->name, combo->keysym, combo->modifiers);
} }
else else
{ {
@ -2157,6 +2266,115 @@ update_binding (MetaKeyPref *binding,
return changed; return changed;
} }
static gboolean
update_list_binding (MetaKeyPref *binding,
GSList *value,
MetaStringListType type_of_value)
{
unsigned int keysym;
MetaVirtualModifier mods;
gboolean changed = FALSE;
const gchar *pref_string;
GSList *pref_iterator = value, *tmp;
MetaKeyCombo *combo;
meta_topic (META_DEBUG_KEYBINDINGS,
"Binding \"%s\" has new gconf value\n",
binding->name);
if (binding->bindings == NULL)
{
/* We need to insert a dummy element into the list, because the first
* element is the one governed by update_binding. We only handle the
* subsequent elements.
*/
MetaKeyCombo *blank = g_malloc0 (sizeof (MetaKeyCombo));
binding->bindings = g_slist_alloc();
binding->bindings->data = blank;
}
/* Okay, so, we're about to provide a new list of key combos for this
* action. Delete any pre-existing list.
*/
tmp = binding->bindings->next;
while (tmp)
{
g_free (tmp->data);
tmp = tmp->next;
}
g_slist_free (binding->bindings->next);
binding->bindings->next = NULL;
while (pref_iterator)
{
keysym = 0;
mods = 0;
if (!pref_iterator->data)
{
pref_iterator = pref_iterator->next;
continue;
}
switch (type_of_value)
{
case META_LIST_OF_STRINGS:
pref_string = pref_iterator->data;
break;
case META_LIST_OF_GCONFVALUE_STRINGS:
pref_string = gconf_value_get_string (pref_iterator->data);
break;
default:
g_assert_not_reached ();
}
if (!meta_ui_parse_accelerator (pref_string, &keysym, &mods))
{
meta_topic (META_DEBUG_KEYBINDINGS,
"Failed to parse new gconf value\n");
meta_warning (_("\"%s\" found in configuration database is not a valid value for keybinding \"%s\"\n"),
pref_string, binding->name);
/* Should we remove this value from the list in gconf? */
pref_iterator = pref_iterator->next;
continue;
}
/* Bug 329676: Bindings which can be shifted must not have no modifiers,
* nor only SHIFT as a modifier.
*/
if (binding->add_shift &&
0 != keysym &&
(META_VIRTUAL_SHIFT_MASK == mods || 0 == mods))
{
meta_warning ("Cannot bind \"%s\" to %s: it needs a modifier "
"such as Ctrl or Alt.\n",
binding->name,
pref_string);
/* Should we remove this value from the list in gconf? */
pref_iterator = pref_iterator->next;
continue;
}
changed = TRUE;
combo = g_malloc0 (sizeof (MetaKeyCombo));
combo->keysym = keysym;
combo->modifiers = mods;
binding->bindings->next = g_slist_prepend (binding->bindings->next, combo);
meta_topic (META_DEBUG_KEYBINDINGS,
"New keybinding for \"%s\" is keysym = 0x%x mods = 0x%x\n",
binding->name, keysym, mods);
pref_iterator = pref_iterator->next;
}
return changed;
}
#ifdef HAVE_GCONF #ifdef HAVE_GCONF
static const gchar* static const gchar*
relative_key (const gchar* key) relative_key (const gchar* key)
@ -2211,6 +2429,50 @@ update_screen_binding (const char *name,
return find_and_update_binding (screen_bindings, name, value); return find_and_update_binding (screen_bindings, name, value);
} }
static gboolean
find_and_update_list_binding (MetaKeyPref *bindings,
const char *name,
GSList *value)
{
const char *key;
int i;
gchar *name_without_suffix = g_strdup(name);
name_without_suffix[strlen(name_without_suffix) - strlen(KEY_LIST_BINDINGS_SUFFIX)] = 0;
/* FIXME factor out dupld code */
if (*name_without_suffix == '/')
key = relative_key (name_without_suffix);
else
key = name_without_suffix;
i = 0;
while (bindings[i].name &&
strcmp (key, bindings[i].name) != 0)
++i;
g_free (name_without_suffix);
if (bindings[i].name)
return update_list_binding (&bindings[i], value, META_LIST_OF_GCONFVALUE_STRINGS);
else
return FALSE;
}
static gboolean
update_window_list_binding (const char *name,
GSList *value)
{
return find_and_update_list_binding (window_bindings, name, value);
}
static gboolean
update_screen_list_binding (const char *name,
GSList *value)
{
return find_and_update_list_binding (screen_bindings, name, value);
}
static gboolean static gboolean
update_command (const char *name, update_command (const char *name,
const char *value) const char *value)
@ -2598,6 +2860,10 @@ meta_prefs_get_keybinding_action (const char *name)
return META_KEYBINDING_ACTION_NONE; return META_KEYBINDING_ACTION_NONE;
} }
/* This is used by the menu system to decide what key binding
* to display next to an option. We return the first non-disabled
* binding, if any.
*/
void void
meta_prefs_get_window_binding (const char *name, meta_prefs_get_window_binding (const char *name,
unsigned int *keysym, unsigned int *keysym,
@ -2610,8 +2876,24 @@ meta_prefs_get_window_binding (const char *name,
{ {
if (strcmp (window_bindings[i].name, name) == 0) if (strcmp (window_bindings[i].name, name) == 0)
{ {
*keysym = window_bindings[i].keysym; GSList *s = window_bindings[i].bindings;
*modifiers = window_bindings[i].modifiers;
while (s)
{
MetaKeyCombo *c = s->data;
if (c->keysym!=0 || c->modifiers!=0)
{
*keysym = c->keysym;
*modifiers = c->modifiers;
return;
}
s = s->next;
}
/* Not found; return the disabled value */
*keysym = *modifiers = 0;
return; return;
} }

View File

@ -256,9 +256,21 @@ typedef enum _MetaKeyBindingAction
typedef struct typedef struct
{ {
const char *name;
unsigned int keysym; unsigned int keysym;
MetaVirtualModifier modifiers; MetaVirtualModifier modifiers;
} MetaKeyCombo;
typedef struct
{
const char *name;
/* a list of MetaKeyCombos. Each of them is bound to
* this keypref. If one has keysym==modifiers==0, it is
* ignored. For historical reasons, the first entry is
* governed by the pref FOO and the remainder are
* governed by the pref FOO_list.
*/
GSList *bindings;
/* for keybindings that can have shift or not like Alt+Tab */ /* for keybindings that can have shift or not like Alt+Tab */
gboolean add_shift; gboolean add_shift;
} MetaKeyPref; } MetaKeyPref;