[gnome-flashback] input-sources: implement org.gnome.Flashback.InputSources
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] input-sources: implement org.gnome.Flashback.InputSources
- Date: Sun, 22 Dec 2019 22:06:22 +0000 (UTC)
commit 7c699fbc90a7c489e6176d54bff9964e74ded5a6
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Sun Dec 22 20:20:09 2019 +0200
input-sources: implement org.gnome.Flashback.InputSources
gnome-flashback/libinput-sources/Makefile.am | 1 +
.../libinput-sources/gf-input-sources.c | 558 ++++++++++++++++++++-
2 files changed, 558 insertions(+), 1 deletion(-)
---
diff --git a/gnome-flashback/libinput-sources/Makefile.am b/gnome-flashback/libinput-sources/Makefile.am
index 1a4feb9..da61b32 100644
--- a/gnome-flashback/libinput-sources/Makefile.am
+++ b/gnome-flashback/libinput-sources/Makefile.am
@@ -48,6 +48,7 @@ libinput_sources_la_LDFLAGS = \
$(NULL)
libinput_sources_la_LIBADD = \
+ $(top_builddir)/dbus/libdbus.la \
$(top_builddir)/gnome-flashback/libcommon/libcommon.la \
$(INPUT_SOURCES_LIBS) \
$(LIBM) \
diff --git a/gnome-flashback/libinput-sources/gf-input-sources.c
b/gnome-flashback/libinput-sources/gf-input-sources.c
index 40c352c..c60e2a7 100644
--- a/gnome-flashback/libinput-sources/gf-input-sources.c
+++ b/gnome-flashback/libinput-sources/gf-input-sources.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015-2016 Alberts Muktupāvels
+ * Copyright (C) 2015-2019 Alberts Muktupāvels
*
* 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
@@ -23,6 +23,7 @@
#include <locale.h>
#include <utime.h>
+#include "dbus/gf-input-sources-gen.h"
#include "gf-ibus-manager.h"
#include "gf-input-sources.h"
#include "gf-input-source-manager.h"
@@ -34,6 +35,9 @@ struct _GfInputSources
{
GObject parent;
+ guint bus_name_id;
+ GfInputSourcesGen *input_sources;
+
GfIBusManager *ibus_manager;
GfInputSourceManager *input_source_manager;
@@ -877,6 +881,7 @@ current_source_changed_cb (GfInputSourceManager *manager,
GfInputSource *old_source,
GfInputSources *sources)
{
+ gf_input_sources_gen_emit_changed (sources->input_sources);
update_status_icon (sources);
}
@@ -888,6 +893,529 @@ status_icon_settings_changed_cb (GSettings *settings,
update_status_icon (sources);
}
+static void
+append_icon_info (GVariantBuilder *builder,
+ GfInputSources *self)
+{
+ const char *display_name;
+ const char *icon_text;
+ IBusPropList *prop_list;
+
+ display_name = gf_input_source_get_display_name (self->current_source);
+ icon_text = gf_input_source_get_short_name (self->current_source);
+ prop_list = gf_input_source_get_properties (self->current_source);
+
+ if (prop_list != NULL)
+ {
+ guint i;
+
+ for (i = 0; i < prop_list->properties->len; i++)
+ {
+ IBusProperty *prop;
+ const char *key;
+ IBusText *symbol;
+ IBusText *label;
+ const char *tmp;
+
+ prop = ibus_prop_list_get (prop_list, i);
+
+ if (!ibus_property_get_visible (prop))
+ continue;
+
+ key = ibus_property_get_key (prop);
+ if (g_strcmp0 (key, "InputMode") != 0)
+ continue;
+
+ symbol = ibus_property_get_symbol (prop);
+ label = ibus_property_get_label (prop);
+
+ if (symbol != NULL)
+ tmp = ibus_text_get_text (symbol);
+ else
+ tmp = ibus_text_get_text (label);
+
+ if (tmp != NULL && *tmp != '\0' && g_utf8_strlen (tmp, -1) < 3)
+ icon_text = tmp;
+ }
+ }
+
+ g_variant_builder_add (builder, "{sv}", "tooltip",
+ g_variant_new_string (display_name));
+
+ g_variant_builder_add (builder, "{sv}", "icon-text",
+ g_variant_new_string (icon_text));
+}
+
+static const char *
+prop_type_to_string (IBusPropType type)
+{
+ switch (type)
+ {
+ case PROP_TYPE_NORMAL:
+ return "normal";
+
+ case PROP_TYPE_TOGGLE:
+ return "toggle";
+
+ case PROP_TYPE_RADIO:
+ return "radio";
+
+ case PROP_TYPE_MENU:
+ return "menu";
+
+ case PROP_TYPE_SEPARATOR:
+ return "separator";
+
+ default:
+ break;
+ }
+
+ return "unknown";
+}
+
+static const char *
+prop_state_to_string (IBusPropState state)
+{
+ switch (state)
+ {
+ case PROP_STATE_UNCHECKED:
+ return "unchecked";
+
+ case PROP_STATE_CHECKED:
+ return "checked";
+
+ case PROP_STATE_INCONSISTENT:
+ return "inconsistent";
+
+ default:
+ break;
+ }
+
+ return "unknown";
+}
+
+static GVariant *
+prop_list_to_variant (IBusPropList *prop_list)
+{
+ GVariantBuilder builder;
+ guint i;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sa{sv})"));
+
+ if (prop_list == NULL)
+ return g_variant_builder_end (&builder);
+
+ for (i = 0; i < prop_list->properties->len; i++)
+ {
+ IBusProperty *prop;
+ GVariantBuilder prop_builder;
+ IBusText *label;
+ IBusText *tooltip;
+ IBusPropType type;
+ IBusPropState state;
+ IBusPropList *sub_props;
+ const char *string;
+
+ prop = ibus_prop_list_get (prop_list, i);
+
+ if (!ibus_property_get_visible (prop))
+ continue;
+
+ g_variant_builder_init (&prop_builder, G_VARIANT_TYPE ("a{sv}"));
+
+ label = ibus_property_get_label (prop);
+ tooltip = ibus_property_get_tooltip (prop);
+ type = ibus_property_get_prop_type (prop);
+ state = ibus_property_get_state (prop);
+ sub_props = ibus_property_get_sub_props (prop);
+
+ string = ibus_property_get_icon (prop);
+ g_variant_builder_add (&prop_builder, "{sv}", "icon",
+ g_variant_new_string (string));
+
+ string = ibus_text_get_text (label);
+ g_variant_builder_add (&prop_builder, "{sv}", "label",
+ g_variant_new_string (string));
+
+ string = ibus_text_get_text (tooltip);
+ g_variant_builder_add (&prop_builder, "{sv}", "tooltip",
+ g_variant_new_string (string));
+
+ string = prop_type_to_string (type);
+ g_variant_builder_add (&prop_builder, "{sv}", "type",
+ g_variant_new_string (string));
+
+ string = prop_state_to_string (state);
+ g_variant_builder_add (&prop_builder, "{sv}", "state",
+ g_variant_new_string (string));
+
+ if (type == PROP_TYPE_MENU)
+ {
+ g_variant_builder_add (&prop_builder, "{sv}", "menu",
+ prop_list_to_variant (sub_props));
+ }
+
+ g_variant_builder_add (&builder,
+ "(sa{sv})",
+ ibus_property_get_key (prop),
+ &prop_builder);
+ }
+
+ return g_variant_builder_end (&builder);
+}
+
+static void
+append_properties (GVariantBuilder *builder,
+ GfInputSources *self)
+{
+ IBusPropList *prop_list;
+ GVariant *properties;
+
+ prop_list = gf_input_source_get_properties (self->current_source);
+ properties = prop_list_to_variant (prop_list);
+
+ g_variant_builder_add (builder, "{sv}", "properties", properties);
+}
+
+static void
+append_layout_info (GVariantBuilder *builder,
+ GfInputSources *self)
+{
+ char *layout;
+ char *layout_variant;
+ const char *type;
+ const char *id;
+ GVariant *variant;
+
+ layout = NULL;
+ layout_variant = NULL;
+
+ type = gf_input_source_get_source_type (self->current_source);
+ id = gf_input_source_get_id (self->current_source);
+
+ if (g_strcmp0 (type, INPUT_SOURCE_TYPE_XKB) == 0)
+ {
+ GnomeXkbInfo *info;
+ const char *xkb_layout;
+ const char *xkb_variant;
+
+ info = gnome_xkb_info_new ();
+
+ gnome_xkb_info_get_layout_info (info,
+ id,
+ NULL,
+ NULL,
+ &xkb_layout,
+ &xkb_variant);
+
+ layout = g_strdup (xkb_layout);
+ layout_variant = g_strdup (xkb_variant);
+
+ g_clear_object (&info);
+ }
+ else if (g_strcmp0 (type, INPUT_SOURCE_TYPE_IBUS) == 0)
+ {
+ IBusEngineDesc *engine_desc;
+
+ engine_desc = gf_ibus_manager_get_engine_desc (self->ibus_manager, id);
+
+ if (engine_desc)
+ {
+ const char *ibus_layout;
+ const char *ibus_variant;
+
+ ibus_layout = ibus_engine_desc_get_layout (engine_desc);
+ ibus_variant = ibus_engine_desc_get_layout_variant (engine_desc);
+
+ layout = g_strdup (ibus_layout);
+ layout_variant = g_strdup (ibus_variant);
+ }
+ }
+
+ if (layout != NULL)
+ {
+ variant = g_variant_new_string (layout);
+ g_variant_builder_add (builder, "{sv}", "layout", variant);
+ }
+
+ if (layout_variant != NULL)
+ {
+ variant = g_variant_new_string (layout_variant);
+ g_variant_builder_add (builder, "{sv}", "layout-variant", variant);
+ }
+
+ g_free (layout_variant);
+ g_free (layout);
+}
+
+static GVariant *
+get_input_sources (GfInputSources *self)
+{
+ GVariantBuilder builder;
+ GList *input_sources;
+ GList *l;
+
+ g_variant_builder_init (&builder,
+ G_VARIANT_TYPE ("a(ussb)"));
+
+ input_sources = gf_input_source_manager_get_input_sources (self->input_source_manager);
+
+ for (l = input_sources; l != NULL; l = l->next)
+ {
+ GfInputSource *input_source;
+
+ input_source = GF_INPUT_SOURCE (l->data);
+
+ g_variant_builder_add (&builder,
+ "(ussb)",
+ gf_input_source_get_index (input_source),
+ gf_input_source_get_short_name (input_source),
+ gf_input_source_get_display_name (input_source),
+ input_source == self->current_source);
+ }
+
+ g_list_free (input_sources);
+
+ return g_variant_builder_end (&builder);
+}
+
+static GVariant *
+get_current_source (GfInputSources *self)
+{
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder,
+ G_VARIANT_TYPE ("a{sv}"));
+
+ append_icon_info (&builder, self);
+ append_layout_info (&builder, self);
+ append_properties (&builder, self);
+
+ return g_variant_builder_end (&builder);
+}
+
+static IBusProperty *
+find_ibus_property (IBusPropList *prop_list,
+ const char *find_key)
+{
+ guint i;
+
+ if (prop_list == NULL)
+ return NULL;
+
+ for (i = 0; i < prop_list->properties->len; i++)
+ {
+ IBusProperty *prop;
+ const char *key;
+ IBusPropList *sub_props;
+
+ prop = ibus_prop_list_get (prop_list, i);
+ key = ibus_property_get_key (prop);
+
+ if (g_strcmp0 (key, find_key) == 0)
+ return prop;
+
+ sub_props = ibus_property_get_sub_props (prop);
+ prop = find_ibus_property (sub_props, find_key);
+
+ if (prop != NULL)
+ return prop;
+ }
+
+ return NULL;
+}
+
+static void
+activate_ibus_property (GfInputSources *self,
+ const char *key,
+ IBusProperty *property)
+{
+ IBusPropType type;
+ IBusPropState state;
+
+ type = ibus_property_get_prop_type (property);
+ state = ibus_property_get_state (property);
+
+ switch (type)
+ {
+ case PROP_TYPE_TOGGLE:
+ case PROP_TYPE_RADIO:
+ if (state == PROP_STATE_CHECKED)
+ state = PROP_STATE_UNCHECKED;
+ else
+ state = PROP_STATE_CHECKED;
+
+ ibus_property_set_state (property, state);
+ break;
+
+ case PROP_TYPE_MENU:
+ case PROP_TYPE_SEPARATOR:
+ g_assert_not_reached ();
+ break;
+
+ case PROP_TYPE_NORMAL:
+ default:
+ break;
+ }
+
+ gf_ibus_manager_activate_property (self->ibus_manager, key, state);
+}
+
+static gboolean
+handle_get_input_sources_cb (GfInputSourcesGen *object,
+ GDBusMethodInvocation *invocation,
+ GfInputSources *self)
+{
+ GVariant *input_sources;
+ GVariant *current_source;
+
+ input_sources = get_input_sources (self);
+ current_source = get_current_source (self);
+
+ gf_input_sources_gen_complete_get_input_sources (object,
+ invocation,
+ input_sources,
+ current_source);
+
+ return TRUE;
+}
+
+static gboolean
+handle_activate_cb (GfInputSourcesGen *object,
+ GDBusMethodInvocation *invocation,
+ guint index,
+ GfInputSources *self)
+{
+ GfInputSource *input_source;
+ GList *input_sources;
+ GList *l;
+
+ input_source = NULL;
+ input_sources = gf_input_source_manager_get_input_sources (self->input_source_manager);
+
+ for (l = input_sources; l != NULL; l = g_list_next (l))
+ {
+ input_source = GF_INPUT_SOURCE (l->data);
+
+ if (gf_input_source_get_index (input_source) == index)
+ break;
+
+ input_source = NULL;
+ }
+
+ g_list_free (input_sources);
+
+ if (input_source == NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Input source with index %d does not exist",
+ index);
+
+ return TRUE;
+ }
+
+ gf_input_source_activate (input_source, TRUE);
+ gf_input_sources_gen_complete_activate (object, invocation);
+
+ return TRUE;
+}
+
+static gboolean
+handle_activate_property_cb (GfInputSourcesGen *object,
+ GDBusMethodInvocation *invocation,
+ const char *key,
+ GfInputSources *self)
+{
+ IBusPropList *prop_list;
+ IBusProperty *prop;
+
+ prop_list = gf_input_source_get_properties (self->current_source);
+
+ if (prop_list == NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Input source does not have properties");
+
+ return TRUE;
+ }
+
+ prop = find_ibus_property (prop_list, key);
+
+ if (prop == NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Input source does not have %s property",
+ key);
+
+ return TRUE;
+ }
+
+ activate_ibus_property (self, key, prop);
+ gf_input_sources_gen_complete_activate_property (object, invocation);
+
+ return TRUE;
+}
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GfInputSources *sources;
+ GDBusInterfaceSkeleton *skeleton;
+ GError *error;
+ gboolean exported;
+
+ sources = GF_INPUT_SOURCES (user_data);
+ skeleton = G_DBUS_INTERFACE_SKELETON (sources->input_sources);
+
+ g_signal_connect (skeleton, "handle-get-input-sources",
+ G_CALLBACK (handle_get_input_sources_cb),
+ sources);
+
+ g_signal_connect (skeleton, "handle-activate",
+ G_CALLBACK (handle_activate_cb),
+ sources);
+
+ g_signal_connect (skeleton, "handle-activate-property",
+ G_CALLBACK (handle_activate_property_cb),
+ sources);
+
+ error = NULL;
+ exported = g_dbus_interface_skeleton_export (skeleton,
+ connection,
+ "/org/gnome/Flashback/InputSources",
+ &error);
+
+ if (!exported)
+ {
+ g_warning ("Failed to export interface: %s", error->message);
+ g_error_free (error);
+
+ return;
+ }
+}
+
+static void
+name_acquired_cb (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+}
+
+static void
+name_lost_cb (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+}
+
static void
gf_input_sources_dispose (GObject *object)
{
@@ -895,6 +1423,22 @@ gf_input_sources_dispose (GObject *object)
sources = GF_INPUT_SOURCES (object);
+ if (sources->bus_name_id != 0)
+ {
+ g_bus_unown_name (sources->bus_name_id);
+ sources->bus_name_id = 0;
+ }
+
+ if (sources->input_sources)
+ {
+ GDBusInterfaceSkeleton *skeleton;
+
+ skeleton = G_DBUS_INTERFACE_SKELETON (sources->input_sources);
+
+ g_dbus_interface_skeleton_unexport (skeleton);
+ g_clear_object (&sources->input_sources);
+ }
+
g_clear_object (&sources->ibus_manager);
g_clear_object (&sources->input_source_manager);
@@ -934,6 +1478,18 @@ gf_input_sources_init (GfInputSources *sources)
{
const gchar *cache_dir;
+ sources->input_sources = gf_input_sources_gen_skeleton_new ();
+
+ sources->bus_name_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+ "org.gnome.Flashback.InputSources",
+ G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
+ G_BUS_NAME_OWNER_FLAGS_REPLACE,
+ bus_acquired_cb,
+ name_acquired_cb,
+ name_lost_cb,
+ sources,
+ NULL);
+
sources->ibus_manager = gf_ibus_manager_new ();
sources->input_source_manager = gf_input_source_manager_new (sources->ibus_manager);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]