[gnome-flashback/wip/segeiger/inputmethods: 5/8] input-sources: add implementation for GfIBusManager



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

    input-sources: add implementation for GfIBusManager

 gnome-flashback/libinput-sources/gf-ibus-manager.c |  369 ++++++++++++++++++++
 gnome-flashback/libinput-sources/gf-ibus-manager.h |   11 +
 2 files changed, 380 insertions(+), 0 deletions(-)
---
diff --git a/gnome-flashback/libinput-sources/gf-ibus-manager.c 
b/gnome-flashback/libinput-sources/gf-ibus-manager.c
index 8011318..187dc88 100644
--- a/gnome-flashback/libinput-sources/gf-ibus-manager.c
+++ b/gnome-flashback/libinput-sources/gf-ibus-manager.c
@@ -17,18 +17,291 @@
 
 #include "config.h"
 
+#include "gf-candidate-popup.h"
 #include "gf-ibus-manager.h"
 #include "gf-candidate-popup.h"
 
+#define MAX_INPUT_SOURCE_ACTIVATION_TIME 4000
+
 struct _GfIBusManager
 {
   GObject           parent;
 
+  IBusBus          *ibus;
+  GHashTable       *engines;
+  IBusPanelService *panel_service;
+  GSubprocess      *subprocess;
+
+  gboolean          ready;
+  gulong            register_properties_id;
+
+  gchar            *current_engine_name;
+
   GfCandidatePopup *candidate_popup;
 };
 
 G_DEFINE_TYPE (GfIBusManager, gf_ibus_manager, G_TYPE_OBJECT)
 
