[gnome-control-center] region: Create classes for input sources



commit 9c655bfba0ab2929dae527b606cc64e13c96557f
Author: Robert Ancell <robert ancell canonical com>
Date:   Wed Sep 12 10:33:06 2018 +1200

    region: Create classes for input sources

 panels/region/cc-input-chooser.c     |  27 ++--
 panels/region/cc-input-chooser.h     |   7 +-
 panels/region/cc-input-row.c         |  64 +++------
 panels/region/cc-input-row.h         |  18 +--
 panels/region/cc-input-source-ibus.c | 155 +++++++++++++++++++++
 panels/region/cc-input-source-ibus.h |  46 +++++++
 panels/region/cc-input-source-xkb.c  | 134 ++++++++++++++++++
 panels/region/cc-input-source-xkb.h  |  39 ++++++
 panels/region/cc-input-source.c      |  84 ++++++++++++
 panels/region/cc-input-source.h      |  49 +++++++
 panels/region/cc-region-panel.c      | 254 ++++++++++++-----------------------
 panels/region/meson.build            |   3 +
 12 files changed, 632 insertions(+), 248 deletions(-)
---
diff --git a/panels/region/cc-input-chooser.c b/panels/region/cc-input-chooser.c
index af22e8b9f..f08e1fb5b 100644
--- a/panels/region/cc-input-chooser.c
+++ b/panels/region/cc-input-chooser.c
@@ -26,6 +26,8 @@
 #include "cc-common-language.h"
 #include "cc-util.h"
 #include "cc-input-chooser.h"
+#include "cc-input-source-ibus.h"
+#include "cc-input-source-xkb.h"
 
 #ifdef HAVE_IBUS
 #include <ibus.h>
@@ -1072,31 +1074,28 @@ cc_input_chooser_set_ibus_engines (CcInputChooser *self,
 #endif  /* HAVE_IBUS */
 }
 
-gboolean
-cc_input_chooser_get_selected (CcInputChooser *self,
-                               gchar         **type,
-                               gchar         **id,
-                               gchar         **name)
+CcInputSource *
+cc_input_chooser_get_source (CcInputChooser *self)
 {
   GtkListBoxRow *selected;
-  const gchar *t, *i, *n;
+  const gchar *t, *i;
 
   g_return_val_if_fail (CC_IS_INPUT_CHOOSER (self), FALSE);
 
   selected = gtk_list_box_get_selected_row (self->input_sources_listbox);
   if (!selected)
-    return FALSE;
+    return NULL;
 
   t = g_object_get_data (G_OBJECT (selected), "type");
   i = g_object_get_data (G_OBJECT (selected), "id");
-  n = g_object_get_data (G_OBJECT (selected), "name");
 
-  if (!t || !i || !n)
+  if (!t || !i)
     return FALSE;
 
-  *type = g_strdup (t);
-  *id = g_strdup (i);
-  *name = g_strdup (n);
-
-  return TRUE;
+  if (g_strcmp0 (t, "xkb") == 0)
+    return CC_INPUT_SOURCE (cc_input_source_xkb_new_from_id (self->xkb_info, i));
+  else if (g_strcmp0 (t, "ibus") == 0)
+    return CC_INPUT_SOURCE (cc_input_source_ibus_new (i));
+  else
+    return NULL;
 }
diff --git a/panels/region/cc-input-chooser.h b/panels/region/cc-input-chooser.h
index bc75d9299..836378266 100644
--- a/panels/region/cc-input-chooser.h
+++ b/panels/region/cc-input-chooser.h
@@ -19,6 +19,8 @@
 
 #include <gtk/gtk.h>
 
+#include "cc-input-source.h"
+
 #define GNOME_DESKTOP_USE_UNSTABLE_API
 #include <libgnome-desktop/gnome-xkb-info.h>
 
