Description: add support for “org.gnome.desktop.input-sources current” key
 This key is deprecated, but still used by indicator-keyboard.
 .
 Now the indices of GfInputSources are not necessarily continuous, and
 correspond to their indices in the “input-methods” list in GSettings.
Author: Dmitry Shachnev <mitya57@ubuntu.com>
Forwarded: not-needed
Last-Update: 2020-02-12

--- a/gnome-flashback/libinput-sources/gf-input-source-manager.c
+++ b/gnome-flashback/libinput-sources/gf-input-source-manager.c
@@ -404,6 +404,9 @@
 
   info = (SourceInfo *) data;
 
+  if (info == NULL)
+    return;
+
   g_free (info->type);
   g_free (info->id);
 
@@ -501,6 +504,7 @@
 {
   GfInputSourceManager *manager;
   guint size;
+  GList *keys;
 
   manager = GF_INPUT_SOURCE_MANAGER (user_data);
 
@@ -511,6 +515,9 @@
       return TRUE;
     }
 
+  keys = g_hash_table_get_keys (manager->input_sources);
+  keys = g_list_sort (keys, compare_indexes);
+
   if (keybinding_type == GF_KEYBINDING_ISO_NEXT_GROUP)
     {
       gf_input_source_manager_activate_next_source (manager);
@@ -520,20 +527,16 @@
       GfInputSource *first_source;
 
       first_source = g_hash_table_lookup (manager->input_sources,
-                                          GUINT_TO_POINTER (0));
+                                          keys->data);
 
       gf_input_source_activate (first_source, TRUE);
     }
   else if (keybinding_type == GF_KEYBINDING_ISO_LAST_GROUP)
     {
-      GList *keys;
       GfInputSource *last_source;
 
-      keys = g_hash_table_get_keys (manager->input_sources);
-      keys = g_list_sort (keys, compare_indexes);
-
       last_source = g_hash_table_lookup (manager->input_sources,
-                                         g_list_nth_data (keys, size - 1));
+                                         g_list_last (keys)->data);
 
       gf_input_source_activate (last_source, TRUE);
       g_list_free (keys);
@@ -674,19 +677,24 @@
           IBusEngineDesc *engine_desc;
 
           if (manager->disable_ibus)
-            continue;
+            {
+              list = g_list_append (list, NULL);
+              continue;
+            }
 
           engine_desc = gf_ibus_manager_get_engine_desc (manager->ibus_manager,
                                                          id);
 
           if (engine_desc == NULL)
-            continue;
+            {
+              list = g_list_append (list, NULL);
+              continue;
+            }
 
           info = source_info_new (type, id);
         }
 
-      if (info != NULL)
-        list = g_list_append (list, info);
+      list = g_list_append (list, info);
     }
 
   g_variant_unref (sources);
@@ -1057,6 +1065,7 @@
   GList *l;
   GHashTable *sources_by_name;
   guint length;
+  guint i;
   gchar **ids;
 
   manager = GF_INPUT_SOURCE_MANAGER (user_data);
@@ -1090,6 +1099,9 @@
       GfInputSource *source;
 
       info = (SourceInfo *) l->data;
+      if (info == NULL)
+        continue;
+
       position = g_list_position (source_infos, l);
 
       if (g_strcmp0 (info->type, INPUT_SOURCE_TYPE_IBUS) == 0)
@@ -1134,7 +1146,10 @@
   g_signal_emit (manager, signals[SIGNAL_SOURCES_CHANGED], 0);
 
   gf_keyboard_manager_set_user_layouts (manager->keyboard_manager, ids);
-  g_strfreev (ids);
+
+  for (i = 0; i < length; ++i)
+    if (ids[i] != NULL)
+      g_free (ids[i]);
 
   update_mru_sources_list (manager);
 
@@ -1201,6 +1216,23 @@
 }
 
 static void
+current_changed_cb (GfInputSourceSettings *settings,
+                    gpointer               user_data)
+{
+  GfInputSourceManager *manager;
+  GfInputSource *source;
+  guint new_current;
+
+  manager = GF_INPUT_SOURCE_MANAGER (user_data);
+  new_current = gf_input_source_settings_get_current (settings);
+
+  source = (GfInputSource *) g_hash_table_lookup (manager->input_sources,
+                                                  GUINT_TO_POINTER (new_current));
+  if (source != manager->current_source)
+    gf_input_source_activate (source, TRUE);
+}
+
+static void
 input_source_settings_init (GfInputSourceManager *manager)
 {
   manager->settings = gf_input_source_settings_new ();
@@ -1211,6 +1243,8 @@
                     G_CALLBACK (xkb_options_changed_cb), manager);
   g_signal_connect (manager->settings, "per-window-changed",
                     G_CALLBACK (per_window_changed_cb), manager);
+  g_signal_connect (manager->settings, "current-changed",
+                    G_CALLBACK (current_changed_cb), manager);
 
   per_window_changed_cb (manager->settings, manager);
 }
@@ -1589,8 +1623,10 @@
   guint size;
   GList *keys;
   GfInputSource *current_source;
-  guint next_index;
   GfInputSource *next_source;