+enum
+{
+  SIGNAL_READY,
+  SIGNAL_PROPERTIES_REGISTERED,
+  SIGNAL_PROPERTY_UPDATED,
+  SIGNAL_SET_CONTENT_TYPE,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+spawn (GfIBusManager *manager)
+{
+  GError *error;
+
+  error = NULL;
+  manager->subprocess = g_subprocess_new (G_SUBPROCESS_FLAGS_NONE, &error,
+                                          "ibus-daemon", "--xim",
+                                          "--panel", "disable",
+                                          NULL);
+  if (error)
+    {
+      g_warning ("Failed to launch ibus-daemon: %s", error->message);
+      g_error_free (error);
+    }
+}
+
+static void
+disconnect (GfIBusManager *manager)
+{
+  if (manager->panel_service)
+    {
+      g_object_unref (manager->panel_service);
+      manager->panel_service = NULL;
+    }
+
+  gf_candidate_popup_set_panel_service (manager->candidate_popup, NULL);
+
+  g_hash_table_destroy (manager->engines);
+
+  manager->engines = NULL;
+  manager->ready = FALSE;
+  manager->register_properties_id = 0;
+  manager->current_engine_name = NULL;
+
+  g_signal_emit (manager, signals[SIGNAL_READY], 0, FALSE);
+
+  spawn (manager);
+}
+
+static void
+disconnected_cb (IBusBus       *ibus,
+                 GfIBusManager *manager)
+{
+  disconnect (manager);
+}
+
+static void
+update_readiness (GfIBusManager *manager)
+{
+  manager->ready = g_hash_table_size (manager->engines) > 0
+                   && manager->panel_service != NULL;
+  g_signal_emit (manager, signals[SIGNAL_READY],
+                 0, manager->ready);
+}
+
+static void
+add_to_engines_cb (IBusEngineDesc *engineDescription,
+                   GfIBusManager  *manager)
+{
+  const char *name = ibus_engine_desc_get_name (engineDescription);
+  g_hash_table_insert (manager->engines, g_strdup (name),
+                       g_object_ref (engineDescription));
+}
+
+static void
+init_engines_cb (GObject      *object,
+                 GAsyncResult *result,
+                 gpointer      user_data)
+{
+  GError *error;
+  IBusBus *ibus;
+  GfIBusManager *manager;
+  GList *engine_list;
+
+  error = NULL;
+  ibus = IBUS_BUS (object);
+  manager = GF_IBUS_MANAGER (user_data);
+
+  engine_list = ibus_bus_list_engines_async_finish (ibus,
+                                                    result,
+                                                    &error);
+
+  if (engine_list)
+    {
+      g_list_foreach (engine_list, (GFunc) add_to_engines_cb, manager);
+      update_readiness (manager);
+    }
+  else
+    {
+      disconnect (manager);
+    }
+}
+
+static void
+update_property_cb (IBusPanelService *panel_service,
+                    IBusProperty     *property,
+                    GfIBusManager    *manager)
+{
+  g_signal_emit (manager, SIGNAL_PROPERTY_UPDATED, 0,
+                 manager->current_engine_name, property);
+}
+
+static void
+set_content_type_cb (IBusPanelService *panel_service,
+                     guint             purpose,
+                     guint             hints,
+                     GfIBusManager    *manager)
+{
+  g_signal_emit (manager, signals[SIGNAL_SET_CONTENT_TYPE], 0,
+                 purpose, hints, manager);
+}
+
+static void
+register_properties_cb (IBusPanelService *panel_service,
+                        IBusPropList     *properties,
+                        GfIBusManager    *manager)
+{
+  if (!ibus_prop_list_get (properties, 0))
+    return;
+
+  g_signal_handler_disconnect (panel_service,
+                               manager->register_properties_id);
+  manager->register_properties_id = 0;
+
+  g_signal_emit (manager, SIGNAL_PROPERTIES_REGISTERED, 0,
+                 manager->current_engine_name, properties);
+}
+
+static void
+engine_changed_cb (GfIBusManager *manager,
+                   const gchar   *engine_name)
+{
+  g_message ("engine_changed_cb: %s", engine_name);
+  if (!manager->ready)
+    return;
+
+  g_free (manager->current_engine_name);
+  manager->current_engine_name = g_strdup (engine_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      *object,
+                      GAsyncResult *result,
+                      gpointer      user_data)
+{
+  GError *error;
+  IBusBus *ibus;
+  GfIBusManager *manager;
+  IBusEngineDesc *engine_description;
+
+  error = NULL;
+  ibus = IBUS_BUS (object);
+  manager = GF_IBUS_MANAGER (user_data);
+
+  engine_description = ibus_bus_get_global_engine_async_finish (ibus,
+                                                                result,
+                                                                &error);
+
+  if (error)
+    {
+      g_warning ("Could not get result for 'ibus_bus_get_global_async': %s",
+                 error->message);
+      disconnect (manager);
+      g_error_free (error);
+    }
+
+  if (!engine_description)
+    return;
+
+  engine_changed_cb (manager, ibus_engine_desc_get_name (engine_description));
+}
+
+static void
+init_panel_service_cb (GObject       *object,
+                       GAsyncResult  *result,
+                       gpointer       user_data)
+{
+  GError *error;
+  IBusBus *ibus;
+  gboolean success;
+  GfIBusManager *manager;
+  GDBusConnection *connection;
+
+  error = NULL;
+  ibus = IBUS_BUS (object);
+  manager = GF_IBUS_MANAGER (user_data);
+  success = ibus_bus_request_name_async_finish (ibus,
+                                                result,
+                                                &error);
+
+  if (error)
+    {
+      g_warning ("Could not get result for 'ibus_bus_request_name_async': %s",
+                 error->message);
+      disconnect (manager);
+      g_error_free (error);
+    }
+
+  if (success)
+    {
+      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);
+      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);
+    }
+  else
+    {
+      disconnect (manager);
+    }
+}
+
+static void
+connected_cb (IBusBus       *ibus,
+              GfIBusManager *manager)
+{
+  manager->engines = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                            g_free, g_object_unref);
+
+  ibus_bus_list_engines_async (ibus, -1, NULL, init_engines_cb, manager);
+
+  ibus_bus_request_name_async (ibus,
+                               IBUS_SERVICE_PANEL,
+                               IBUS_BUS_NAME_FLAG_REPLACE_EXISTING,
+                               -1,
+                               NULL,
+                               init_panel_service_cb,
+                               manager);
+}
+
 static void
 gf_ibus_manager_dispose (GObject *object)
 {
@@ -37,6 +310,7 @@ gf_ibus_manager_dispose (GObject *object)
   manager = GF_IBUS_MANAGER (object);
 
   g_clear_object (&manager->candidate_popup);
+  g_clear_object (&manager->subprocess);
 
   G_OBJECT_CLASS (gf_ibus_manager_parent_class)->dispose (object);
 }
@@ -49,12 +323,64 @@ gf_ibus_manager_class_init (GfIBusManagerClass *manager_class)
   object_class = G_OBJECT_CLASS (manager_class);
 
   object_class->dispose = gf_ibus_manager_dispose;