@@ -34,9 +36,6 @@ CcInputChooser *cc_input_chooser_new              (gboolean       is_login,
 void            cc_input_chooser_set_ibus_engines (CcInputChooser *chooser,
                                                    GHashTable     *ibus_engines);
 
-gboolean        cc_input_chooser_get_selected     (CcInputChooser *chooser,
-                                                   gchar         **type,
-                                                   gchar         **id,
-                                                   gchar         **name);
+CcInputSource  *cc_input_chooser_get_source       (CcInputChooser *chooser);
 
 G_END_DECLS
diff --git a/panels/region/cc-input-row.c b/panels/region/cc-input-row.c
index 86b452dee..c3d269bf6 100644
--- a/panels/region/cc-input-row.c
+++ b/panels/region/cc-input-row.c
@@ -17,14 +17,13 @@
 
 #include <config.h>
 #include "cc-input-row.h"
+#include "cc-input-source-ibus.h"
 
 struct _CcInputRow
 {
   GtkListBoxRow    parent_instance;
 
-  gchar           *type;
-  gchar           *id;
-  GDesktopAppInfo *app_info;
+  CcInputSource   *source;
 
   GtkWidget       *name_label;
   GtkWidget       *icon_image;
@@ -37,9 +36,7 @@ cc_input_row_dispose (GObject *object)
 {
   CcInputRow *self = CC_INPUT_ROW (object);
 
-  g_clear_pointer (&self->type, g_free);
-  g_clear_pointer (&self->id, g_free);
-  g_clear_object (&self->app_info);
+  g_clear_object (&self->source);
 
   G_OBJECT_CLASS (cc_input_row_parent_class)->dispose (object);
 }
@@ -63,55 +60,32 @@ cc_input_row_init (CcInputRow *row)
   gtk_widget_init_template (GTK_WIDGET (row));
 }
 
+static void
+label_changed_cb (CcInputRow *row)
+{
+  g_autofree gchar *label = cc_input_source_get_label (row->source);
+  gtk_label_set_text (GTK_LABEL (row->name_label), label);
+}
+
 CcInputRow *
-cc_input_row_new (const gchar     *type,
-                  const gchar     *id,
-                  GDesktopAppInfo *app_info)
+cc_input_row_new (CcInputSource *source)
 {
   CcInputRow *row;
 
   row = g_object_new (CC_TYPE_INPUT_ROW, NULL);
-  row->type = g_strdup (type);
-  row->id = g_strdup (id);
-  if (app_info != NULL)
-    row->app_info = g_object_ref (app_info);
+  row->source = g_object_ref (source);
 
-  return row;
-}
+  g_signal_connect_object (source, "label-changed", G_CALLBACK (label_changed_cb), row, G_CONNECT_SWAPPED);
+  label_changed_cb (row);
 
-const gchar *
-cc_input_row_get_input_type (CcInputRow *row)
-{
-  g_return_val_if_fail (CC_IS_INPUT_ROW (row), NULL);
-  return row->type;
-}
+  gtk_widget_set_visible (row->icon_image, CC_IS_INPUT_SOURCE_IBUS (source));
 
-const gchar *
-cc_input_row_get_id (CcInputRow *row)
-{
-  g_return_val_if_fail (CC_IS_INPUT_ROW (row), NULL);
-  return row->id;
+  return row;
 }
 
-GDesktopAppInfo *
-cc_input_row_get_app_info (CcInputRow *row)
+CcInputSource *
+cc_input_row_get_source (CcInputRow *row)
 {
   g_return_val_if_fail (CC_IS_INPUT_ROW (row), NULL);
-  return row->app_info;
-}
-
-void
-cc_input_row_set_label (CcInputRow  *row,
-                        const gchar *text)
-{
-  g_return_if_fail (CC_IS_INPUT_ROW (row));
-  gtk_label_set_text (GTK_LABEL (row->name_label), text);
-}
-
-void
-cc_input_row_set_is_input_method (CcInputRow  *row,
-                                  gboolean is_input_method)
-{
-  g_return_if_fail (CC_IS_INPUT_ROW (row));
-  gtk_widget_set_visible (row->icon_image, is_input_method);
+  return row->source;
 }
diff --git a/panels/region/cc-input-row.h b/panels/region/cc-input-row.h
index dba8b6158..a5c0ec62c 100644
--- a/panels/region/cc-input-row.h
+++ b/panels/region/cc-input-row.h
@@ -20,25 +20,15 @@
 #include <gtk/gtk.h>
 #include <gio/gdesktopappinfo.h>
 
+#include "cc-input-source.h"
+
 G_BEGIN_DECLS
 
 #define CC_TYPE_INPUT_ROW (cc_input_row_get_type ())
 G_DECLARE_FINAL_TYPE (CcInputRow, cc_input_row, CC, INPUT_ROW, GtkListBoxRow)
 
-CcInputRow      *cc_input_row_new                 (const gchar     *type,
-                                                   const gchar     *id,
-                                                   GDesktopAppInfo *app_info);
-
-const gchar     *cc_input_row_get_input_type      (CcInputRow      *row);
-
-const gchar     *cc_input_row_get_id              (CcInputRow      *row);
-
-GDesktopAppInfo *cc_input_row_get_app_info        (CcInputRow      *row);
-
-void             cc_input_row_set_label           (CcInputRow      *row,
-                                                   const gchar     *text);
+CcInputRow      *cc_input_row_new        (CcInputSource   *source);
 
-void             cc_input_row_set_is_input_method (CcInputRow      *row,
-                                                   gboolean         is_input_method);
+CcInputSource   *cc_input_row_get_source (CcInputRow      *row);
 
 G_END_DECLS
diff --git a/panels/region/cc-input-source-ibus.c b/panels/region/cc-input-source-ibus.c
new file mode 100644
index 000000000..1aa1ab8a2
--- /dev/null
+++ b/panels/region/cc-input-source-ibus.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright © 2018 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cc-input-source-ibus.h"
+#ifdef HAVE_IBUS
+#include "cc-ibus-utils.h"
+#endif
+
+struct _CcInputSourceIBus
+{
+  CcInputSource   parent_instance;
+
+  gchar          *engine_name;
+#ifdef HAVE_IBUS
+  IBusEngineDesc *engine_desc;
+#endif
+};
+
+G_DEFINE_TYPE (CcInputSourceIBus, cc_input_source_ibus, CC_TYPE_INPUT_SOURCE)
+
+static gchar *
+cc_input_source_ibus_get_label (CcInputSource *source)
+{
+  CcInputSourceIBus *self = CC_INPUT_SOURCE_IBUS (source);
+#ifdef HAVE_IBUS
+  if (self->engine_desc)
+    return g_strdup (engine_get_display_name (self->engine_desc));
+  else
+#endif
+    return g_strdup (self->engine_name);
+}
+
+static gboolean
+cc_input_source_ibus_matches (CcInputSource *source,
+                              CcInputSource *source2)
+{
+  if (!CC_IS_INPUT_SOURCE_IBUS (source2))
+    return FALSE;
+
+  return g_strcmp0 (CC_INPUT_SOURCE_IBUS (source)->engine_name, CC_INPUT_SOURCE_IBUS (source2)->engine_name) 
== 0;
+}
+
+static const gchar *
+cc_input_source_ibus_get_layout (CcInputSource *source)
+{
+#ifdef HAVE_IBUS
+  CcInputSourceIBus *self = CC_INPUT_SOURCE_IBUS (source);
+  if (self->engine_desc != NULL)
+    return ibus_engine_desc_get_layout (self->engine_desc);
+  else
+#endif
+    return NULL;
+}
+
+static const gchar *
+cc_input_source_ibus_get_layout_variant (CcInputSource *source)
+{
+#ifdef HAVE_IBUS
+  CcInputSourceIBus *self = CC_INPUT_SOURCE_IBUS (source);
+  if (self->engine_desc != NULL)
+    return ibus_engine_desc_get_layout_variant (self->engine_desc);
+  else
+#endif
+    return NULL;
+}
+
+static void
+cc_input_source_ibus_dispose (GObject *object)
+{
+  CcInputSourceIBus *self = CC_INPUT_SOURCE_IBUS (object);
+
+  g_clear_pointer (&self->engine_name, g_free);
+#ifdef HAVE_IBUS
+  g_clear_object (&self->engine_desc);
+#endif
+
+  G_OBJECT_CLASS (cc_input_source_ibus_parent_class)->dispose (object);
+}
+
+void
+cc_input_source_ibus_class_init (CcInputSourceIBusClass *klass)
+{
+  CcInputSourceClass *input_source_class = CC_INPUT_SOURCE_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  input_source_class->get_label = cc_input_source_ibus_get_label;
+  input_source_class->matches = cc_input_source_ibus_matches;
+  input_source_class->get_layout = cc_input_source_ibus_get_layout;
+  input_source_class->get_layout_variant = cc_input_source_ibus_get_layout_variant;
+  object_class->dispose = cc_input_source_ibus_dispose;
+}
+
+void
+cc_input_source_ibus_init (CcInputSourceIBus *source)
+{
+}
+
+CcInputSourceIBus *
+cc_input_source_ibus_new (const gchar *engine_name)
+{
+  CcInputSourceIBus *source;
+
+  source = g_object_new (CC_TYPE_INPUT_SOURCE_IBUS, NULL);
+  source->engine_name = g_strdup (engine_name);
+
+  return source;
+}
+
+#ifdef HAVE_IBUS
+void
+cc_input_source_ibus_set_engine_desc (CcInputSourceIBus *source,
+                                      IBusEngineDesc    *engine_desc)
+{
+  g_return_if_fail (CC_IS_INPUT_SOURCE_IBUS (source));
+
+  g_clear_object (&source->engine_desc);
+  source->engine_desc = g_object_ref (engine_desc);
+  cc_input_source_emit_label_changed (CC_INPUT_SOURCE (source));
+}
+#endif
+
+const gchar *
+cc_input_source_ibus_get_engine_name (CcInputSourceIBus *source)
+{
+  g_return_val_if_fail (CC_IS_INPUT_SOURCE_IBUS (source), NULL);
+  return source->engine_name;
+}
+
+GDesktopAppInfo *
+cc_input_source_ibus_get_app_info (CcInputSourceIBus *source)
+{
+  g_auto(GStrv) tokens = NULL;
+  g_autofree gchar *desktop_file_name = NULL;
+
+  g_return_val_if_fail (CC_IS_INPUT_SOURCE_IBUS (source), NULL);
+
+  tokens = g_strsplit (source->engine_name, ":", 2);
+  desktop_file_name = g_strdup_printf ("ibus-setup-%s.desktop", tokens[0]);
+
+  return g_desktop_app_info_new (desktop_file_name);
+}
diff --git a/panels/region/cc-input-source-ibus.h b/panels/region/cc-input-source-ibus.h
new file mode 100644
index 000000000..2c09d01c6
--- /dev/null
+++ b/panels/region/cc-input-source-ibus.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2018 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <config.h>
+
+#ifdef HAVE_IBUS
+#include <ibus.h>
+#endif
+
+#include <gio/gdesktopappinfo.h>
+
+#include "cc-input-source.h"
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_INPUT_SOURCE_IBUS (cc_input_source_ibus_get_type ())
+G_DECLARE_FINAL_TYPE (CcInputSourceIBus, cc_input_source_ibus, CC, INPUT_SOURCE_IBUS, CcInputSource)
+
+CcInputSourceIBus *cc_input_source_ibus_new             (const gchar       *engine_name);
+
+#ifdef HAVE_IBUS
+void               cc_input_source_ibus_set_engine_desc (CcInputSourceIBus *source,
+                                                         IBusEngineDesc    *engine_desc);
+#endif
+
+const gchar       *cc_input_source_ibus_get_engine_name (CcInputSourceIBus *source);
+
+GDesktopAppInfo   *cc_input_source_ibus_get_app_info    (CcInputSourceIBus *source);
+
+G_END_DECLS
diff --git a/panels/region/cc-input-source-xkb.c b/panels/region/cc-input-source-xkb.c
new file mode 100644
index 000000000..2ea30beb5
--- /dev/null
+++ b/panels/region/cc-input-source-xkb.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright © 2018 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include "cc-input-source-xkb.h"
+
+struct _CcInputSourceXkb
+{
+  CcInputSource  parent_instance;
+
+  GnomeXkbInfo  *xkb_info;
+  gchar         *layout;
+  gchar         *variant;
+};
+
+G_DEFINE_TYPE (CcInputSourceXkb, cc_input_source_xkb, CC_TYPE_INPUT_SOURCE)
+
+static gchar *
+cc_input_source_xkb_get_label (CcInputSource *source)
+{
+  CcInputSourceXkb *self = CC_INPUT_SOURCE_XKB (source);
+  g_autofree gchar *id = NULL;
+  const gchar *name;
+
+  id = cc_input_source_xkb_get_id (self);
+  gnome_xkb_info_get_layout_info (self->xkb_info, id, &name, NULL, NULL, NULL);
+  if (name)
+    return g_strdup (name);
+  else
+    return g_strdup (id);
+}
+
+static gboolean
+cc_input_source_xkb_matches (CcInputSource *source,
+                             CcInputSource *source2)
+{
+  if (!CC_IS_INPUT_SOURCE_XKB (source2))
+    return FALSE;
+
+  return g_strcmp0 (CC_INPUT_SOURCE_XKB (source)->layout, CC_INPUT_SOURCE_XKB (source2)->layout) == 0 &&
+         g_strcmp0 (CC_INPUT_SOURCE_XKB (source)->variant, CC_INPUT_SOURCE_XKB (source2)->variant) == 0;
+}
+
+static void
+cc_input_source_xkb_dispose (GObject *object)
+{
+  CcInputSourceXkb *self = CC_INPUT_SOURCE_XKB (object);
+
+  g_clear_object (&self->xkb_info);
+  g_clear_pointer (&self->layout, g_free);
+  g_clear_pointer (&self->variant, g_free);
+
+  G_OBJECT_CLASS (cc_input_source_xkb_parent_class)->dispose (object);
+}
+
+static const gchar *
+cc_input_source_xkb_get_layout (CcInputSource *source)
+{
+  return CC_INPUT_SOURCE_XKB (source)->layout;
+}
+
+static const gchar *
+cc_input_source_xkb_get_layout_variant (CcInputSource *source)
+{
+  return CC_INPUT_SOURCE_XKB (source)->variant;
+}
+
+void
+cc_input_source_xkb_class_init (CcInputSourceXkbClass *klass)
+{
+  CcInputSourceClass *input_source_class = CC_INPUT_SOURCE_CLASS (klass);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  input_source_class->get_label = cc_input_source_xkb_get_label;
+  input_source_class->matches = cc_input_source_xkb_matches;
+  input_source_class->get_layout = cc_input_source_xkb_get_layout;
+  input_source_class->get_layout_variant = cc_input_source_xkb_get_layout_variant;
+  object_class->dispose = cc_input_source_xkb_dispose;
+}
+
+void
+cc_input_source_xkb_init (CcInputSourceXkb *source)
+{
+}
+
+CcInputSourceXkb *
+cc_input_source_xkb_new (GnomeXkbInfo *xkb_info,
+                         const gchar  *layout,
+                         const gchar  *variant)
+{
+  CcInputSourceXkb *source;
+
+  source = g_object_new (CC_TYPE_INPUT_SOURCE_XKB, NULL);
+  source->xkb_info = g_object_ref (xkb_info);
+  source->layout = g_strdup (layout);
+  source->variant = g_strdup (variant);
+
+  return source;
+}
+
+CcInputSourceXkb *
+cc_input_source_xkb_new_from_id (GnomeXkbInfo *xkb_info,
+                                 const gchar  *id)
+{
+  g_auto(GStrv) tokens = NULL;
+
+  tokens = g_strsplit (id, "+", 2);
+
+  return cc_input_source_xkb_new (xkb_info, tokens[0], tokens[1]);
+}
+
+gchar *
+cc_input_source_xkb_get_id (CcInputSourceXkb *source)
+{
+  g_return_val_if_fail (CC_IS_INPUT_SOURCE_XKB (source), NULL);
+  if (source->variant != NULL)
+    return g_strdup_printf ("%s+%s", source->layout, source->variant);
+  else
+    return g_strdup (source->layout);
+}
diff --git a/panels/region/cc-input-source-xkb.h b/panels/region/cc-input-source-xkb.h
new file mode 100644
index 000000000..e8886d014
--- /dev/null
+++ b/panels/region/cc-input-source-xkb.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2018 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-xkb-info.h>
+
+#include "cc-input-source.h"
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_INPUT_SOURCE_XKB (cc_input_source_xkb_get_type ())
+G_DECLARE_FINAL_TYPE (CcInputSourceXkb, cc_input_source_xkb, CC, INPUT_SOURCE_XKB, CcInputSource)
+
+CcInputSourceXkb *cc_input_source_xkb_new         (GnomeXkbInfo     *xkb_info,
+                                                   const gchar      *layout,
+                                                   const gchar      *variant);
+
+CcInputSourceXkb *cc_input_source_xkb_new_from_id (GnomeXkbInfo     *xkb_info,
+                                                   const gchar      *id);
+
+gchar            *cc_input_source_xkb_get_id      (CcInputSourceXkb *source);
+
+G_END_DECLS
diff --git a/panels/region/cc-input-source.c b/panels/region/cc-input-source.c
new file mode 100644
index 000000000..df8db8b9c
--- /dev/null
+++ b/panels/region/cc-input-source.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright © 2018 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include "cc-input-source.h"
+
+enum
+{
+  SIGNAL_LABEL_CHANGED,
+  SIGNAL_LAST
+};
+
+static guint signals[SIGNAL_LAST] = {0};
+
+G_DEFINE_TYPE (CcInputSource, cc_input_source, G_TYPE_OBJECT)
+
+void
+cc_input_source_class_init (CcInputSourceClass *klass)
+{
+  signals[SIGNAL_LABEL_CHANGED] =
+    g_signal_new ("label-changed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE,
+                  0);
+}
+
+void
+cc_input_source_init (CcInputSource *source)
+{
+}
+
+void
+cc_input_source_emit_label_changed (CcInputSource *source)
+{
+  g_return_if_fail (CC_IS_INPUT_SOURCE (source));
+  g_signal_emit (source, signals[SIGNAL_LABEL_CHANGED], 0);
+}
+
+gchar *
+cc_input_source_get_label (CcInputSource *source)
+{
+  g_return_val_if_fail (CC_IS_INPUT_SOURCE (source), NULL);
+  return CC_INPUT_SOURCE_GET_CLASS (source)->get_label (source);
+}
+
+gboolean
+cc_input_source_matches (CcInputSource *source,
+                         CcInputSource *source2)
+{
+  g_return_val_if_fail (CC_IS_INPUT_SOURCE (source), FALSE);
+  return CC_INPUT_SOURCE_GET_CLASS (source)->matches (source, source2);
+}
+
+const gchar *
+cc_input_source_get_layout (CcInputSource *source)
+{
+  g_return_val_if_fail (CC_IS_INPUT_SOURCE (source), NULL);
+  return CC_INPUT_SOURCE_GET_CLASS (source)->get_layout (source);
+}
+
+const gchar *
+cc_input_source_get_layout_variant (CcInputSource *source)
+{
+  g_return_val_if_fail (CC_IS_INPUT_SOURCE (source), NULL);
+  return CC_INPUT_SOURCE_GET_CLASS (source)->get_layout_variant (source);
+}
diff --git a/panels/region/cc-input-source.h b/panels/region/cc-input-source.h
new file mode 100644
index 000000000..5b7865d5c
--- /dev/null
+++ b/panels/region/cc-input-source.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2018 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define CC_TYPE_INPUT_SOURCE (cc_input_source_get_type ())
+G_DECLARE_DERIVABLE_TYPE (CcInputSource, cc_input_source, CC, INPUT_SOURCE, GObject)
+
+struct _CcInputSourceClass
+{
+  GObjectClass parent_class;
+
+  gchar*       (*get_label)          (CcInputSource *source);
+  gboolean     (*matches)            (CcInputSource *source,
+                                      CcInputSource *source2);
+  const gchar* (*get_layout)         (CcInputSource *source);
+  const gchar* (*get_layout_variant) (CcInputSource *source);
+};
+
+void             cc_input_source_emit_label_changed (CcInputSource *source);
+
+gchar           *cc_input_source_get_label          (CcInputSource *source);
+
+gboolean         cc_input_source_matches            (CcInputSource *source,
+                                                     CcInputSource *source2);
+
+const gchar     *cc_input_source_get_layout         (CcInputSource *source);
+
+const gchar     *cc_input_source_get_layout_variant (CcInputSource *source);
+
+G_END_DECLS
diff --git a/panels/region/cc-region-panel.c b/panels/region/cc-region-panel.c
index 2c6b29e46..5c9cb50fd 100644
--- a/panels/region/cc-region-panel.c
+++ b/panels/region/cc-region-panel.c
@@ -33,6 +33,8 @@
 #include "cc-format-chooser.h"
 #include "cc-input-chooser.h"
 #include "cc-input-row.h"
+#include "cc-input-source-ibus.h"
+#include "cc-input-source-xkb.h"
 
 #include "cc-common-language.h"
 
@@ -42,7 +44,6 @@
 
 #ifdef HAVE_IBUS
 #include <ibus.h>
-#include "cc-ibus-utils.h"
 #endif
 
 #include <act/act.h>
@@ -53,9 +54,6 @@
 #define GNOME_SYSTEM_LOCALE_DIR "org.gnome.system.locale"
 #define KEY_REGION "region"
 
-#define INPUT_SOURCE_TYPE_XKB "xkb"
-#define INPUT_SOURCE_TYPE_IBUS "ibus"
-
 #define DEFAULT_LOCALE "en_US.utf-8"
 
 struct _CcRegionPanel {
@@ -639,20 +637,20 @@ update_ibus_active_sources (CcRegionPanel *self)
         rows = gtk_container_get_children (GTK_CONTAINER (self->input_list));
         for (l = rows; l; l = l->next) {
                 CcInputRow *row;
+                CcInputSourceIBus *source;
                 IBusEngineDesc *engine_desc;
 
                 if (!CC_IS_INPUT_ROW (l->data))
                         continue;
                 row = CC_INPUT_ROW (l->data);
 
-                if (g_strcmp0 (cc_input_row_get_input_type (row), INPUT_SOURCE_TYPE_IBUS) != 0)
+                if (!CC_IS_INPUT_SOURCE_IBUS (cc_input_row_get_source (row)))
                         continue;
+                source = CC_INPUT_SOURCE_IBUS (cc_input_row_get_source (row));
 
-                engine_desc = g_hash_table_lookup (self->ibus_engines, cc_input_row_get_id (row));
-                if (engine_desc) {
-                        g_autofree gchar *display_name = engine_get_display_name (engine_desc);
-                        cc_input_row_set_label (row, display_name);
-                }
+                engine_desc = g_hash_table_lookup (self->ibus_engines, cc_input_source_ibus_get_engine_name 
(source));
+                if (engine_desc != NULL)
+                        cc_input_source_ibus_set_engine_desc (source, engine_desc);
         }
 }
 
@@ -717,34 +715,17 @@ maybe_start_ibus (void)
                                               NULL));
 }
 
