[gnome-flashback] input-sources: implement GfIBusManager



commit 028e4882cb0bffa7fb3d44d2ab69c87f84bd1a8c
Author: Sebastian Geiger <sbastig gmx net>
Date:   Sat Sep 19 19:31:42 2015 +0200

    input-sources: implement GfIBusManager

 configure.ac                                       |    2 +-
 gnome-flashback/libinput-sources/gf-ibus-manager.c |  403 +++++++++++++++++++-
 2 files changed, 402 insertions(+), 3 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 9b17f68..de589c0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -91,7 +91,7 @@ GLIB_REQUIRED=2.44.0
 GSETTINGS_DESKTOP_SCHEMAS_REQUIRED=3.12.0
 POLKIT_AGENT_REQUIRED=0.97
 POLKIT_GOBJECT_REQUIRED=0.97
-IBUS_REQUIRED=1.5.10
+IBUS_REQUIRED=1.5.2
 UPOWER_GLIB_REQUIRED=0.99.0
 
 PKG_CHECK_MODULES([GNOME_FLASHBACK], [
diff --git a/gnome-flashback/libinput-sources/gf-ibus-manager.c 
b/gnome-flashback/libinput-sources/gf-ibus-manager.c
index a9f0321..7975236 100644
--- a/gnome-flashback/libinput-sources/gf-ibus-manager.c
+++ b/gnome-flashback/libinput-sources/gf-ibus-manager.c
@@ -20,11 +20,30 @@
 #include "gf-candidate-popup.h"
 #include "gf-ibus-manager.h"
 
+/*
+ * This is the longest we'll keep the keyboard frozen until an input
+ * source is active.
+ */
+#define MAX_INPUT_SOURCE_ACTIVATION_TIME 4000
+
 struct _GfIBusManager
 {
   GObject           parent;
 
   GfCandidatePopup *candidate_popup;
+  IBusBus          *ibus;
+
+  GSubprocess      *subprocess;
+
+  GHashTable       *engines;
+
+  IBusPanelService *panel_service;
+
+  gboolean          ready;
+
+  gchar            *current_engine_name;
+
+  gulong            register_properties_id;
 };
 
 enum
@@ -44,6 +63,324 @@ static guint signals[LAST_SIGNAL] = { 0 };
 G_DEFINE_TYPE (GfIBusManager, gf_ibus_manager, G_TYPE_OBJECT)
 
 static void
+spawn (GfIBusManager *manager)
+{
+  GError *error;
+
+  error = NULL;
+  manager->subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE |
+                                          G_SUBPROCESS_FLAGS_STDERR_SILENCE,
+                                          &error, "ibus-daemon", "--xim",
+                                          "--panel", "disable", NULL);
+
+  if (error != NULL)
+    {
+      g_warning ("Failed to launch ibus-daemon: %s", error->message);
+      g_error_free (error);
+    }
+}
+
+static void
+clear (GfIBusManager *manager)
+{
+  gf_candidate_popup_set_panel_service (manager->candidate_popup, NULL);
+  g_clear_object (&manager->panel_service);
+
+  if (manager->engines != NULL)
+    {
+      g_hash_table_destroy (manager->engines);
+      manager->engines = NULL;
+    }
+
+  manager->ready = FALSE;
+
+  g_free (manager->current_engine_name);
+  manager->current_engine_name = NULL;
+
+  manager->register_properties_id = 0;
+
+  g_signal_emit (manager, signals[SIGNAL_READY], 0, FALSE);
+
+  spawn (manager);
+}
+
+static void
+update_readiness (GfIBusManager *manager)
+{
+  manager->ready = FALSE;
+
+  if (g_hash_table_size (manager->engines) > 0 &&
+      manager->panel_service != NULL)
+    {
+      manager->ready = TRUE;
+    }
+
+  g_signal_emit (manager, signals[SIGNAL_READY], 0, manager->ready);
+}
+
+static void
+add_engine_to_hash_table (gpointer data,
+                          gpointer user_data)
+{
+  IBusEngineDesc *engine_desc;
+  GfIBusManager *manager;
+  const gchar *name;
+
+  engine_desc = (IBusEngineDesc *) data;
+  manager = GF_IBUS_MANAGER (user_data);
+
+  name = ibus_engine_desc_get_name (engine_desc);
+  g_hash_table_insert (manager->engines, g_strdup (name),
+                       g_object_ref (engine_desc));
+}
+
+static void
+list_engines_cb (GObject      *source_object,
+                 GAsyncResult *res,
+                 gpointer      user_data)
+{
+  GfIBusManager *manager;
+  GList *engines;
+  GError *error;
+
+  manager = GF_IBUS_MANAGER (user_data);
+
+  error = NULL;
+  engines = ibus_bus_list_engines_async_finish (manager->ibus, res, &error);
+
+  if (engines != NULL)
+    {
+      if (manager->engines == NULL)
+        manager->engines = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                  g_free, g_object_unref);
+
+      g_list_foreach (engines, add_engine_to_hash_table, manager);
+      g_list_free (engines);
+
+      update_readiness (manager);
+    }
+  else
+    {
+      g_warning ("Failed to list ibus engines - %s", error->message);
+      g_error_free (error);
+
+      clear (manager);
+    }
+}
+
+static void
+update_property_cb (IBusPanelService *panel_service,
+                    IBusProperty     *property,
+                    gpointer          user_data)
+{
+  GfIBusManager *manager;
+
+  manager = GF_IBUS_MANAGER (user_data);
+
+  g_signal_emit (manager, signals[SIGNAL_PROPERTY_UPDATED], 0,
+                 manager->current_engine_name, property);
+}
+
+static void
+set_content_type_cb (IBusPanelService *panel_service,
+                     guint             purpose,
+                     guint             hints,
+                     gpointer          user_data)
+{
+  GfIBusManager *manager;
+
+  manager = GF_IBUS_MANAGER (user_data);
+
+  g_signal_emit (manager, signals[SIGNAL_SET_CONTENT_TYPE], 0, purpose, hints);
+}
+
+static void
+register_properties_cb (IBusPanelService *service,
+                        IBusPropList     *prop_list,
+                        gpointer          user_data)
+{
+  GfIBusManager *manager;
+
+  manager = GF_IBUS_MANAGER (user_data);
+
+  if (ibus_prop_list_get (prop_list, 0) == NULL)
+    return;
+
+  g_signal_handler_disconnect (service, manager->register_properties_id);
+  manager->register_properties_id = 0;
+
+  g_signal_emit (manager, signals[SIGNAL_PROPERTIES_REGISTERED], 0,
+                 manager->current_engine_name, prop_list);
+}
+
+static void
+global_engine_changed_cb (IBusBus     *ibus,
+                          const gchar *name,
+                          gpointer     user_data)
+{
+  GfIBusManager *manager;
+
+  manager = GF_IBUS_MANAGER (user_data);
+
+  if (!manager->ready)
+    return;
+
+  g_free (manager->current_engine_name);
+  manager->current_engine_name = g_strdup (name);
+
+  if (manager->register_properties_id != 0)
+    return;
+
+  manager->register_properties_id =
+    g_signal_connect (manager->panel_service, "register-properties",
+                      G_CALLBACK (register_properties_cb), manager);
+}
+
+static void
+get_global_engine_cb (GObject      *source_object,
+                      GAsyncResult *res,
+                      gpointer      user_data)
+{
+  GfIBusManager *manager;
+  IBusEngineDesc *engine_desc;
+  GError *error;
+  const gchar *name;
+
+  manager = GF_IBUS_MANAGER (user_data);
+
+  error = NULL;
+  engine_desc = ibus_bus_get_global_engine_async_finish (manager->ibus, res,
+                                                         &error);
+
+  if (engine_desc == NULL)
+    {
+      g_warning ("Failed to get global engine - %s", error->message);
+      g_error_free (error);
+
+      clear (manager);
+
+      return;
+    }
+
+  name = ibus_engine_desc_get_name (engine_desc);
+
+  global_engine_changed_cb (manager->ibus, name, manager);
+}
+
+static void
+request_name_cb (GObject      *source_object,
+                 GAsyncResult *res,
+                 gpointer      user_data)
+{
+  GfIBusManager *manager;
+  guint result;
+  GError *error;
+  GDBusConnection *connection;
+
+  manager = GF_IBUS_MANAGER (user_data);
+
+  error = NULL;
+  result = ibus_bus_request_name_async_finish (manager->ibus, res, &error);
+
+  if (result == 0)
+    {
+      g_warning ("Name request failed - %s", error->message);
+      g_error_free (error);
+
+      clear (manager);
+
+      return;
+    }
+
+  connection = ibus_bus_get_connection (manager->ibus);
+  manager->panel_service = ibus_panel_service_new (connection);
+
+  gf_candidate_popup_set_panel_service (manager->candidate_popup,
+                                        manager->panel_service);
+
+  g_signal_connect (manager->panel_service, "update-property",
+                    G_CALLBACK (update_property_cb), manager);
+
+  if (IBUS_CHECK_VERSION (1, 5, 10))
+    g_signal_connect (manager->panel_service, "set-content-type",
+                      G_CALLBACK (set_content_type_cb), manager);
+
+  ibus_bus_get_global_engine_async (manager->ibus, -1, NULL,
+                                    get_global_engine_cb, manager);
+
+  update_readiness (manager);
+}
+
+static void
+connected_cb (IBusBus  *ibus,
+              gpointer  user_data)
+{
+  IBusBusNameFlag flags;
+
+  flags = IBUS_BUS_NAME_FLAG_ALLOW_REPLACEMENT |
+          IBUS_BUS_NAME_FLAG_REPLACE_EXISTING;
+
+  ibus_bus_list_engines_async (ibus, -1, NULL, list_engines_cb, user_data);
+  ibus_bus_request_name_async (ibus, IBUS_SERVICE_PANEL, flags, -1, NULL,
+                               request_name_cb, user_data);
+}
+
+static void
+disconnected_cb (IBusBus  *ibus,
+                 gpointer  user_data)
+{
+  GfIBusManager *manager;
+
+  manager = GF_IBUS_MANAGER (user_data);
+
+  clear (manager);
+}
+
+static void
+set_global_engine_cb (GObject      *source_object,
+                      GAsyncResult *res,
+                      gpointer      user_data)
+{
+  GfIBusManager *manager;
+  gboolean result;
+  GError *error;
+
+  manager = GF_IBUS_MANAGER (user_data);
+
+  error = NULL;
+  result = ibus_bus_set_global_engine_async_finish (manager->ibus, res, &error);
+
+  if (!result)
+    {
+      g_warning ("Failed to set ibus engine - %s", error->message);
+      g_error_free (error);
+    }
+
+  g_signal_emit (manager, signals[SIGNAL_ENGINE_SET], 0);
+}
+
+static void
+preload_engines_cb (GObject      *source_object,
+                    GAsyncResult *res,
+                    gpointer      user_data)
+{
+  GfIBusManager *manager;
+  gboolean result;
+  GError *error;
+
+  manager = GF_IBUS_MANAGER (user_data);
+
+  error = NULL;
+  result = ibus_bus_preload_engines_async_finish (manager->ibus, res, &error);
+
+  if (!result)
+    {
+      g_warning ("Failed to preload engines - %s", error->message);
+      g_error_free (error);
+    }
+}
+
+static void
 gf_ibus_manager_dispose (GObject *object)
 {
   GfIBusManager *manager;
@@ -51,11 +388,32 @@ gf_ibus_manager_dispose (GObject *object)
   manager = GF_IBUS_MANAGER (object);
 
   g_clear_object (&manager->candidate_popup);
+  g_clear_object (&manager->subprocess);
+
+  if (manager->engines != NULL)
+    {
+      g_hash_table_destroy (manager->engines);
+      manager->engines = NULL;
+    }
+
+  g_clear_object (&manager->panel_service);
 
   G_OBJECT_CLASS (gf_ibus_manager_parent_class)->dispose (object);
 }
 
 static void