+
+  signals[SIGNAL_READY] =
+    g_signal_new ("ready",
+                  G_TYPE_FROM_CLASS (manager_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL, NULL,
+                  G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+  signals[SIGNAL_PROPERTIES_REGISTERED] =
+    g_signal_new ("properties-registered",
+                  G_TYPE_FROM_CLASS (manager_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL, NULL,
+                  G_TYPE_NONE, 2, G_TYPE_STRING, IBUS_TYPE_PROP_LIST);
+
+  signals[SIGNAL_PROPERTY_UPDATED] =
+    g_signal_new ("property-updated",
+                  G_TYPE_FROM_CLASS (manager_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL, NULL,
+                  G_TYPE_NONE, 2, G_TYPE_STRING, IBUS_TYPE_PROPERTY);
+
+  signals[SIGNAL_SET_CONTENT_TYPE] =
+    g_signal_new ("set-content-type",
+                  G_TYPE_FROM_CLASS (manager_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL, NULL,
+                  G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
 }
 
 static void
 gf_ibus_manager_init (GfIBusManager *manager)
 {
+  ibus_init ();
+
   manager->candidate_popup = gf_candidate_popup_new ();
+
+  manager->ibus = ibus_bus_new_async ();
+
+  if (ibus_bus_is_connected (manager->ibus))
+    {
+      connected_cb (manager->ibus, manager);
+    }
+  else
+    {
+      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 (engine_changed_cb), manager);
+
+  spawn (manager);
 }
 
 GfIBusManager *
@@ -62,3 +388,46 @@ gf_ibus_manager_new (void)
 {
   return g_object_new (GF_TYPE_IBUS_MANAGER, NULL);
 }
+
+void
+gf_ibus_manager_preload_engines (GfIBusManager       *manager,
+                                 const gchar * const *ids)
+{
+  if (!manager->ibus || g_strv_length ((gchar **) ids) == 0)
+    return;
+
+  ibus_bus_preload_engines_async (manager->ibus,
+                                  ids,
+                                  -1, NULL,
+                                  NULL, NULL);
+}
+
+void
+gf_ibus_manager_set_engine (GfIBusManager       *manager,
+                            const gchar         *id,
+                            GAsyncReadyCallback  callback)
+{
+  if (!manager->ready)
+    {
+      if (callback != NULL)
+        callback (G_OBJECT (manager), NULL, NULL);
+
+      return;
+    }
+
+  ibus_bus_set_global_engine_async (manager->ibus, id,
+                                    MAX_INPUT_SOURCE_ACTIVATION_TIME,
+                                    NULL, callback, manager);
+}
+
+IBusEngineDesc *
+gf_ibus_manager_get_engine_description (GfIBusManager *manager,
+                                        const gchar   *id)
+{
+  g_return_val_if_fail (manager->engines, NULL);
+
+  if (!manager->ready)
+    return NULL;
+
+  return g_hash_table_lookup (manager->engines, id);
+}
diff --git a/gnome-flashback/libinput-sources/gf-ibus-manager.h 
b/gnome-flashback/libinput-sources/gf-ibus-manager.h
index 7886eb5..78b199c 100644
--- a/gnome-flashback/libinput-sources/gf-ibus-manager.h
+++ b/gnome-flashback/libinput-sources/gf-ibus-manager.h
@@ -19,6 +19,7 @@
 #define GF_IBUS_MANAGER_H
 
 #include <glib-object.h>
+#include <ibus-1.0/ibus.h>
 
 #define GF_TYPE_IBUS_MANAGER gf_ibus_manager_get_type ()
 G_DECLARE_FINAL_TYPE (GfIBusManager, gf_ibus_manager,
@@ -26,4 +27,14 @@ G_DECLARE_FINAL_TYPE (GfIBusManager, gf_ibus_manager,
 
 GfIBusManager *gf_ibus_manager_new (void);
 
+void            gf_ibus_manager_preload_engines        (GfIBusManager       *manager,
+                                                        const gchar * const *ids);
+
+void            gf_ibus_manager_set_engine             (GfIBusManager       *manager,
+                                                        const gchar         *id,
+                                                        GAsyncReadyCallback  callback);
+
+IBusEngineDesc *gf_ibus_manager_get_engine_description (GfIBusManager       *manager,
+                                                        const gchar         *id);
+
 #endif


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