-static GDesktopAppInfo *
-setup_app_info_for_id (const gchar *id)
-{
-        g_autofree gchar *desktop_file_name = NULL;
-        g_auto(GStrv) strv = NULL;
-
-        strv = g_strsplit (id, ":", 2);
-        desktop_file_name = g_strdup_printf ("ibus-setup-%s.desktop", strv[0]);
-
-        return g_desktop_app_info_new (desktop_file_name);
-}
 #endif
 
 static void
-add_input_row (CcRegionPanel   *self,
-               const gchar     *type,
-               const gchar     *id,
-               const gchar     *name,
-               GDesktopAppInfo *app_info)
+add_input_row (CcRegionPanel *self, CcInputSource *source)
 {
         CcInputRow *row;
 
         gtk_widget_set_visible (GTK_WIDGET (self->no_inputs_row), FALSE);
 
-        row = cc_input_row_new (type, id, app_info);
+        row = cc_input_row_new (source);
         gtk_widget_show (GTK_WIDGET (row));
-        cc_input_row_set_label (row, name);
-        cc_input_row_set_is_input_method (row, strcmp (type, INPUT_SOURCE_TYPE_IBUS) == 0);
         gtk_container_add (GTK_CONTAINER (self->input_list), GTK_WIDGET (row));
 
         cc_list_box_adjust_scrolling (self->input_list);
@@ -764,37 +745,25 @@ add_input_sources (CcRegionPanel *self,
 
         g_variant_iter_init (&iter, sources);
         while (g_variant_iter_next (&iter, "(&s&s)", &type, &id)) {
-                g_autoptr(GDesktopAppInfo) app_info = NULL;
-                g_autofree gchar *display_name = NULL;
-
-                if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) {
-                        const gchar *name;
+                g_autoptr(CcInputSource) source = NULL;
 
-                        gnome_xkb_info_get_layout_info (self->xkb_info, id, &name, NULL, NULL, NULL);
-                        if (!name) {
-                                g_warning ("Couldn't find XKB input source '%s'", id);
-                                continue;
-                        }
-                        display_name = g_strdup (name);
-                        type = INPUT_SOURCE_TYPE_XKB;
+                if (g_str_equal (type, "xkb")) {
+                        source = CC_INPUT_SOURCE (cc_input_source_xkb_new_from_id (self->xkb_info, id));
+                } else if (g_str_equal (type, "ibus")) {
+                        source = CC_INPUT_SOURCE (cc_input_source_ibus_new (id));
 #ifdef HAVE_IBUS
-                } else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) {
-                        IBusEngineDesc *engine_desc = NULL;
-
-                        if (self->ibus_engines)
-                                engine_desc = g_hash_table_lookup (self->ibus_engines, id);
-                        if (engine_desc)
-                                display_name = engine_get_display_name (engine_desc);
-
-                        app_info = setup_app_info_for_id (id);
-                        type = INPUT_SOURCE_TYPE_IBUS;
+                        if (self->ibus_engines) {
+                                IBusEngineDesc *engine_desc = g_hash_table_lookup (self->ibus_engines, id);
+                                if (engine_desc != NULL)
+                                        cc_input_source_ibus_set_engine_desc (CC_INPUT_SOURCE_IBUS (source), 
engine_desc);
+                        }
 #endif
                 } else {
                         g_warning ("Unhandled input source type '%s'", type);
                         continue;
                 }
 
-                add_input_row (self, type, id, display_name ? display_name : id, app_info);
+                add_input_row (self, source);
         }
 }
 
