Commit 028e4882 authored by Sebastian Geiger's avatar Sebastian Geiger Committed by Alberts Muktupāvels
Browse files

input-sources: implement GfIBusManager

parent 6f342bce
......@@ -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], [
......
......@@ -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
......@@ -43,6 +62,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)
{
......@@ -51,10 +388,31 @@ 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)
{
......@@ -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);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment