197 lines
6.6 KiB
Diff
197 lines
6.6 KiB
Diff
Index: gnome-settings-daemon-2.27.4/plugins/keyboard/gsd-keyboard-xkb.c
|
|
===================================================================
|
|
--- gnome-settings-daemon-2.27.4.orig/plugins/keyboard/gsd-keyboard-xkb.c
|
|
+++ gnome-settings-daemon-2.27.4/plugins/keyboard/gsd-keyboard-xkb.c
|
|
@@ -137,6 +137,103 @@ apply_desktop_settings (void)
|
|
gkbd_desktop_config_activate (¤t_config);
|
|
}
|
|
|
|
+#define GROUP_SWITCHERS_GROUP "grp"
|
|
+#define DEFAULT_GROUP_SWITCH "grp:shifts_toggle"
|
|
+
|
|
+static void
|
|
+_maybe_add_layout_switcher (GSList *layouts,
|
|
+ GConfClient *conf_client)
|
|
+{
|
|
+ GSList *options;
|
|
+ GSList *option;
|
|
+ gboolean any_switcher;
|
|
+
|
|
+ /* do we have more than one layout? */
|
|
+ if (g_slist_length (layouts) > 1)
|
|
+ return;
|
|
+
|
|
+ /* If yes, we need to make sure there's a way to change the layout
|
|
+ * Based on xkl_layout_chooser_add_default_switcher_if_necessary() in
|
|
+ * capplets/keyboard/gnome-keyboard-properties-xkbltadd.c
|
|
+ * (gnome-control-center) */
|
|
+ options = gconf_client_get_list (conf_client,
|
|
+ GKBD_KEYBOARD_CONFIG_KEY_OPTIONS,
|
|
+ GCONF_VALUE_STRING,
|
|
+ NULL);
|
|
+
|
|
+ if (options == NULL) {
|
|
+ /* nothing in gconf, get the current options from X */
|
|
+ GkbdKeyboardConfig kbd_config;
|
|
+
|
|
+ gkbd_keyboard_config_init (&kbd_config,
|
|
+ conf_client,
|
|
+ xkl_engine);
|
|
+ gkbd_keyboard_config_load_from_x_initial (&kbd_config, NULL);
|
|
+
|
|
+ for (option = kbd_config.options; option != NULL; option = option->next) {
|
|
+ options = g_slist_prepend (options,
|
|
+ g_strdup (option->data));
|
|
+ }
|
|
+
|
|
+ options = g_slist_reverse (options);
|
|
+
|
|
+ gkbd_keyboard_config_term (&kbd_config);
|
|
+ }
|
|
+
|
|
+ any_switcher = FALSE;
|
|
+
|
|
+ while (option != NULL) {
|
|
+ char *g, *o;
|
|
+
|
|
+ if (gkbd_keyboard_config_split_items (option->data, &g, &o)) {
|
|
+ if (!g_ascii_strcasecmp (g, GROUP_SWITCHERS_GROUP)) {
|
|
+ any_switcher = TRUE;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ option = option->next;
|
|
+ }
|
|
+
|
|
+ /* no option to switch between layouts, let's add one */
|
|
+ if (!any_switcher) {
|
|
+ XklConfigItem *ci = xkl_config_item_new ();
|
|
+
|
|
+ g_snprintf (ci->name, XKL_MAX_CI_NAME_LENGTH,
|
|
+ DEFAULT_GROUP_SWITCH);
|
|
+
|
|
+ /* we make sure the option we want to add is known */
|
|
+ if (!xkl_registry) {
|
|
+ xkl_registry = xkl_config_registry_get_instance (xkl_engine);
|
|
+ if (!xkl_config_registry_load (xkl_registry, TRUE)) {
|
|
+ g_object_unref (xkl_registry);
|
|
+ xkl_registry = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (xkl_registry &&
|
|
+ xkl_config_registry_find_option (xkl_registry,
|
|
+ GROUP_SWITCHERS_GROUP,
|
|
+ ci)) {
|
|
+ const char *id;
|
|
+
|
|
+ id = gkbd_keyboard_config_merge_items
|
|
+ (GROUP_SWITCHERS_GROUP,
|
|
+ DEFAULT_GROUP_SWITCH);
|
|
+
|
|
+ options = g_slist_append (options, g_strdup (id));
|
|
+ gconf_client_set_list (conf_client,
|
|
+ GKBD_KEYBOARD_CONFIG_KEY_OPTIONS,
|
|
+ GCONF_VALUE_STRING, options,
|
|
+ NULL);
|
|
+ }
|
|
+
|
|
+ g_object_unref (G_OBJECT (ci));
|
|
+ }
|
|
+
|
|
+ g_slist_foreach (options, (GFunc) g_free, NULL);
|
|
+ g_slist_free (options);
|
|
+}
|
|
+
|
|
static gboolean
|
|
try_activating_xkb_config_if_new (GkbdKeyboardConfig *current_sys_kbd_config)
|
|
{
|
|
@@ -211,6 +308,38 @@ filter_xkb_config (void)
|
|
return any_change;
|
|
}
|
|
|
|
+static int
|
|
+_xkb_layout_strcmp (const char *a,
|
|
+ const char *b)
|
|
+{
|
|
+ char *layout_a;
|
|
+ char *layout_b;
|
|
+ char *p;
|
|
+ int ret;
|
|
+
|
|
+ if (!a)
|
|
+ return -(a != b);
|
|
+ if (!b)
|
|
+ return (a != b);
|
|
+
|
|
+ layout_a = g_strdup (a);
|
|
+ p = strchr (layout_a, '\t');
|
|
+ if (p != NULL)
|
|
+ p[0] = '\0';
|
|
+
|
|
+ layout_b = g_strdup (b);
|
|
+ p = strchr (layout_b, '\t');
|
|
+ if (p != NULL)
|
|
+ p[0] = '\0';
|
|
+
|
|
+ ret = strcmp (layout_a, layout_b);
|
|
+
|
|
+ g_free (layout_a);
|
|
+ g_free (layout_b);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static void
|
|
apply_xkb_settings (void)
|
|
{
|
|
@@ -233,18 +362,44 @@ apply_xkb_settings (void)
|
|
gdm_keyboard_layout = NULL;
|
|
if (gdm_layout != NULL) {
|
|
GSList *layouts;
|
|
+ GSList *found_node;
|
|
+
|
|
layouts = gconf_client_get_list (conf_client,
|
|
GKBD_KEYBOARD_CONFIG_KEY_LAYOUTS,
|
|
GCONF_VALUE_STRING, NULL);
|
|
- if (layouts == NULL) {
|
|
- layouts =
|
|
- g_slist_append (layouts,
|
|
- g_strdup (gdm_layout));
|
|
+
|
|
+ /* Add the layout if it doesn't already exist. XKB limits the
|
|
+ * total number of layouts to four. If we already have four
|
|
+ * layouts configured, we replace the last one. This prevents the
|
|
+ * list from becoming full if the user has a habit of selecting
|
|
+ * many different keyboard layouts in GDM. */
|
|
+
|
|
+ found_node = g_slist_find_custom (layouts, gdm_layout, _xkb_layout_strcmp);
|
|
+
|
|
+ if (found_node) {
|
|
+ if (g_slist_position (layouts, found_node) > 3) {
|
|
+ /* If the layout we found appears after the
|
|
+ * fourth entry, we move it up to fourth place.
|
|
+ * Otherwise, XKB will not activate it. */
|
|
+ g_free (found_node->data);
|
|
+ layouts = g_slist_delete_link (layouts, found_node);
|
|
+ found_node = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!found_node) {
|
|
+ /* Insert in fourth slot or at the end of list,
|
|
+ * whichever comes first */
|
|
+ layouts = g_slist_insert (layouts, g_strdup (gdm_layout), 3);
|
|
+
|
|
+ _maybe_add_layout_switcher (layouts, conf_client);
|
|
+
|
|
gconf_client_set_list (conf_client,
|
|
GKBD_KEYBOARD_CONFIG_KEY_LAYOUTS,
|
|
GCONF_VALUE_STRING, layouts,
|
|
NULL);
|
|
}
|
|
+
|
|
g_slist_foreach (layouts, (GFunc) g_free, NULL);
|
|
g_slist_free (layouts);
|
|
}
|