@@ -821,25 +790,25 @@ clear_input_sources (CcRegionPanel *self)
         cc_list_box_adjust_scrolling (self->input_list);
 }
 
-static void
-select_by_id (GtkWidget   *row,
-              gpointer     data)
+static CcInputRow *
+get_row_by_source (CcRegionPanel *self, CcInputSource *source)
 {
-        const gchar *id = data;
+        g_autoptr(GList) list = NULL;
+        GList *l;
 
-        if (!CC_IS_INPUT_ROW (row))
-                return;
+        list = gtk_container_get_children (GTK_CONTAINER (self->input_list));
+        for (l = list; l; l = l->next) {
+                CcInputRow *row;
 
-        if (g_strcmp0 (cc_input_row_get_id (CC_INPUT_ROW (row)), id) == 0)
-                gtk_list_box_select_row (GTK_LIST_BOX (gtk_widget_get_parent (row)), GTK_LIST_BOX_ROW (row));
-}
+                if (!CC_IS_INPUT_ROW (l->data))
+                        continue;
+                row = CC_INPUT_ROW (l->data);
 
-static void
-select_input (CcRegionPanel *self,
-              const gchar   *id)
-{
-        gtk_container_foreach (GTK_CONTAINER (self->input_list),
-                               select_by_id, (gpointer)id);
+                if (cc_input_source_matches (source, cc_input_row_get_source (row)))
+                        return row;
+        }
+
+        return NULL;
 }
 
 static void