+gf_ibus_manager_finalize (GObject *object)
+{
+  GfIBusManager *manager;
+
+  manager = GF_IBUS_MANAGER (object);
+
+  g_free (manager->current_engine_name);
+
+  G_OBJECT_CLASS (gf_ibus_manager_parent_class)->finalize (object);
+}
+
+static void
 gf_ibus_manager_class_init (GfIBusManagerClass *manager_class)
 {
   GObjectClass *object_class;
@@ -63,6 +421,7 @@ gf_ibus_manager_class_init (GfIBusManagerClass *manager_class)
   object_class = G_OBJECT_CLASS (manager_class);
 
   object_class->dispose = gf_ibus_manager_dispose;
+  object_class->finalize = gf_ibus_manager_finalize;
 
   signals[SIGNAL_READY] =
     g_signal_new ("ready", G_TYPE_FROM_CLASS (manager_class),
@@ -92,7 +451,31 @@ gf_ibus_manager_class_init (GfIBusManagerClass *manager_class)
 static void
 gf_ibus_manager_init (GfIBusManager *manager)
 {
+  if (IBUS_CHECK_VERSION (1, 5, 2) == FALSE)
+    {
+      g_warning ("Found IBus version %d.%d.%d but required is 1.5.2 or newer.",
+                 IBUS_MAJOR_VERSION, IBUS_MINOR_VERSION, IBUS_MICRO_VERSION);
+      return;
+    }
+
+  ibus_init ();
+
   manager->candidate_popup = gf_candidate_popup_new ();
+  manager->ibus = ibus_bus_new_async ();
+
+  g_signal_connect (manager->ibus, "connected",
+                    G_CALLBACK (connected_cb), manager);
+
+  g_signal_connect (manager->ibus, "disconnected",
+                    G_CALLBACK (disconnected_cb), manager);
+
+  /* Need to set this to get 'global-engine-changed' emissions */
+  ibus_bus_set_watch_ibus_signal (manager->ibus, TRUE);
+
+  g_signal_connect (manager->ibus, "global-engine-changed",
+                    G_CALLBACK (global_engine_changed_cb), manager);
+
+  spawn (manager);
 }
 
 GfIBusManager *
@@ -105,18 +488,34 @@ IBusEngineDesc *
 gf_ibus_manager_get_engine_desc (GfIBusManager *manager,
                                  const gchar   *id)
 {
-  return NULL;
+  if (!manager->ready || manager->engines == NULL)
+    return NULL;
+
+  return g_hash_table_lookup (manager->engines, id);
 }
 
 void
 gf_ibus_manager_set_engine (GfIBusManager *manager,
                             const gchar   *id)
 {
-  g_signal_emit (manager, signals[SIGNAL_ENGINE_SET], 0);
+  if (!manager->ready)
+    {
+      g_signal_emit (manager, signals[SIGNAL_ENGINE_SET], 0);
+      return;
+    }
+
+  ibus_bus_set_global_engine_async (manager->ibus, id,
+                                    MAX_INPUT_SOURCE_ACTIVATION_TIME,
+                                    NULL, set_global_engine_cb, manager);
 }
 
 void
 gf_ibus_manager_preload_engines (GfIBusManager  *manager,
                                  gchar         **engines)
 {
+  if (manager->ibus == NULL || g_strv_length (engines) == 0)
+    return;
+
+  ibus_bus_preload_engines_async (manager->ibus, (const gchar *const *) engines,
+                                  -1, NULL, preload_engines_cb, manager);
 }


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