[gnome-flashback/wip/segeiger/inputmethods: 5/8] input-sources: add implementation for GfIBusManager
- From: Sebastian Geiger <segeiger src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback/wip/segeiger/inputmethods: 5/8] input-sources: add implementation for GfIBusManager
- Date: Sat, 19 Sep 2015 18:07:15 +0000 (UTC)
commit d648e10ef1698b9697cc89faf85f19c12ab20a74
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 | 363 +++++++++++++++++++-
gnome-flashback/libinput-sources/gf-ibus-manager.h | 11 +
2 files changed, 373 insertions(+), 1 deletions(-)
---
diff --git a/gnome-flashback/libinput-sources/gf-ibus-manager.c
b/gnome-flashback/libinput-sources/gf-ibus-manager.c
index 8011318..9784142 100644
--- a/gnome-flashback/libinput-sources/gf-ibus-manager.c
+++ b/gnome-flashback/libinput-sources/gf-ibus-manager.c
@@ -17,18 +17,284 @@
#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);
+
+ //FIXME: should free the hashtable here
+ 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, (gpointer) name, engineDescription);
+}
+
+static void
+init_engines_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GError *error;
+ IBusBus *ibus;
+ GfIBusManager *manager;
+ GList *engineList;
+
+ error = NULL;
+ ibus = IBUS_BUS (object);
+ manager = GF_IBUS_MANAGER (user_data);
+
+ engineList = ibus_bus_list_engines_async_finish (ibus,
+ result,
+ &error);
+
+ if (engineList)
+ {
+ g_list_foreach (engineList, (GFunc) add_to_engines_cb, manager);
+ update_readiness (manager);
+ }
+ else
+ {
+ disconnect (manager);
+ }
+}
+
+static void
+update_property_cb (IBusPanelService *panelService,
+ IBusProperty *property,
+ GfIBusManager *manager)
+{
+ g_signal_emit (manager, SIGNAL_PROPERTY_UPDATED, 0,
+ manager->current_engine_name, property);
+}
+
+static void
+set_content_type_cb (IBusPanelService *panelService,
+ 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 *panelService,
+ IBusPropList *properties,
+ GfIBusManager *manager)
+{
+ if (!ibus_prop_list_get (properties, 0))
+ return;
+
+ g_signal_handler_disconnect (panelService,
+ 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 *engineName)
+{
+ g_message ("engine_changed_cb: %s", engineName);
+ if (!manager->ready)
+ return;
+
+ g_free (manager->current_engine_name);
+ manager->current_engine_name = g_strdup (engineName);
+
+ 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 *engineDescription;
+
+ error = NULL;
+ ibus = IBUS_BUS (object);
+ manager = GF_IBUS_MANAGER (user_data);
+
+ engineDescription = 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 (!engineDescription)
+ return;
+
+ engine_changed_cb (manager, ibus_engine_desc_get_name (engineDescription));
+
+}
+
+static void
+init_panel_service_cb (IBusBus *ibus,
+ GAsyncResult *result,
+ GfIBusManager *manager)
+{
+ GError *error;
+ gboolean success;
+
+ error = NULL;
+ 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)
+ {
+ manager->panel_service = ibus_panel_service_new (ibus_bus_get_connection (manager->ibus));
+
+ 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_free);
+
+ 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,
+ (GAsyncReadyCallback) init_panel_service_cb,
+ manager);
+}
+
static void
gf_ibus_manager_dispose (GObject *object)
{
@@ -36,7 +302,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 +315,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 +380,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]