@@ -848,18 +817,20 @@ input_sources_changed (GSettings     *settings,
                        CcRegionPanel *self)
 {
         CcInputRow *selected;
-        g_autofree gchar *id = NULL;
+        g_autoptr(CcInputSource) source = NULL;
 
         selected = CC_INPUT_ROW (gtk_list_box_get_selected_row (self->input_list));
         if (selected)
-                id = g_strdup (cc_input_row_get_id (selected));
+                source = g_object_ref (cc_input_row_get_source (selected));
         clear_input_sources (self);
         add_input_sources_from_settings (self);
-        if (id)
-                select_input (self, id);
+        if (source != NULL) {
+                CcInputRow *row = get_row_by_source (self, source);
+                if (row != NULL)
+                        gtk_list_box_select_row (GTK_LIST_BOX (self->input_list), GTK_LIST_BOX_ROW (row));
+        }
 }
 
-
 static void
 update_buttons (CcRegionPanel *self)
 {
@@ -878,13 +849,11 @@ update_buttons (CcRegionPanel *self)
                 gtk_widget_set_sensitive (GTK_WIDGET (self->move_up_input_button), FALSE);
                 gtk_widget_set_sensitive (GTK_WIDGET (self->move_down_input_button), FALSE);
         } else {
-                GDesktopAppInfo *app_info;
                 gint index;
 
-                app_info = cc_input_row_get_app_info (selected);
                 index = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (selected));
 