+  GList *current_key;
+  GList *next_key;
+  guint current_index;
 
   size = g_hash_table_size (manager->input_sources);
   if (size == 0)
@@ -1603,15 +1639,29 @@
 
   if (current_source == NULL)
     current_source = g_hash_table_lookup (manager->input_sources,
-                                          GUINT_TO_POINTER (0));
+                                          keys->data);
 
-  next_index = gf_input_source_get_index (current_source) + 1;
-  if (next_index > GPOINTER_TO_UINT (g_list_nth_data (keys, size - 1)))
-    next_index = 0;
+  current_index = gf_input_source_get_index (current_source);
+  current_key = g_list_find (keys, GUINT_TO_POINTER (current_index));
+  next_key = g_list_next (current_key);
+  if (!next_key)
+    next_key = keys;
 
   next_source = g_hash_table_lookup (manager->input_sources,
-                                     GUINT_TO_POINTER (next_index));
+                                     next_key->data);
 
   gf_input_source_activate (next_source, TRUE);
   g_list_free (keys);
 }
+
+void
+gf_input_source_manager_write_current (GfInputSourceManager *manager)
+{
+  guint index;
+
+  if (manager->current_source != NULL)
+    {
+      index = gf_input_source_get_index (manager->current_source);
+      gf_input_source_settings_set_current (manager->settings, index);
+    }
+}
--- a/gnome-flashback/libinput-sources/gf-input-source-manager.h
+++ b/gnome-flashback/libinput-sources/gf-input-source-manager.h
@@ -36,4 +36,6 @@
 
 void                  gf_input_source_manager_activate_next_source (GfInputSourceManager *manager);
 
+void                  gf_input_source_manager_write_current      (GfInputSourceManager *manager);
+
 #endif
--- a/gnome-flashback/libinput-sources/gf-input-source-settings.c
+++ b/gnome-flashback/libinput-sources/gf-input-source-settings.c
@@ -27,6 +27,7 @@
 #define KEY_MRU_SOURCES "mru-sources"
 #define KEY_XKB_OPTIONS "xkb-options"
 #define KEY_PER_WINDOW "per-window"
+#define KEY_CURRENT "current"
 
 struct _GfInputSourceSettings
 {
@@ -40,6 +41,7 @@
   SIGNAL_SOURCES_CHANGED,
   SIGNAL_XKB_OPTIONS_CHANGED,
   SIGNAL_PER_WINDOW_CHANGED,
+  SIGNAL_CURRENT_CHANGED,
 
   LAST_SIGNAL
 };
@@ -63,6 +65,8 @@
     g_signal_emit (source_settings, signals[SIGNAL_XKB_OPTIONS_CHANGED], 0);
   else if (g_strcmp0 (key, KEY_PER_WINDOW) == 0)
     g_signal_emit (source_settings, signals[SIGNAL_PER_WINDOW_CHANGED], 0);
+  else if (g_strcmp0 (key, KEY_CURRENT) == 0)
+    g_signal_emit (source_settings, signals[SIGNAL_CURRENT_CHANGED], 0);
 }
 
 static void
@@ -118,6 +122,17 @@
   signals[SIGNAL_PER_WINDOW_CHANGED] =
     g_signal_new ("per-window-changed", G_TYPE_FROM_CLASS (settings_class),
                   G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+
+  /**
+   * GfInputSourceSettings::current-changed:
+   * @settings: the object on which the signal is emitted
+   *
+   * The ::current-changed signal is emitted each time when current
+   * setting has changed.
+   */
+  signals[SIGNAL_CURRENT_CHANGED] =
+    g_signal_new ("current-changed", G_TYPE_FROM_CLASS (settings_class),
+                  G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
 }
 
 static void
@@ -205,3 +220,16 @@
 {
   return g_settings_get_boolean (settings->settings, KEY_PER_WINDOW);
 }
+
+guint
+gf_input_source_settings_get_current (GfInputSourceSettings *settings)
+{
+  return g_settings_get_uint (settings->settings, KEY_CURRENT);
+}
+
+void
+gf_input_source_settings_set_current (GfInputSourceSettings *settings,
+                                      guint                  current)
+{
+  g_settings_set_uint (settings->settings, KEY_CURRENT, current);
+}
--- a/gnome-flashback/libinput-sources/gf-input-source-settings.h
+++ b/gnome-flashback/libinput-sources/gf-input-source-settings.h
@@ -39,6 +39,11 @@
 
 gboolean                gf_input_source_settings_get_per_window  (GfInputSourceSettings *settings);
 
+void                    gf_input_source_settings_set_current     (GfInputSourceSettings *settings,
+                                                                  guint                  current);
+
+guint                   gf_input_source_settings_get_current     (GfInputSourceSettings *settings);
+
 G_END_DECLS
 
 #endif
--- a/gnome-flashback/libinput-sources/gf-input-sources.c
+++ b/gnome-flashback/libinput-sources/gf-input-sources.c
@@ -57,6 +57,7 @@
   g_clear_object (&sources->current_source);
   sources->current_source = g_object_ref (source);
 
+  gf_input_source_manager_write_current (manager);
   gf_input_sources_gen_emit_changed (sources->input_sources);
 }
 