-                gtk_widget_set_visible (GTK_WIDGET (self->show_config_button), app_info != NULL);
+                gtk_widget_set_visible (GTK_WIDGET (self->show_config_button), CC_IS_INPUT_SOURCE_IBUS 
(cc_input_row_get_source (selected)));
                 gtk_widget_set_sensitive (GTK_WIDGET (self->show_layout_button), TRUE);
                 gtk_widget_set_sensitive (GTK_WIDGET (self->remove_input_button), n_rows > 1);
                 gtk_widget_set_sensitive (GTK_WIDGET (self->move_up_input_button), index > 1);
@@ -906,12 +875,20 @@ set_input_settings (CcRegionPanel *self)
         list = gtk_container_get_children (GTK_CONTAINER (self->input_list));
         for (l = list; l; l = l->next) {
                 CcInputRow *row;
+                CcInputSource *source;
 
                 if (!CC_IS_INPUT_ROW (l->data))
                         continue;
-
                 row = CC_INPUT_ROW (l->data);
-                g_variant_builder_add (&builder, "(ss)", cc_input_row_get_input_type (row), 
cc_input_row_get_id (row));
+                source = cc_input_row_get_source (row);
+
+                if (CC_IS_INPUT_SOURCE_XKB (source)) {
+                        g_autofree gchar *id = cc_input_source_xkb_get_id (CC_INPUT_SOURCE_XKB (source));
+                        g_variant_builder_add (&builder, "(ss)", "xkb", id);
+                } else if (CC_IS_INPUT_SOURCE_IBUS (source)) {
+                        g_variant_builder_add (&builder, "(ss)", "ibus",
+                                               cc_input_source_ibus_get_engine_name (CC_INPUT_SOURCE_IBUS 
(source)));
+                }
         }
 
         g_settings_set_value (self->input_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder));
@@ -932,33 +909,10 @@ update_input (CcRegionPanel *self)
         }
 }
 
-static gboolean
-input_source_already_added (CcRegionPanel *self,
-                            const gchar   *id)
-{
-        g_autoptr(GList) list = NULL;
-        GList *l;
-
-        list = gtk_container_get_children (GTK_CONTAINER (self->input_list));
-        for (l = list; l; l = l->next) {
-                if (!CC_IS_INPUT_ROW (l->data))
-                        continue;
-
-                if (g_str_equal (id, cc_input_row_get_id (CC_INPUT_ROW (l->data)))) {
-                        return TRUE;
-                }
-        }
-
-        return FALSE;
-}
-
 static void
 show_input_chooser (CcRegionPanel *self)
 {
         CcInputChooser *chooser;
-        g_autofree gchar *type = NULL;
-        g_autofree gchar *id = NULL;
-        g_autofree gchar *name = NULL;
 
         chooser = cc_input_chooser_new (self->login,
                                         self->xkb_info,
@@ -970,27 +924,15 @@ show_input_chooser (CcRegionPanel *self)
                                         );
         gtk_window_set_transient_for (GTK_WINDOW (chooser), GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET 
(self))));
 
-        if (gtk_dialog_run (GTK_DIALOG (chooser)) != GTK_RESPONSE_OK) {
-                gtk_widget_destroy (GTK_WIDGET (chooser));
-                return;
-        }
-
-        if (cc_input_chooser_get_selected (chooser, &type, &id, &name) &&
-            !input_source_already_added (self, id)) {
-                g_autoptr(GDesktopAppInfo) app_info = NULL;
+        if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK) {
+                CcInputSource *source;
 
-                if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) {
-#ifdef HAVE_IBUS
-                        app_info = setup_app_info_for_id (id);
-#endif
-                } else {
-                        g_free (type);
-                        type = g_strdup (INPUT_SOURCE_TYPE_XKB);
+                source = cc_input_chooser_get_source (chooser);
+                if (source != NULL && get_row_by_source (self, source) == NULL) {
+                        add_input_row (self, source);
+                        update_buttons (self);
+                        update_input (self);
                 }
-
-                add_input_row (self, type, id, name, app_info);
-                update_buttons (self);
-                update_input (self);
         }
         gtk_widget_destroy (GTK_WIDGET (chooser));
 }
@@ -1163,23 +1105,26 @@ static void
 show_selected_settings (CcRegionPanel *self)
 {
         CcInputRow *selected;
+        CcInputSourceIBus *source;
         g_autoptr(GdkAppLaunchContext) ctx = NULL;
-        GDesktopAppInfo *app_info;
+        g_autoptr(GDesktopAppInfo) app_info = NULL;
         g_autoptr(GError) error = NULL;
 
         selected = CC_INPUT_ROW (gtk_list_box_get_selected_row (self->input_list));
         if (selected == NULL)
                 return;
+        g_return_if_fail (CC_IS_INPUT_SOURCE_IBUS (cc_input_row_get_source (selected)));
+        source = CC_INPUT_SOURCE_IBUS (cc_input_row_get_source (selected));
 
-        app_info = cc_input_row_get_app_info (selected);
-        if  (app_info == NULL)
+        app_info = cc_input_source_ibus_get_app_info (source);
+        if (app_info == NULL)
                 return;
 
         ctx = gdk_display_get_app_launch_context (gdk_display_get_default ());
         gdk_app_launch_context_set_timestamp (ctx, gtk_get_current_event_time ());
 
         g_app_launch_context_setenv (G_APP_LAUNCH_CONTEXT (ctx),
-                                     "IBUS_ENGINE_NAME", cc_input_row_get_id (selected));
+                                     "IBUS_ENGINE_NAME", cc_input_source_ibus_get_engine_name (source));
 
         if (!g_app_info_launch (G_APP_INFO (app_info), NULL, G_APP_LAUNCH_CONTEXT (ctx), &error))
                 g_warning ("Failed to launch input source setup: %s", error->message);
@@ -1189,49 +1134,21 @@ static void
 show_selected_layout (CcRegionPanel *self)
 {
         CcInputRow *selected;
-        const gchar *type, *id;
-        const gchar *layout;
-        const gchar *variant;
+        CcInputSource *source;
+        const gchar *layout, *layout_variant;
         g_autofree gchar *commandline = NULL;
 
         selected = CC_INPUT_ROW (gtk_list_box_get_selected_row (self->input_list));
         if (selected == NULL)
                 return;
+        source = cc_input_row_get_source (selected);
 
-        type = cc_input_row_get_input_type (selected);
-        id = cc_input_row_get_id (selected);
-        if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) {
-                gnome_xkb_info_get_layout_info (self->xkb_info,
-                                                id, NULL, NULL,
-                                                &layout, &variant);
+        layout = cc_input_source_get_layout (source);
+        layout_variant = cc_input_source_get_layout_variant (source);
 
-                if (!layout || !layout[0]) {
-                        g_warning ("Couldn't find XKB input source '%s'", id);
-                        return;
-                }
-#ifdef HAVE_IBUS
-        } else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) {
-                IBusEngineDesc *engine_desc = NULL;
-
-                if (self->ibus_engines)
-                        engine_desc = g_hash_table_lookup (self->ibus_engines, id);
-
-                if (engine_desc) {
-                        layout = ibus_engine_desc_get_layout (engine_desc);
-                        variant = ibus_engine_desc_get_layout_variant (engine_desc);
-                } else {
-                        g_warning ("Couldn't find IBus input source '%s'", id);
-                        return;
-                }
-#endif
-        } else {
-                g_warning ("Unhandled input source type '%s'", type);
-                return;
-        }
-
-        if (variant && variant[0])
+        if (layout_variant && layout_variant[0])
                 commandline = g_strdup_printf ("gkbd-keyboard-display -l \"%s\t%s\"",
-                                               layout, variant);
+                                               layout, layout_variant);
         else
                 commandline = g_strdup_printf ("gkbd-keyboard-display -l %s",
                                                layout);
@@ -1440,17 +1357,8 @@ add_input_sources_from_localed (CcRegionPanel *self)
                 n = 0;
 
         for (i = 0; i < n && layouts[i][0]; i++) {
-                const gchar *name;
-                g_autofree gchar *id = NULL;
-
-                if (variants && variants[i] && variants[i][0])
-                        id = g_strdup_printf ("%s+%s", layouts[i], variants[i]);
-                else
-                        id = g_strdup (layouts[i]);
-
-                gnome_xkb_info_get_layout_info (self->xkb_info, id, &name, NULL, NULL, NULL);
-
-                add_input_row (self, INPUT_SOURCE_TYPE_XKB, id, name ? name : id, NULL);
+                g_autoptr(CcInputSourceXkb) source = cc_input_source_xkb_new (self->xkb_info, layouts[i], 
variants[i]);
+                add_input_row (self, CC_INPUT_SOURCE (source));
         }
         gtk_widget_set_visible (GTK_WIDGET (self->no_inputs_row), n == 0);
 }
@@ -1504,16 +1412,20 @@ set_localed_input (CcRegionPanel *self)
         list = gtk_container_get_children (GTK_CONTAINER (self->input_list));
         for (li = list; li; li = li->next) {
                 CcInputRow *row;
+                CcInputSourceXkb *source;
+                g_autofree gchar *id = NULL;
                 const gchar *l, *v;
 
                 if (!CC_IS_INPUT_ROW (li->data))
                         continue;
                 row = CC_INPUT_ROW (li->data);
 
-                if (g_str_equal (cc_input_row_get_input_type (row), INPUT_SOURCE_TYPE_IBUS))
+                if (!CC_IS_INPUT_SOURCE_XKB (cc_input_row_get_source (row)))
                         continue;
+                source = CC_INPUT_SOURCE_XKB (cc_input_row_get_source (row));
 
-                if (gnome_xkb_info_get_layout_info (self->xkb_info, cc_input_row_get_id (row), NULL, NULL, 
&l, &v)) {
+                id = cc_input_source_xkb_get_id (source);
+                if (gnome_xkb_info_get_layout_info (self->xkb_info, id, NULL, NULL, &l, &v)) {
                         if (layouts->str[0]) {
                                 g_string_append_c (layouts, ',');
                                 g_string_append_c (variants, ',');
diff --git a/panels/region/meson.build b/panels/region/meson.build
index 57b407597..c0b886dd4 100644
--- a/panels/region/meson.build
+++ b/panels/region/meson.build
@@ -23,6 +23,9 @@ sources = files(
   'cc-ibus-utils.c',
   'cc-input-chooser.c',
   'cc-input-row.c',
+  'cc-input-source.c',
+  'cc-input-source-ibus.c',
+  'cc-input-source-xkb.c',
 )
 
 resource_data = files(



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]