From d6bf0e42b2c6515f33cd3f8dc621431b277a9fb1 Mon Sep 17 00:00:00 2001 From: Takao Fujiwara Date: Fri, 2 Mar 2018 17:34:59 +0900 Subject: [PATCH] Removed ibus-HEAD.patch --- ibus-HEAD.patch | 10021 ---------------------------------------------- 1 file changed, 10021 deletions(-) delete mode 100644 ibus-HEAD.patch diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch deleted file mode 100644 index fa81971..0000000 --- a/ibus-HEAD.patch +++ /dev/null @@ -1,10021 +0,0 @@ -From bfe57d20e9d39d52428e95e493d9af0bd034a82f Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Mon, 15 Jan 2018 14:44:07 +0900 -Subject: [PATCH] Added DBus filtering against malware - -The proposal prevents non-ower of the GDBusConnection from accessing -DBus methods against malicious usages. - -BUG=https://github.com/ibus/ibus/issues/1955 - -Review URL: https://codereview.appspot.com/335380043 ---- - bus/inputcontext.c | 24 +++++++++++++++++++++++- - src/ibusengine.c | 18 +++++++++++++++++- - src/ibuspanelservice.c | 14 +++++++++++++- - 3 files changed, 53 insertions(+), 3 deletions(-) - -diff --git a/bus/inputcontext.c b/bus/inputcontext.c -index d8be9e3f..4f2ecafc 100644 ---- a/bus/inputcontext.c -+++ b/bus/inputcontext.c -@@ -2,7 +2,7 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2014 Peng Huang -- * Copyright (C) 2015-2017 Takao Fujiwara -+ * Copyright (C) 2015-2018 Takao Fujiwara - * Copyright (C) 2008-2016 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or -@@ -1148,6 +1148,20 @@ _ic_set_surrounding_text (BusInputContext *context, - g_dbus_method_invocation_return_value (invocation, NULL); - } - -+/* -+ * Since IBusService is inherited by IBusImpl, this method cannot be -+ * applied to IBusServiceClass.method_call() directly but can be in -+ * each child class.method_call(). -+ */ -+static gboolean -+bus_input_context_service_authorized_method (IBusService *service, -+ GDBusConnection *connection) -+{ -+ if (ibus_service_get_connection (service) == connection) -+ return TRUE; -+ return FALSE; -+} -+ - /** - * bus_input_context_service_method_call: - * -@@ -1197,6 +1211,10 @@ bus_input_context_service_method_call (IBusService *service, - }; - - gint i; -+ -+ if (!bus_input_context_service_authorized_method (service, connection)) -+ return; -+ - for (i = 0; i < G_N_ELEMENTS (methods); i++) { - if (g_strcmp0 (method_name, methods[i].method_name) == 0) { - methods[i].method_callback ((BusInputContext *)service, parameters, invocation); -@@ -1270,6 +1288,9 @@ bus_input_context_service_set_property (IBusService *service, - error); - } - -+ if (!bus_input_context_service_authorized_method (service, connection)) -+ return FALSE; -+ - if (g_strcmp0 (property_name, "ContentType") == 0) { - BusInputContext *context = (BusInputContext *) service; - _ic_set_content_type (context, value); -@@ -1279,6 +1300,7 @@ bus_input_context_service_set_property (IBusService *service, - g_return_val_if_reached (FALSE); - } - -+ - gboolean - bus_input_context_has_focus (BusInputContext *context) - { -diff --git a/src/ibusengine.c b/src/ibusengine.c -index b2a8022a..da648d11 100644 ---- a/src/ibusengine.c -+++ b/src/ibusengine.c -@@ -2,7 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2008-2013 Red Hat, Inc. -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -851,6 +852,15 @@ ibus_engine_get_property (IBusEngine *engine, - } - } - -+static gboolean -+ibus_engine_service_authorized_method (IBusService *service, -+ GDBusConnection *connection) -+{ -+ if (ibus_service_get_connection (service) == connection) -+ return TRUE; -+ return FALSE; -+} -+ - static void - ibus_engine_service_method_call (IBusService *service, - GDBusConnection *connection, -@@ -876,6 +886,9 @@ ibus_engine_service_method_call (IBusService *service, - return; - } - -+ if (!ibus_engine_service_authorized_method (service, connection)) -+ return; -+ - if (g_strcmp0 (method_name, "ProcessKeyEvent") == 0) { - guint keyval, keycode, state; - gboolean retval = FALSE; -@@ -1085,6 +1098,9 @@ ibus_engine_service_set_property (IBusService *service, - error); - } - -+ if (!ibus_engine_service_authorized_method (service, connection)) -+ return FALSE; -+ - if (g_strcmp0 (property_name, "ContentType") == 0) { - guint purpose = 0; - guint hints = 0; -diff --git a/src/ibuspanelservice.c b/src/ibuspanelservice.c -index 468aa324..33949fa1 100644 ---- a/src/ibuspanelservice.c -+++ b/src/ibuspanelservice.c -@@ -3,7 +3,7 @@ - /* ibus - The Input Bus - * Copyright (c) 2009-2014 Google Inc. All rights reserved. - * Copyright (C) 2010-2014 Peng Huang -- * Copyright (C) 2017 Takao Fujiwara -+ * Copyright (C) 2017-2018 Takao Fujiwara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -936,6 +936,15 @@ _g_object_unref_if_floating (gpointer instance) - g_object_unref (instance); - } - -+static gboolean -+ibus_panel_service_service_authorized_method (IBusService *service, -+ GDBusConnection *connection) -+{ -+ if (ibus_service_get_connection (service) == connection) -+ return TRUE; -+ return FALSE; -+} -+ - static void - ibus_panel_service_service_method_call (IBusService *service, - GDBusConnection *connection, -@@ -961,6 +970,9 @@ ibus_panel_service_service_method_call (IBusService *service, - return; - } - -+ if (!ibus_panel_service_service_authorized_method (service, connection)) -+ return; -+ - if (g_strcmp0 (method_name, "UpdatePreeditText") == 0) { - GVariant *variant = NULL; - guint cursor = 0; --- -2.14.3 - -From e17c99859d06ab75326730e45072e1061f7d87c7 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Mon, 29 Jan 2018 16:50:07 +0900 -Subject: [PATCH] Implement Unicode choice on Emojier - -BUG=https://github.com/ibus/ibus/issues/1922 - -Review URL: https://codereview.appspot.com/340190043 ---- - configure.ac | 41 +- - po/POTFILES.in | 1 + - src/Makefile.am | 55 ++- - src/emoji-parser.c | 3 +- - src/ibus.h | 4 +- - src/ibusunicode.c | 1069 +++++++++++++++++++++++++++++++++++++++++ - src/ibusunicode.h | 299 ++++++++++++ - src/ibusunicodegen.h | 1151 +++++++++++++++++++++++++++++++++++++++++++++ - src/unicode-parser.c | 502 ++++++++++++++++++++ - ui/gtk3/emojier.vala | 550 +++++++++++++++++++--- - ui/gtk3/emojierapp.vala | 2 + - ui/gtk3/ibusemojidialog.h | 9 +- - ui/gtk3/panel.vala | 3 +- - 13 files changed, 3613 insertions(+), 76 deletions(-) - create mode 100644 src/ibusunicode.c - create mode 100644 src/ibusunicode.h - create mode 100644 src/ibusunicodegen.h - create mode 100644 src/unicode-parser.c - -diff --git a/configure.ac b/configure.ac -index 4789328e..bd41069b 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3,8 +3,8 @@ - # ibus - The Input Bus - # - # Copyright (c) 2007-2016 Peng Huang --# Copyright (c) 2015-2017 Takao Fujiwara --# Copyright (c) 2007-2017 Red Hat, Inc. -+# Copyright (c) 2015-2018 Takao Fujiwara -+# Copyright (c) 2007-2018 Red Hat, Inc. - # - # This library is free software; you can redistribute it and/or - # modify it under the terms of the GNU Lesser General Public -@@ -653,6 +653,41 @@ https://github.com/fujiwarat/cldr-emoji-annotation) - enable_emoji_dict="yes (enabled, use --disable-emoji-dict to disable)" - fi - -+# --disable-unicode-dict option. -+AC_ARG_ENABLE(unicode-dict, -+ AS_HELP_STRING([--disable-unicode-dict], -+ [Do not build Unicode dict files]), -+ [enable_unicode_dict=$enableval], -+ [enable_unicode_dict=yes] -+) -+AM_CONDITIONAL([ENABLE_UNICODE_DICT], [test x"$enable_unicode_dict" = x"yes"]) -+ -+AC_ARG_WITH(ucd-dir, -+ AS_HELP_STRING([--with-ucd-dir[=DIR]], -+ [Set the directory of UCD (Unicode Character Database) files. -+ (default: "/usr/share/unicode/ucd")]), -+ UCD_DIR=$with_emoji_annotation_dir, -+ UCD_DIR="/usr/share/unicode/ucd" -+) -+AC_SUBST(UCD_DIR) -+ -+if test x"$enable_unicode_dict" = x"yes"; then -+ if test ! -f $UCD_DIR/NamesList.txt ; then -+ AC_MSG_ERROR(Not found $UCD_DIR/NamesList.txt. You can get \ -+the UCD files from https://www.unicode.org/Public/UNIDATA/) -+ elif test ! -f $UCD_DIR/Blocks.txt ; then -+ AC_MSG_ERROR(Not found $UCD_DIR/Blocks.txt. You can get \ -+the UCD files from https://www.unicode.org/Public/UNIDATA/) -+ else -+ # POSIX SHELL has no ${FOO:0:1} -+ head=`echo "$UCD_DIR" | cut -c1`; -+ if test $head != "/" ; then -+ UCD_DIR=`realpath "$UCD_DIR"` -+ fi -+ fi -+ enable_unicode_dict="yes (enabled, use --disable-unicode-dict to disable)" -+fi -+ - # Check iso-codes. - PKG_CHECK_MODULES(ISOCODES, [ - iso-codes -@@ -743,6 +778,8 @@ Build options: - Enable Emoji dict $enable_emoji_dict - Unicode Emoji directory $UNICODE_EMOJI_DIR - CLDR annotation directory $EMOJI_ANNOTATION_DIR -+ Enable Unicode dict $enable_unicode_dict -+ UCD directory $UCD_DIR - Run test cases $enable_tests - ]) - -diff --git a/po/POTFILES.in b/po/POTFILES.in -index 00f7c7f6..58d1e39d 100644 ---- a/po/POTFILES.in -+++ b/po/POTFILES.in -@@ -51,6 +51,7 @@ src/ibuspanelservice.c - src/ibusproxy.c - src/ibusregistry.c - src/ibusservice.c -+src/ibusunicodegen.h - src/ibusutil.c - src/keyname-table.h - tools/main.vala -diff --git a/src/Makefile.am b/src/Makefile.am -index 303250f5..1ba418d8 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -41,6 +41,7 @@ INTROSPECTION_COMPILER_ARGS = \ - $(NULL) - INTROSPECTION_GIRS = - CLEANFILES = -+noinst_PROGRAMS = - - # C preprocessor flags - AM_CPPFLAGS = \ -@@ -100,6 +101,7 @@ ibus_sources = \ - ibusservice.c \ - ibusshare.c \ - ibustext.c \ -+ ibusunicode.c \ - ibusutil.c \ - ibusxml.c \ - $(NULL) -@@ -151,6 +153,7 @@ ibus_headers = \ - ibusshare.h \ - ibustext.h \ - ibustypes.h \ -+ ibusunicode.h \ - ibusutil.h \ - ibusxml.h \ - $(NULL) -@@ -169,6 +172,7 @@ ibus_private_headers = \ - ibusemojigen.h \ - ibusenginesimpleprivate.h \ - ibusinternal.h \ -+ ibusunicodegen.h \ - keyname-table.h \ - $(NULL) - noinst_HEADERS = \ -@@ -241,7 +245,7 @@ dictdir = $(pkgdatadir)/dicts - dict_DATA = dicts/emoji-en.dict - LANG_FILES = $(basename $(notdir $(wildcard $(EMOJI_ANNOTATION_DIR)/*.xml))) - --noinst_PROGRAMS = emoji-parser -+noinst_PROGRAMS += emoji-parser - - dicts/emoji-en.dict: emoji-parser - $(AM_V_at)if test x"$(LANG_FILES)" = x ; then \ -@@ -325,12 +329,60 @@ clean-local: - $(NULL) - endif - -+if ENABLE_UNICODE_DICT -+unicodedir = $(pkgdatadir)/dicts -+unicode_DATA = dicts/unicode-names.dict dicts/unicode-blocks.dict -+noinst_PROGRAMS += unicode-parser -+ -+dicts/unicode-names.dict: unicode-parser -+ $(AM_V_at)input_file="$(UCD_DIR)/NamesList.txt"; \ -+ if test ! -f "$$input_file" ; then \ -+ echo "WARNING: Not found $$input_file" 1>&2; \ -+ else \ -+ $(builddir)/unicode-parser \ -+ --input-names-list $$input_file \ -+ --output-names-list $@; \ -+ echo "Generated $@"; \ -+ fi; -+ -+dicts/unicode-blocks.dict: unicode-parser -+ $(AM_V_at)input_file="$(UCD_DIR)/Blocks.txt"; \ -+ if test ! -f "$$input_file" ; then \ -+ echo "WARNING: Not found $$input_file" 1>&2; \ -+ else \ -+ $(builddir)/unicode-parser \ -+ --input-blocks $$input_file \ -+ --output-blocks-trans ibusunicodegen.h \ -+ --output-blocks $@; \ -+ echo "Generated $@"; \ -+ fi; -+ -+ibusunicodegen.h: dicts/unicode-blocks.dict -+ $(NULL) -+ -+unicode_parser_SOURCES = \ -+ unicode-parser.c \ -+ $(NULL) -+unicode_parser_CFLAGS = \ -+ $(GLIB2_CFLAGS) \ -+ $(NULL) -+unicode_parser_LDADD = \ -+ $(GLIB2_LIBS) \ -+ $(libibus) \ -+ $(NULL) -+ -+clean-local: -+ -rm -rf dicts -+ $(NULL) -+endif -+ - EXTRA_DIST = \ - emoji-parser.c \ - ibusversion.h.in \ - ibusmarshalers.list \ - ibusenumtypes.h.template \ - ibusenumtypes.c.template \ -+ unicode-parser.c \ - $(NULL) - - CLEANFILES += \ -@@ -341,6 +393,7 @@ CLEANFILES += \ - - DISTCLEANFILES = \ - ibusemojigen.h \ -+ ibusunicodegen.h \ - ibusversion.h \ - $(NULL) - -diff --git a/src/emoji-parser.c b/src/emoji-parser.c -index fe3e4ef8..0f7c8cfb 100644 ---- a/src/emoji-parser.c -+++ b/src/emoji-parser.c -@@ -1,7 +1,7 @@ - /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ - /* vim:set et sts=4: */ - /* ibus - The Input Bus -- * Copyright (C) 2016-2017 Takao Fujiwara -+ * Copyright (C) 2016-2018 Takao Fujiwara - * Copyright (C) 2016 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or -@@ -1126,6 +1126,7 @@ category_file_save (const gchar *filename, - if (!g_file_get_contents (__FILE__, &content, &length, &error)) { - g_warning ("Failed to load %s: %s", __FILE__, error->message); - g_clear_pointer (&error, g_error_free); -+ return; - } - buff = g_string_new (NULL); - p = content; -diff --git a/src/ibus.h b/src/ibus.h -index c6cf58cf..8011729f 100644 ---- a/src/ibus.h -+++ b/src/ibus.h -@@ -2,7 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2008-2013 Red Hat, Inc. -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -57,6 +58,7 @@ - #include - #include - #include -+#include - - #ifndef IBUS_DISABLE_DEPRECATED - #include -diff --git a/src/ibusunicode.c b/src/ibusunicode.c -new file mode 100644 -index 00000000..8559819d ---- /dev/null -+++ b/src/ibusunicode.c -@@ -0,0 +1,1069 @@ -+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -+/* vim:set et sts=4: */ -+/* bus - The Input Bus -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2018 Red Hat, Inc. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -+ * USA -+ */ -+#ifdef HAVE_CONFIG_H -+#include -+#endif -+ -+#include -+#include -+#include "ibusinternal.h" -+#include "ibuserror.h" -+#include "ibusunicode.h" -+ -+#define IBUS_UNICODE_DATA_MAGIC "IBusUnicodeData" -+#define IBUS_UNICODE_BLOCK_MAGIC "IBusUnicodeBlock" -+#define IBUS_UNICODE_DATA_VERSION (1) -+#define IBUS_UNICODE_DESERIALIZE_SIGNALL_STR \ -+ "deserialize-unicode" -+ -+enum { -+ PROP_0 = 0, -+ PROP_CODE, -+ PROP_NAME, -+ PROP_ALIAS, -+ PROP_BLOCK_NAME, -+ PROP_START, -+ PROP_END -+}; -+ -+struct _IBusUnicodeDataPrivate { -+ gunichar code; -+ gchar *name; -+ gchar *alias; -+ gchar *block_name; -+}; -+ -+struct _IBusUnicodeBlockPrivate { -+ gunichar start; -+ gunichar end; -+ gchar *name; -+}; -+ -+typedef struct { -+ IBusUnicodeDataLoadAsyncFinish callback; -+ gpointer user_data; -+} IBusUnicodeDataLoadData; -+ -+#define IBUS_UNICODE_DATA_GET_PRIVATE(o) \ -+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ -+ IBUS_TYPE_UNICODE_DATA, \ -+ IBusUnicodeDataPrivate)) -+#define IBUS_UNICODE_BLOCK_GET_PRIVATE(o) \ -+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ -+ IBUS_TYPE_UNICODE_BLOCK, \ -+ IBusUnicodeBlockPrivate)) -+ -+/* functions prototype */ -+static void ibus_unicode_data_set_property (IBusUnicodeData *unicode, -+ guint prop_id, -+ const GValue *value, -+ GParamSpec *pspec); -+static void ibus_unicode_data_get_property (IBusUnicodeData *unicode, -+ guint prop_id, -+ GValue *value, -+ GParamSpec *pspec); -+static void ibus_unicode_data_destroy (IBusUnicodeData *unicode); -+static gboolean ibus_unicode_data_serialize (IBusUnicodeData *unicode, -+ GVariantBuilder *builder); -+static gint ibus_unicode_data_deserialize (IBusUnicodeData *unicode, -+ GVariant *variant); -+static gboolean ibus_unicode_data_copy (IBusUnicodeData *dest, -+ const IBusUnicodeData *src); -+static void ibus_unicode_block_set_property -+ (IBusUnicodeBlock *block, -+ guint prop_id, -+ const GValue *value, -+ GParamSpec *pspec); -+static void ibus_unicode_block_get_property -+ (IBusUnicodeBlock *block, -+ guint prop_id, -+ GValue *value, -+ GParamSpec *pspec); -+static void ibus_unicode_block_destroy (IBusUnicodeBlock *block); -+static gboolean ibus_unicode_block_serialize (IBusUnicodeBlock *block, -+ GVariantBuilder *builder); -+static gint ibus_unicode_block_deserialize (IBusUnicodeBlock *block, -+ GVariant *variant); -+static gboolean ibus_unicode_block_copy (IBusUnicodeBlock *dest, -+ const IBusUnicodeBlock *src); -+ -+G_DEFINE_TYPE (IBusUnicodeData, ibus_unicode_data, IBUS_TYPE_SERIALIZABLE) -+G_DEFINE_TYPE (IBusUnicodeBlock, ibus_unicode_block, IBUS_TYPE_SERIALIZABLE) -+ -+static void -+ibus_unicode_data_class_init (IBusUnicodeDataClass *class) -+{ -+ IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class); -+ GObjectClass *gobject_class = G_OBJECT_CLASS (class); -+ IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class); -+ -+ object_class->destroy = (IBusObjectDestroyFunc) ibus_unicode_data_destroy; -+ gobject_class->set_property = -+ (GObjectSetPropertyFunc) ibus_unicode_data_set_property; -+ gobject_class->get_property = -+ (GObjectGetPropertyFunc) ibus_unicode_data_get_property; -+ serializable_class->serialize = -+ (IBusSerializableSerializeFunc) ibus_unicode_data_serialize; -+ serializable_class->deserialize = -+ (IBusSerializableDeserializeFunc) ibus_unicode_data_deserialize; -+ serializable_class->copy = -+ (IBusSerializableCopyFunc) ibus_unicode_data_copy; -+ -+ g_type_class_add_private (class, sizeof (IBusUnicodeDataPrivate)); -+ -+ /* install properties */ -+ /** -+ * IBusUnicodeData:code: -+ * -+ * The Uniode code point -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_CODE, -+ g_param_spec_unichar ("code", -+ "code point", -+ "The Unicode code point", -+ 0, -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -+ -+ -+ /** -+ * IBusUnicodeData:name: -+ * -+ * The Uniode name -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_NAME, -+ g_param_spec_string ("name", -+ "name", -+ "The Unicode name", -+ "", -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); -+ -+ /** -+ * IBusUnicodeData:alias: -+ * -+ * The Uniode alias name -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_ALIAS, -+ g_param_spec_string ("alias", -+ "alias name", -+ "The Unicode alias name", -+ "", -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); -+ -+ /** -+ * IBusUnicodeData:block-name: -+ * -+ * The Uniode block name -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_BLOCK_NAME, -+ g_param_spec_string ("block-name", -+ "block name", -+ "The Unicode block name", -+ "", -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); -+} -+ -+static void -+ibus_unicode_data_init (IBusUnicodeData *unicode) -+{ -+ unicode->priv = IBUS_UNICODE_DATA_GET_PRIVATE (unicode); -+} -+ -+static void -+ibus_unicode_data_destroy (IBusUnicodeData *unicode) -+{ -+ g_clear_pointer (&unicode->priv->name, g_free); -+ g_clear_pointer (&unicode->priv->alias, g_free); -+ g_clear_pointer (&unicode->priv->block_name, g_free); -+ -+ IBUS_OBJECT_CLASS (ibus_unicode_data_parent_class)-> -+ destroy (IBUS_OBJECT (unicode)); -+} -+ -+static void -+ibus_unicode_data_set_property (IBusUnicodeData *unicode, -+ guint prop_id, -+ const GValue *value, -+ GParamSpec *pspec) -+{ -+ switch (prop_id) { -+ case PROP_CODE: -+ g_assert (unicode->priv->code == 0); -+ unicode->priv->code = g_value_get_uint (value); -+ break; -+ case PROP_NAME: -+ g_assert (unicode->priv->name == NULL); -+ unicode->priv->name = g_value_dup_string (value); -+ break; -+ case PROP_ALIAS: -+ g_assert (unicode->priv->alias == NULL); -+ unicode->priv->alias = g_value_dup_string (value); -+ break; -+ case PROP_BLOCK_NAME: -+ g_free (unicode->priv->block_name); -+ unicode->priv->block_name = g_value_dup_string (value); -+ break; -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (unicode, prop_id, pspec); -+ } -+} -+ -+static void -+ibus_unicode_data_get_property (IBusUnicodeData *unicode, -+ guint prop_id, -+ GValue *value, -+ GParamSpec *pspec) -+{ -+ switch (prop_id) { -+ case PROP_CODE: -+ g_value_set_uint (value, ibus_unicode_data_get_code (unicode)); -+ break; -+ case PROP_NAME: -+ g_value_set_string (value, ibus_unicode_data_get_name (unicode)); -+ break; -+ case PROP_ALIAS: -+ g_value_set_string (value, ibus_unicode_data_get_alias (unicode)); -+ break; -+ case PROP_BLOCK_NAME: -+ g_value_set_string (value, ibus_unicode_data_get_block_name (unicode)); -+ break; -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (unicode, prop_id, pspec); -+ } -+} -+ -+static gboolean -+ibus_unicode_data_serialize (IBusUnicodeData *unicode, -+ GVariantBuilder *builder) -+{ -+ gboolean retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_data_parent_class)-> -+ serialize ((IBusSerializable *)unicode, builder); -+ g_return_val_if_fail (retval, FALSE); -+ -+#define NOTNULL(s) ((s) != NULL ? (s) : "") -+ /* If you will add a new property, you can append it at the end and -+ * you should not change the serialized order of name, longname, -+ * description, ... because the order is also used in other applications -+ * likes ibus-qt. */ -+ g_variant_builder_add (builder, "u", unicode->priv->code); -+ g_variant_builder_add (builder, "s", NOTNULL (unicode->priv->name)); -+ g_variant_builder_add (builder, "s", NOTNULL (unicode->priv->alias)); -+ /* Use IBusUnicodeBlock for memory usage. -+ g_variant_builder_add (builder, "s", NOTNULL (unicode->priv->block_name)); -+ */ -+#undef NOTNULL -+ return TRUE; -+} -+ -+static gint -+ibus_unicode_data_deserialize (IBusUnicodeData *unicode, -+ GVariant *variant) -+{ -+ gint retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_data_parent_class)-> -+ deserialize ((IBusSerializable *)unicode, variant); -+ g_return_val_if_fail (retval, 0); -+ -+ /* If you will add a new property, you can append it at the end and -+ * you should not change the serialized order of name, longname, -+ * description, ... because the order is also used in other applications -+ * likes ibus-qt. */ -+ g_variant_get_child (variant, retval++, "u", &unicode->priv->code); -+ ibus_g_variant_get_child_string (variant, retval++, -+ &unicode->priv->name); -+ ibus_g_variant_get_child_string (variant, retval++, -+ &unicode->priv->alias); -+ /* Use IBusUnicodeBlock for memory usage. -+ ibus_g_variant_get_child_string (variant, retval++, -+ &unicode->priv->block_name); -+ */ -+ return retval; -+} -+ -+static gboolean -+ibus_unicode_data_copy (IBusUnicodeData *dest, -+ const IBusUnicodeData *src) -+{ -+ gboolean retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_data_parent_class)-> -+ copy ((IBusSerializable *)dest, -+ (IBusSerializable *)src); -+ g_return_val_if_fail (retval, FALSE); -+ -+ dest->priv->code = src->priv->code; -+ dest->priv->name = g_strdup (src->priv->name); -+ dest->priv->alias = g_strdup (src->priv->alias); -+ dest->priv->block_name = g_strdup (src->priv->block_name); -+ return TRUE; -+} -+ -+IBusUnicodeData * -+ibus_unicode_data_new (const gchar *first_property_name, ...) -+{ -+ va_list var_args; -+ IBusUnicodeData *unicode; -+ -+ g_assert (first_property_name != NULL); -+ va_start (var_args, first_property_name); -+ unicode = (IBusUnicodeData *) g_object_new_valist (IBUS_TYPE_UNICODE_DATA, -+ first_property_name, -+ var_args); -+ va_end (var_args); -+ /* code is required. Other properties are set in class_init by default. */ -+ g_assert (unicode->priv->name != NULL); -+ g_assert (unicode->priv->alias != NULL); -+ g_assert (unicode->priv->block_name != NULL); -+ return unicode; -+} -+ -+gunichar -+ibus_unicode_data_get_code (IBusUnicodeData *unicode) -+{ -+ g_return_val_if_fail (IBUS_IS_UNICODE_DATA (unicode), G_MAXUINT32); -+ -+ return unicode->priv->code; -+} -+ -+const gchar * -+ibus_unicode_data_get_name (IBusUnicodeData *unicode) -+{ -+ g_return_val_if_fail (IBUS_IS_UNICODE_DATA (unicode), ""); -+ -+ return unicode->priv->name; -+} -+ -+const gchar * -+ibus_unicode_data_get_alias (IBusUnicodeData *unicode) -+{ -+ g_return_val_if_fail (IBUS_IS_UNICODE_DATA (unicode), ""); -+ -+ return unicode->priv->alias; -+} -+ -+const gchar * -+ibus_unicode_data_get_block_name (IBusUnicodeData *unicode) -+{ -+ g_return_val_if_fail (IBUS_IS_UNICODE_DATA (unicode), ""); -+ -+ return unicode->priv->block_name; -+} -+ -+void -+ibus_unicode_data_set_block_name (IBusUnicodeData *unicode, -+ const gchar *block_name) -+{ -+ g_return_if_fail (IBUS_IS_UNICODE_DATA (unicode)); -+ -+ g_free (unicode->priv->block_name); -+ unicode->priv->block_name = g_strdup (block_name); -+} -+ -+static void -+variant_foreach_add_unicode (IBusUnicodeData *unicode, -+ GVariantBuilder *builder) -+{ -+ g_variant_builder_add ( -+ builder, "v", -+ ibus_serializable_serialize (IBUS_SERIALIZABLE (unicode))); -+} -+ -+static GVariant * -+ibus_unicode_data_list_serialize (GSList *list) -+{ -+ GVariantBuilder builder; -+ -+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("av")); -+ g_slist_foreach (list, (GFunc) variant_foreach_add_unicode, &builder); -+ return g_variant_builder_end (&builder); -+} -+ -+static GSList * -+ibus_unicode_data_list_deserialize (GVariant *variant, -+ GObject *source_object) -+{ -+ GSList *list = NULL; -+ GVariantIter iter; -+ GVariant *unicode_variant = NULL; -+ gsize i, size; -+ gboolean has_signal = FALSE; -+ -+ if (G_IS_OBJECT (source_object)) { -+ has_signal = g_signal_lookup ( -+ IBUS_UNICODE_DESERIALIZE_SIGNALL_STR, -+ G_OBJECT_TYPE (source_object)); -+ if (!has_signal) { -+ const gchar type_name = g_type_name (source_object); -+ g_warning ("GObject %s does not have the signal \"%s\"", -+ type_name ? type_name : "(null)", -+ IBUS_UNICODE_DESERIALIZE_SIGNALL_STR); -+ } -+ } -+ g_variant_iter_init (&iter, variant); -+ size = g_variant_iter_n_children (&iter); -+ i = 0; -+ while (g_variant_iter_loop (&iter, "v", &unicode_variant)) { -+ IBusUnicodeData *data = -+ IBUS_UNICODE_DATA (ibus_serializable_deserialize ( -+ unicode_variant)); -+ list = g_slist_append (list, data); -+ g_clear_pointer (&unicode_variant, g_variant_unref); -+ if (has_signal && (i == 0 || ((i + 1) % 100) == 0)) { -+ g_signal_emit_by_name (source_object, -+ IBUS_UNICODE_DESERIALIZE_SIGNALL_STR, -+ i + 1, size); -+ } -+ i++; -+ } -+ if (has_signal && (i != 1 && (i % 100) != 0)) { -+ g_signal_emit_by_name (source_object, -+ IBUS_UNICODE_DESERIALIZE_SIGNALL_STR, -+ i, size); -+ } -+ -+ return list; -+} -+ -+void -+ibus_unicode_data_save (const gchar *path, -+ GSList *list) -+{ -+ GVariant *variant; -+ const gchar *header = IBUS_UNICODE_DATA_MAGIC; -+ const guint16 version = IBUS_UNICODE_DATA_VERSION; -+ const gchar *contents; -+ gsize length; -+ gchar *dir; -+ GStatBuf buf = { 0, }; -+ GError *error = NULL; -+ -+ g_return_if_fail (path != NULL); -+ g_return_if_fail (list != NULL); -+ if (list->data == NULL) { -+ g_warning ("Failed to save IBus Unicode data: Need a list data."); -+ return; -+ } -+ -+ variant = g_variant_new ("(sqv)", -+ header, -+ version, -+ ibus_unicode_data_list_serialize (list)); -+ -+ contents = g_variant_get_data (variant); -+ length = g_variant_get_size (variant); -+ -+ dir = g_path_get_dirname (path); -+ if (g_strcmp0 (dir, ".") != 0 && g_stat (dir, &buf) != 0) { -+ g_mkdir_with_parents (dir, 0777); -+ } -+ g_free (dir); -+ if (!g_file_set_contents (path, contents, length, &error)) { -+ g_warning ("Failed to save Unicode dict %s: %s", path, error->message); -+ g_error_free (error); -+ } -+ -+ g_variant_unref (variant); -+} -+ -+static GSList * -+ibus_unicode_data_load_with_error (const gchar *path, -+ GObject *source_object, -+ GError **error) -+{ -+ gchar *contents = NULL; -+ gsize length = 0; -+ GVariant *variant_table = NULL; -+ GVariant *variant = NULL; -+ const gchar *header = NULL; -+ guint16 version = 0; -+ GSList *retval = NULL; -+ -+ if (!g_file_test (path, G_FILE_TEST_EXISTS)) { -+ g_set_error (error, -+ IBUS_ERROR, -+ IBUS_ERROR_FAILED, -+ "Unicode dict does not exist: %s", path); -+ goto out_load_cache; -+ } -+ -+ if (!g_file_get_contents (path, &contents, &length, error)) { -+ goto out_load_cache; -+ } -+ -+ variant_table = g_variant_new_from_data (G_VARIANT_TYPE ("(sq)"), -+ contents, -+ length, -+ FALSE, -+ NULL, -+ NULL); -+ -+ if (variant_table == NULL) { -+ g_set_error (error, -+ IBUS_ERROR, -+ IBUS_ERROR_FAILED, -+ "cache table is broken."); -+ goto out_load_cache; -+ } -+ -+ g_variant_get (variant_table, "(&sq)", &header, &version); -+ -+ if (g_strcmp0 (header, IBUS_UNICODE_DATA_MAGIC) != 0) { -+ g_set_error (error, -+ IBUS_ERROR, -+ IBUS_ERROR_FAILED, -+ "cache is not IBusUnicodeData."); -+ goto out_load_cache; -+ } -+ -+ if (version > IBUS_UNICODE_DATA_VERSION) { -+ g_set_error (error, -+ IBUS_ERROR, -+ IBUS_ERROR_FAILED, -+ "cache version is different: %u != %u", -+ version, IBUS_UNICODE_DATA_VERSION); -+ goto out_load_cache; -+ } -+ -+ version = 0; -+ header = NULL; -+ g_variant_unref (variant_table); -+ -+ variant_table = g_variant_new_from_data (G_VARIANT_TYPE ("(sqv)"), -+ contents, -+ length, -+ FALSE, -+ NULL, -+ NULL); -+ -+ if (variant_table == NULL) { -+ g_set_error (error, -+ IBUS_ERROR, -+ IBUS_ERROR_FAILED, -+ "cache table is broken."); -+ goto out_load_cache; -+ } -+ -+ g_variant_get (variant_table, "(&sqv)", -+ NULL, -+ NULL, -+ &variant); -+ -+ if (variant == NULL) { -+ g_set_error (error, -+ IBUS_ERROR, -+ IBUS_ERROR_FAILED, -+ "cache dict is broken."); -+ goto out_load_cache; -+ } -+ -+ retval = ibus_unicode_data_list_deserialize (variant, source_object); -+ -+out_load_cache: -+ if (variant) -+ g_variant_unref (variant); -+ if (variant_table) -+ g_variant_unref (variant_table); -+ g_free (contents); -+ -+ return retval; -+} -+ -+GSList * -+ibus_unicode_data_load (const gchar *path, -+ GObject *source_object) -+{ -+ GError *error = NULL; -+ GSList *retval = ibus_unicode_data_load_with_error (path, -+ source_object, -+ &error); -+ -+ if (retval == NULL) { -+ g_warning ("%s", error->message); -+ g_error_free (error); -+ } -+ -+ return retval; -+} -+ -+static void -+ibus_unicode_data_load_async_thread (GTask *task, -+ gpointer source_object, -+ gpointer task_data, -+ GCancellable *cancellable) -+{ -+ GSList *retval; -+ gchar *path = (gchar *)task_data; -+ GError *error = NULL; -+ -+ g_assert (path != NULL); -+ -+ retval = ibus_unicode_data_load_with_error (path, source_object, &error); -+ g_free (path); -+ if (retval == NULL) -+ g_task_return_error (task, error); -+ else -+ g_task_return_pointer (task, retval, NULL); -+ g_object_unref (task); -+} -+ -+static void -+ibus_unicode_data_load_async_done (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ IBusUnicodeDataLoadData *data = (IBusUnicodeDataLoadData*)user_data; -+ GSList *list; -+ GError *error = NULL; -+ g_assert (data != NULL); -+ list = g_task_propagate_pointer (G_TASK (res), &error); -+ if (error) { -+ g_warning ("%s", error->message); -+ g_error_free (error); -+ data->callback (NULL, data->user_data); -+ } else { -+ data->callback (list, data->user_data); -+ } -+ g_slice_free (IBusUnicodeDataLoadData, data); -+} -+ -+void -+ibus_unicode_data_load_async (const gchar *path, -+ GObject *source_object, -+ GCancellable *cancellable, -+ IBusUnicodeDataLoadAsyncFinish -+ callback, -+ gpointer user_data) -+{ -+ GTask *task; -+ IBusUnicodeDataLoadData *data; -+ -+ g_return_if_fail (path != NULL); -+ -+ data = g_slice_new0 (IBusUnicodeDataLoadData); -+ data->callback = callback; -+ data->user_data = user_data; -+ task = g_task_new (source_object, -+ cancellable, -+ ibus_unicode_data_load_async_done, -+ data); -+ g_task_set_source_tag (task, ibus_unicode_data_load_async); -+ g_task_set_task_data (task, g_strdup (path), NULL); -+ g_task_run_in_thread (task, ibus_unicode_data_load_async_thread); -+} -+ -+static void -+ibus_unicode_block_class_init (IBusUnicodeBlockClass *class) -+{ -+ IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class); -+ GObjectClass *gobject_class = G_OBJECT_CLASS (class); -+ IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class); -+ -+ object_class->destroy = (IBusObjectDestroyFunc) ibus_unicode_data_destroy; -+ gobject_class->set_property = -+ (GObjectSetPropertyFunc) ibus_unicode_block_set_property; -+ gobject_class->get_property = -+ (GObjectGetPropertyFunc) ibus_unicode_block_get_property; -+ serializable_class->serialize = -+ (IBusSerializableSerializeFunc) ibus_unicode_block_serialize; -+ serializable_class->deserialize = -+ (IBusSerializableDeserializeFunc) ibus_unicode_block_deserialize; -+ serializable_class->copy = -+ (IBusSerializableCopyFunc) ibus_unicode_block_copy; -+ -+ g_type_class_add_private (class, sizeof (IBusUnicodeBlockPrivate)); -+ -+ /* install properties */ -+ /** -+ * IBusUnicodeBlock:start: -+ * -+ * The Uniode start code point -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_START, -+ /* Cannot use g_param_spec_unichar() for the Unicode -+ * boundary values because the function checks -+ * if the value is a valid Unicode besides MAXUINT. -+ */ -+ g_param_spec_uint ("start", -+ "start code point", -+ "The Unicode start code point", -+ 0, -+ G_MAXUINT, -+ 0, -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -+ -+ -+ /** -+ * IBusUnicodeBlock:end: -+ * -+ * The Uniode end code point -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_END, -+ /* Cannot use g_param_spec_unichar() for the Unicode -+ * boundary values because the function checks -+ * if the value is a valid Unicode besides MAXUINT. -+ */ -+ g_param_spec_uint ("end", -+ "end code point", -+ "The Unicode end code point", -+ 0, -+ G_MAXUINT, -+ 0, -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -+ -+ -+ /** -+ * IBusUnicodeBlock:name: -+ * -+ * The Uniode block name -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_NAME, -+ g_param_spec_string ("name", -+ "name", -+ "The Unicode name", -+ "", -+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); -+} -+ -+static void -+ibus_unicode_block_init (IBusUnicodeBlock *block) -+{ -+ block->priv = IBUS_UNICODE_BLOCK_GET_PRIVATE (block); -+} -+ -+static void -+ibus_unicode_block_destroy (IBusUnicodeBlock *block) -+{ -+ g_clear_pointer (&block->priv->name, g_free); -+ -+ IBUS_OBJECT_CLASS (ibus_unicode_data_parent_class)-> -+ destroy (IBUS_OBJECT (block)); -+} -+ -+static void -+ibus_unicode_block_set_property (IBusUnicodeBlock *block, -+ guint prop_id, -+ const GValue *value, -+ GParamSpec *pspec) -+{ -+ switch (prop_id) { -+ case PROP_START: -+ g_assert (block->priv->start == 0); -+ block->priv->start = g_value_get_uint (value); -+ break; -+ case PROP_END: -+ g_assert (block->priv->end == 0); -+ block->priv->end = g_value_get_uint (value); -+ break; -+ case PROP_NAME: -+ g_assert (block->priv->name == NULL); -+ block->priv->name = g_value_dup_string (value); -+ break; -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (block, prop_id, pspec); -+ } -+} -+ -+static void -+ibus_unicode_block_get_property (IBusUnicodeBlock *block, -+ guint prop_id, -+ GValue *value, -+ GParamSpec *pspec) -+{ -+ switch (prop_id) { -+ case PROP_START: -+ g_value_set_uint (value, ibus_unicode_block_get_start (block)); -+ break; -+ case PROP_END: -+ g_value_set_uint (value, ibus_unicode_block_get_end (block)); -+ break; -+ case PROP_NAME: -+ g_value_set_string (value, ibus_unicode_block_get_name (block)); -+ break; -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (block, prop_id, pspec); -+ } -+} -+ -+static gboolean -+ibus_unicode_block_serialize (IBusUnicodeBlock *block, -+ GVariantBuilder *builder) -+{ -+ gboolean retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_block_parent_class)-> -+ serialize ((IBusSerializable *)block, builder); -+ g_return_val_if_fail (retval, FALSE); -+ -+#define NOTNULL(s) ((s) != NULL ? (s) : "") -+ /* If you will add a new property, you can append it at the end and -+ * you should not change the serialized order of name, longname, -+ * description, ... because the order is also used in other applications -+ * likes ibus-qt. */ -+ g_variant_builder_add (builder, "u", block->priv->start); -+ g_variant_builder_add (builder, "u", block->priv->end); -+ g_variant_builder_add (builder, "s", NOTNULL (block->priv->name)); -+#undef NOTNULL -+ return TRUE; -+} -+ -+static gint -+ibus_unicode_block_deserialize (IBusUnicodeBlock *block, -+ GVariant *variant) -+{ -+ gint retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_block_parent_class)-> -+ deserialize ((IBusSerializable *)block, variant); -+ g_return_val_if_fail (retval, 0); -+ -+ /* If you will add a new property, you can append it at the end and -+ * you should not change the serialized order of name, longname, -+ * description, ... because the order is also used in other applications -+ * likes ibus-qt. */ -+ g_variant_get_child (variant, retval++, "u", &block->priv->start); -+ g_variant_get_child (variant, retval++, "u", &block->priv->end); -+ ibus_g_variant_get_child_string (variant, retval++, -+ &block->priv->name); -+ return retval; -+} -+ -+static gboolean -+ibus_unicode_block_copy (IBusUnicodeBlock *dest, -+ const IBusUnicodeBlock *src) -+{ -+ gboolean retval = IBUS_SERIALIZABLE_CLASS (ibus_unicode_block_parent_class)-> -+ copy ((IBusSerializable *)dest, -+ (IBusSerializable *)src); -+ g_return_val_if_fail (retval, FALSE); -+ -+ dest->priv->start = src->priv->start; -+ dest->priv->end = src->priv->end; -+ dest->priv->name = g_strdup (src->priv->name); -+ return TRUE; -+} -+ -+IBusUnicodeBlock * -+ibus_unicode_block_new (const gchar *first_property_name, ...) -+{ -+ va_list var_args; -+ IBusUnicodeBlock *block; -+ -+ g_assert (first_property_name != NULL); -+ va_start (var_args, first_property_name); -+ block = (IBusUnicodeBlock *) g_object_new_valist (IBUS_TYPE_UNICODE_BLOCK, -+ first_property_name, -+ var_args); -+ va_end (var_args); -+ /* end is required. Other properties are set in class_init by default. */ -+ g_assert (block->priv->start != block->priv->end); -+ g_assert (block->priv->name != NULL); -+ return block; -+} -+ -+gunichar -+ibus_unicode_block_get_start (IBusUnicodeBlock *block) -+{ -+ g_return_val_if_fail (IBUS_IS_UNICODE_BLOCK (block), G_MAXUINT32); -+ -+ return block->priv->start; -+} -+ -+gunichar -+ibus_unicode_block_get_end (IBusUnicodeBlock *block) -+{ -+ g_return_val_if_fail (IBUS_IS_UNICODE_BLOCK (block), G_MAXUINT32); -+ -+ return block->priv->end; -+} -+ -+const gchar * -+ibus_unicode_block_get_name (IBusUnicodeBlock *block) -+{ -+ g_return_val_if_fail (IBUS_IS_UNICODE_BLOCK (block), ""); -+ -+ return block->priv->name; -+} -+ -+static void -+variant_foreach_add_block (IBusUnicodeBlock *block, -+ GVariantBuilder *builder) -+{ -+ g_variant_builder_add ( -+ builder, "v", -+ ibus_serializable_serialize (IBUS_SERIALIZABLE (block))); -+} -+ -+static GVariant * -+ibus_unicode_block_list_serialize (GSList *list) -+{ -+ GVariantBuilder builder; -+ -+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("av")); -+ g_slist_foreach (list, (GFunc) variant_foreach_add_block, &builder); -+ return g_variant_builder_end (&builder); -+} -+ -+static GSList * -+ibus_unicode_block_list_deserialize (GVariant *variant) -+{ -+ GSList *list = NULL; -+ GVariantIter iter; -+ GVariant *unicode_variant = NULL; -+ -+ g_variant_iter_init (&iter, variant); -+ while (g_variant_iter_loop (&iter, "v", &unicode_variant)) { -+ IBusUnicodeBlock *data = -+ IBUS_UNICODE_BLOCK (ibus_serializable_deserialize ( -+ unicode_variant)); -+ list = g_slist_append (list, data); -+ g_clear_pointer (&unicode_variant, g_variant_unref); -+ } -+ -+ return list; -+} -+ -+void -+ibus_unicode_block_save (const gchar *path, -+ GSList *list) -+{ -+ GVariant *variant; -+ const gchar *header = IBUS_UNICODE_BLOCK_MAGIC; -+ const guint16 version = IBUS_UNICODE_DATA_VERSION; -+ const gchar *contents; -+ gsize length; -+ gchar *dir; -+ GStatBuf buf = { 0, }; -+ GError *error = NULL; -+ -+ g_return_if_fail (path != NULL); -+ g_return_if_fail (list != NULL); -+ if (list->data == NULL) { -+ g_warning ("Failed to save IBus Unicode block: Need a list data."); -+ return; -+ } -+ -+ variant = g_variant_new ("(sqv)", -+ header, -+ version, -+ ibus_unicode_block_list_serialize (list)); -+ -+ contents = g_variant_get_data (variant); -+ length = g_variant_get_size (variant); -+ -+ dir = g_path_get_dirname (path); -+ if (g_strcmp0 (dir, ".") != 0 && g_stat (dir, &buf) != 0) { -+ g_mkdir_with_parents (dir, 0777); -+ } -+ g_free (dir); -+ if (!g_file_set_contents (path, contents, length, &error)) { -+ g_warning ("Failed to save Unicode dict %s: %s", path, error->message); -+ g_error_free (error); -+ } -+ -+ g_variant_unref (variant); -+} -+ -+GSList * -+ibus_unicode_block_load (const gchar *path) -+{ -+ gchar *contents = NULL; -+ gsize length = 0; -+ GError *error = NULL; -+ GVariant *variant_table = NULL; -+ GVariant *variant = NULL; -+ const gchar *header = NULL; -+ guint16 version = 0; -+ GSList *retval = NULL; -+ -+ if (!g_file_test (path, G_FILE_TEST_EXISTS)) { -+ g_warning ("Unicode dict does not exist: %s", path); -+ goto out_load_cache; -+ } -+ -+ if (!g_file_get_contents (path, &contents, &length, &error)) { -+ g_warning ("Failed to get dict content %s: %s", path, error->message); -+ g_error_free (error); -+ goto out_load_cache; -+ } -+ -+ variant_table = g_variant_new_from_data (G_VARIANT_TYPE ("(sq)"), -+ contents, -+ length, -+ FALSE, -+ NULL, -+ NULL); -+ -+ if (variant_table == NULL) { -+ g_warning ("cache table is broken."); -+ goto out_load_cache; -+ } -+ -+ g_variant_get (variant_table, "(&sq)", &header, &version); -+ -+ if (g_strcmp0 (header, IBUS_UNICODE_BLOCK_MAGIC) != 0) { -+ g_warning ("cache is not IBusUnicodeBlock."); -+ goto out_load_cache; -+ } -+ -+ if (version > IBUS_UNICODE_DATA_VERSION) { -+ g_warning ("cache version is different: %u != %u", -+ version, IBUS_UNICODE_DATA_VERSION); -+ goto out_load_cache; -+ } -+ -+ version = 0; -+ header = NULL; -+ g_variant_unref (variant_table); -+ -+ variant_table = g_variant_new_from_data (G_VARIANT_TYPE ("(sqv)"), -+ contents, -+ length, -+ FALSE, -+ NULL, -+ NULL); -+ -+ if (variant_table == NULL) { -+ g_warning ("cache table is broken."); -+ goto out_load_cache; -+ } -+ -+ g_variant_get (variant_table, "(&sqv)", -+ NULL, -+ NULL, -+ &variant); -+ -+ if (variant == NULL) { -+ g_warning ("cache dict is broken."); -+ goto out_load_cache; -+ } -+ -+ retval = ibus_unicode_block_list_deserialize (variant); -+ -+out_load_cache: -+ if (variant) -+ g_variant_unref (variant); -+ if (variant_table) -+ g_variant_unref (variant_table); -+ g_free (contents); -+ -+ return retval; -+} -+ -diff --git a/src/ibusunicode.h b/src/ibusunicode.h -new file mode 100644 -index 00000000..99de9451 ---- /dev/null -+++ b/src/ibusunicode.h -@@ -0,0 +1,299 @@ -+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -+/* vim:set et sts=4: */ -+/* bus - The Input Bus -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2018 Red Hat, Inc. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -+ * USA -+ */ -+ -+#if !defined (__IBUS_H_INSIDE__) && !defined (IBUS_COMPILATION) -+#error "Only can be included directly" -+#endif -+ -+#ifndef __IBUS_UNICODE_H_ -+#define __IBUS_UNICODE_H_ -+ -+/** -+ * SECTION: ibusunicode -+ * @short_description: unicode utility. -+ * @stability: Unstable -+ * -+ * miscellaneous unicode APIs. -+ */ -+ -+#include -+#include "ibusserializable.h" -+ -+/* -+ * Type macros. -+ */ -+/* define GOBJECT macros */ -+#define IBUS_TYPE_UNICODE_DATA (ibus_unicode_data_get_type ()) -+#define IBUS_UNICODE_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ -+ IBUS_TYPE_UNICODE_DATA, IBusUnicodeData)) -+#define IBUS_UNICODE_DATA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \ -+ IBUS_TYPE_UNICODE_DATA, \ -+ IBusUnicodeDataClass)) -+#define IBUS_IS_UNICODE_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ -+ IBUS_TYPE_UNICODE_DATA)) -+#define IBUS_TYPE_UNICODE_BLOCK (ibus_unicode_block_get_type ()) -+#define IBUS_UNICODE_BLOCK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ -+ IBUS_TYPE_UNICODE_BLOCK, \ -+ IBusUnicodeBlock)) -+#define IBUS_UNICODE_BLOCK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \ -+ IBUS_TYPE_UNICODE_BLOCK, \ -+ IBusUnicodeBlockClass)) -+#define IBUS_IS_UNICODE_BLOCK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ -+ IBUS_TYPE_UNICODE_BLOCK)) -+ -+ -+G_BEGIN_DECLS -+ -+typedef struct _IBusUnicodeData IBusUnicodeData; -+typedef struct _IBusUnicodeDataPrivate IBusUnicodeDataPrivate; -+typedef struct _IBusUnicodeDataClass IBusUnicodeDataClass; -+typedef struct _IBusUnicodeBlock IBusUnicodeBlock; -+typedef struct _IBusUnicodeBlockPrivate IBusUnicodeBlockPrivate; -+typedef struct _IBusUnicodeBlockClass IBusUnicodeBlockClass; -+ -+/** -+ * IBusUnicodeDataLoadAsyncFinish: -+ * @data_list: (transfer full) (element-type IBusUnicodeData): -+ * -+ * This callback can receive the list of #IBusUnicodeData. -+ */ -+typedef void (*IBusUnicodeDataLoadAsyncFinish) (GSList *data_list, -+ gpointer user_data); -+ -+/** -+ * IBusUnicodeData: -+ * -+ * Unicode data likes code, name, alias, block-name. -+ * You can get extended values with g_object_get_properties. -+ */ -+struct _IBusUnicodeData { -+ IBusSerializable parent; -+ /* instance members */ -+ -+ /*< public >*/ -+ /*< private >*/ -+ IBusUnicodeDataPrivate *priv; -+}; -+ -+struct _IBusUnicodeDataClass { -+ IBusSerializableClass parent; -+ /* class members */ -+}; -+ -+struct _IBusUnicodeBlock { -+ IBusSerializable parent; -+ /* instance members */ -+ -+ /*< public >*/ -+ /*< private >*/ -+ IBusUnicodeBlockPrivate *priv; -+}; -+ -+struct _IBusUnicodeBlockClass { -+ IBusSerializableClass parent; -+ /* class members */ -+}; -+ -+GType ibus_unicode_data_get_type (void); -+GType ibus_unicode_block_get_type (void); -+ -+/** -+ * ibus_unicode_data_new: -+ * @first_property_name: Name of the first property. -+ * @...: the NULL-terminated arguments of the properties and values. -+ * -+ * Creates a new #IBusUnicodeData. -+ * code property is required. e.g. -+ * ibus_unicode_data_new ("code", 0x3042, NULL) -+ * -+ * Returns: A newly allocated #IBusUnicodeData. -+ */ -+IBusUnicodeData * ibus_unicode_data_new (const gchar *first_property_name, -+ ...); -+ -+/** -+ * ibus_unicode_data_get_code: -+ * @unicode: An #IBusUnicodeData -+ * -+ * Gets the code point in #IBusUnicodeData. -+ * -+ * Returns: code property in #IBusUnicodeData -+ */ -+gunichar ibus_unicode_data_get_code (IBusUnicodeData *unicode); -+ -+/** -+ * ibus_unicode_data_get_name: -+ * @unicode: An #IBusUnicodeData -+ * -+ * Gets the name in #IBusUnicodeData. It should not be freed. -+ * -+ * Returns: name property in #IBusUnicodeData -+ */ -+const gchar * ibus_unicode_data_get_name (IBusUnicodeData *unicode); -+ -+/** -+ * ibus_unicode_data_get_alias: -+ * @unicode: An #IBusUnicodeData -+ * -+ * Gets the alias in #IBusUnicodeData. It should not be freed. -+ * -+ * Returns: alias property in #IBusUnicodeData -+ */ -+const gchar * ibus_unicode_data_get_alias (IBusUnicodeData *unicode); -+ -+/** -+ * ibus_unicode_data_get_block_name: -+ * @unicode: An #IBusUnicodeData -+ * -+ * Gets the block name in #IBusUnicodeData. It should not be freed. -+ * -+ * Returns: block-name property in #IBusUnicodeData -+ */ -+const gchar * ibus_unicode_data_get_block_name -+ (IBusUnicodeData *unicode); -+ -+/** -+ * ibus_unicode_data_set_block_name: -+ * @unicode: An #IBusUnicodeData -+ * @block_name: A block name -+ * -+ * Sets the block name in #IBusUnicodeData. -+ */ -+void ibus_unicode_data_set_block_name -+ (IBusUnicodeData *unicode, -+ const gchar *block_name); -+ -+/** -+ * ibus_unicode_data_save: -+ * @path: A path of the saved Unicode data. -+ * @list: (element-type IBusUnicodeData) (transfer none): A list of unicode -+ * data. -+ * -+ * Save the list of #IBusUnicodeData to the cache file. -+ */ -+void ibus_unicode_data_save (const gchar *path, -+ GSList *list); -+ -+/** -+ * ibus_unicode_data_load: -+ * @path: A path of the saved dictionary file. -+ * @object: (nullable): If the #GObject has "unicode-deserialize-progress" -+ * signal, this function will emit (the number of desrialized -+ * #IBusUnicodeData, * the total number of #IBusUnicodeData) of uint values -+ * with that signal by 100 times. Otherwise %NULL. -+ * -+ * Returns: (element-type IBusUnicodeData) (transfer container): -+ * An #IBusUnicodeData list loaded from the saved cache file. -+ */ -+GSList * ibus_unicode_data_load (const gchar *path, -+ GObject *object); -+ -+/** -+ * ibus_unicode_data_load_async: -+ * @path: A path of the saved dictionary file. -+ * @object: (nullable): If the #GObject has "unicode-deserialize-progress" -+ * signal, this function will emit (the number of desrialized -+ * #IBusUnicodeData, * the total number of #IBusUnicodeData) of uint values -+ * with that signal by 100 times. Otherwise %NULL. -+ * @cancellable: cancellable. -+ * @callback: (scope notified): IBusUnicodeDataLoadAsyncFinish. -+ * @user_data: User data. -+ * -+ * IBusUnicodeDataLoadAsyncFinish can receive the list of #IBusUnicodeData. -+ */ -+void ibus_unicode_data_load_async -+ (const gchar *path, -+ GObject *object, -+ GCancellable *cancellable, -+ IBusUnicodeDataLoadAsyncFinish -+ callback, -+ gpointer user_data); -+ -+/** -+ * ibus_unicode_block_new: -+ * @first_property_name: Name of the first property. -+ * @...: the NULL-terminated arguments of the properties and values. -+ * -+ * Creates a new #IBusUnicodeBlock. -+ * block property is required. e.g. -+ * ibus_unicode_block_new ("start", 0x0000, "end", "0x007f", "name", "basic", -+ * NULL) -+ * -+ * Returns: A newly allocated #IBusUnicodeBlock. -+ */ -+IBusUnicodeBlock *ibus_unicode_block_new (const gchar *first_property_name, -+ ...); -+ -+/** -+ * ibus_unicode_block_get_start: -+ * @block: An #IBusUnicodeData -+ * -+ * Gets the start code point in #IBusUnicodeBlock. -+ * -+ * Returns: start property in #IBusUnicodeBlock -+ */ -+gunichar ibus_unicode_block_get_start -+ (IBusUnicodeBlock *block); -+ -+/** -+ * ibus_unicode_block_get_end: -+ * @block: An #IBusUnicodeData -+ * -+ * Gets the end code point in #IBusUnicodeBlock. -+ * -+ * Returns: end property in #IBusUnicodeBlock -+ */ -+gunichar ibus_unicode_block_get_end -+ (IBusUnicodeBlock *block); -+ -+/** -+ * ibus_unicode_block_get_name: -+ * @block: An #IBusUnicodeBlock -+ * -+ * Gets the name in #IBusUnicodeBlock. It should not be freed. -+ * -+ * Returns: name property in #IBusUnicodeBlock -+ */ -+const gchar * ibus_unicode_block_get_name (IBusUnicodeBlock *block); -+ -+/** -+ * ibus_unicode_block_save: -+ * @path: A path of the saved Unicode block. -+ * @list: (element-type IBusUnicodeBlock) (transfer none): A list of unicode -+ * block. -+ * -+ * Save the list of #IBusUnicodeBlock to the cache file. -+ */ -+void ibus_unicode_block_save (const gchar *path, -+ GSList *list); -+ -+/** -+ * ibus_unicode_block_load: -+ * @path: A path of the saved dictionary file. -+ * -+ * Returns: (element-type IBusUnicodeBlock) (transfer container): -+ * An #IBusUnicodeBlock list loaded from the saved cache file. -+ */ -+GSList * ibus_unicode_block_load (const gchar *path); -+ -+G_END_DECLS -+#endif -diff --git a/src/ibusunicodegen.h b/src/ibusunicodegen.h -new file mode 100644 -index 00000000..c613b81b ---- /dev/null -+++ b/src/ibusunicodegen.h -@@ -0,0 +1,1151 @@ -+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -+/* vim:set et sts=4: */ -+/* ibus - The Input Bus -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2018 Red Hat, Inc. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -+ * USA -+ */ -+ -+ -+/* This file is generated by unicode-parser.c. */ -+include -+ -+#ifndef __IBUS_UNICODE_GEN_H_ -+#define __IBUS_UNICODE_GEN_H_ -+const static char *unicode_blocks[] = { -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Basic Latin"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Latin-1 Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Latin Extended-A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Latin Extended-B"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("IPA Extensions"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Spacing Modifier Letters"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Combining Diacritical Marks"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Greek and Coptic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Cyrillic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Cyrillic Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Armenian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Hebrew"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Arabic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Syriac"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Arabic Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Thaana"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("NKo"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Samaritan"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Mandaic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Syriac Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Arabic Extended-A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Devanagari"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Bengali"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Gurmukhi"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Gujarati"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Oriya"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tamil"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Telugu"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Kannada"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Malayalam"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Sinhala"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Thai"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Lao"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tibetan"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Myanmar"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Georgian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Hangul Jamo"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ethiopic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ethiopic Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Cherokee"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Unified Canadian Aboriginal Syllabics"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ogham"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Runic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tagalog"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Hanunoo"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Buhid"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tagbanwa"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Khmer"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Mongolian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Unified Canadian Aboriginal Syllabics Extended"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Limbu"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tai Le"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("New Tai Lue"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Khmer Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Buginese"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tai Tham"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Combining Diacritical Marks Extended"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Balinese"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Sundanese"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Batak"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Lepcha"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ol Chiki"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Cyrillic Extended-C"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Sundanese Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Vedic Extensions"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Phonetic Extensions"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Phonetic Extensions Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Combining Diacritical Marks Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Latin Extended Additional"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Greek Extended"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("General Punctuation"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Superscripts and Subscripts"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Currency Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Combining Diacritical Marks for Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Letterlike Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Number Forms"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Arrows"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Mathematical Operators"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Miscellaneous Technical"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Control Pictures"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Optical Character Recognition"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Enclosed Alphanumerics"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Box Drawing"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Block Elements"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Geometric Shapes"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Miscellaneous Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Dingbats"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Miscellaneous Mathematical Symbols-A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Supplemental Arrows-A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Braille Patterns"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Supplemental Arrows-B"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Miscellaneous Mathematical Symbols-B"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Supplemental Mathematical Operators"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Miscellaneous Symbols and Arrows"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Glagolitic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Latin Extended-C"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Coptic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Georgian Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tifinagh"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ethiopic Extended"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Cyrillic Extended-A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Supplemental Punctuation"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Radicals Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Kangxi Radicals"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ideographic Description Characters"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Symbols and Punctuation"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Hiragana"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Katakana"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Bopomofo"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Hangul Compatibility Jamo"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Kanbun"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Bopomofo Extended"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Strokes"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Katakana Phonetic Extensions"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Enclosed CJK Letters and Months"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Compatibility"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Unified Ideographs Extension A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Yijing Hexagram Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Unified Ideographs"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Yi Syllables"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Yi Radicals"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Lisu"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Vai"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Cyrillic Extended-B"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Bamum"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Modifier Tone Letters"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Latin Extended-D"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Syloti Nagri"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Common Indic Number Forms"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Phags-pa"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Saurashtra"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Devanagari Extended"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Kayah Li"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Rejang"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Hangul Jamo Extended-A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Javanese"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Myanmar Extended-B"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Cham"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Myanmar Extended-A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tai Viet"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Meetei Mayek Extensions"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ethiopic Extended-A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Latin Extended-E"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Cherokee Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Meetei Mayek"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Hangul Syllables"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Hangul Jamo Extended-B"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("High Surrogates"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("High Private Use Surrogates"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Low Surrogates"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Private Use Area"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Compatibility Ideographs"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Alphabetic Presentation Forms"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Arabic Presentation Forms-A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Variation Selectors"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Vertical Forms"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Combining Half Marks"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Compatibility Forms"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Small Form Variants"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Arabic Presentation Forms-B"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Halfwidth and Fullwidth Forms"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Specials"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Linear B Syllabary"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Linear B Ideograms"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Aegean Numbers"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ancient Greek Numbers"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ancient Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Phaistos Disc"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Lycian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Carian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Coptic Epact Numbers"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Old Italic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Gothic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Old Permic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ugaritic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Old Persian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Deseret"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Shavian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Osmanya"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Osage"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Elbasan"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Caucasian Albanian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Linear A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Cypriot Syllabary"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Imperial Aramaic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Palmyrene"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Nabataean"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Hatran"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Phoenician"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Lydian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Meroitic Hieroglyphs"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Meroitic Cursive"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Kharoshthi"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Old South Arabian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Old North Arabian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Manichaean"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Avestan"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Inscriptional Parthian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Inscriptional Pahlavi"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Psalter Pahlavi"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Old Turkic"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Old Hungarian"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Rumi Numeral Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Brahmi"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Kaithi"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Sora Sompeng"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Chakma"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Mahajani"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Sharada"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Sinhala Archaic Numbers"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Khojki"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Multani"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Khudawadi"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Grantha"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Newa"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tirhuta"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Siddham"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Modi"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Mongolian Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Takri"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ahom"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Warang Citi"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Zanabazar Square"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Soyombo"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Pau Cin Hau"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Bhaiksuki"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Marchen"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Masaram Gondi"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Cuneiform"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Cuneiform Numbers and Punctuation"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Early Dynastic Cuneiform"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Egyptian Hieroglyphs"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Anatolian Hieroglyphs"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Bamum Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Mro"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Bassa Vah"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Pahawh Hmong"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Miao"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ideographic Symbols and Punctuation"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tangut"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tangut Components"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Kana Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Kana Extended-A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Nushu"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Duployan"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Shorthand Format Controls"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Byzantine Musical Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Musical Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ancient Greek Musical Notation"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tai Xuan Jing Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Counting Rod Numerals"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Mathematical Alphanumeric Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Sutton SignWriting"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Glagolitic Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Mende Kikakui"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Adlam"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Arabic Mathematical Alphabetic Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Mahjong Tiles"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Domino Tiles"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Playing Cards"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Enclosed Alphanumeric Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Enclosed Ideographic Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Miscellaneous Symbols and Pictographs"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Emoticons"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Ornamental Dingbats"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Transport and Map Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Alchemical Symbols"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Geometric Shapes Extended"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Supplemental Arrows-C"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Supplemental Symbols and Pictographs"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Unified Ideographs Extension B"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Unified Ideographs Extension C"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Unified Ideographs Extension D"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Unified Ideographs Extension E"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Unified Ideographs Extension F"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("CJK Compatibility Ideographs Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Tags"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Variation Selectors Supplement"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Supplementary Private Use Area-A"), -+ /* TRANSLATORS: You might refer the translations from gucharmap with -+ the following command: -+ msgmerge -C gucharmap.po ibus.po ibus.pot */ -+ N_("Supplementary Private Use Area-B"), -+}; -+#endif -diff --git a/src/unicode-parser.c b/src/unicode-parser.c -new file mode 100644 -index 00000000..e98c6d5f ---- /dev/null -+++ b/src/unicode-parser.c -@@ -0,0 +1,502 @@ -+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -+/* vim:set et sts=4: */ -+/* ibus - The Input Bus -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2018 Red Hat, Inc. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -+ * USA -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include -+#endif -+ -+#include -+#include -+#include -+ -+#ifdef HAVE_LOCALE_H -+#include -+#endif -+ -+#include "ibusunicode.h" -+ -+#define NAMES_LIST_SUBJECT "The Unicode Standard" -+#define BLOCKS_SUBJECT "Blocks-" -+ -+/* This file has 21 lines about the license at the top of the file. */ -+#define LICENSE_LINES 21 -+ -+typedef enum -+{ -+ UCD_NAMES_LIST, -+ UCD_BLOCKS -+} UCDType; -+ -+typedef struct _UnicodeData UnicodeData; -+typedef struct _UnicodeDataIndex UnicodeDataIndex; -+ -+struct _UnicodeData{ -+ gunichar code; -+ gchar *name; -+ gchar *alias; -+ gunichar start; -+ gunichar end; -+ GSList *list; -+}; -+ -+struct _UnicodeDataIndex { -+ gchar *index; -+ UnicodeData *data_list; -+}; -+ -+static gchar *unicode_version; -+ -+static void -+unicode_data_new_object (UnicodeData *data) -+{ -+ g_return_if_fail (data != NULL); -+ if (!data->name) { -+ g_warning ("No name in U+%04X", data->code); -+ } -+ IBusUnicodeData *unicode = -+ ibus_unicode_data_new ("code", -+ data->code, -+ "name", -+ data->name ? g_strdup (data->name) -+ : g_strdup (""), -+ "alias", -+ data->alias ? g_strdup (data->alias) -+ : g_strdup (""), -+ NULL); -+ data->list = g_slist_append (data->list, unicode); -+} -+ -+static void -+unicode_block_new_object (UnicodeData *data) -+{ -+ g_return_if_fail (data != NULL); -+ if (!data->name) { -+ g_warning ("No name in U+%04X", data->start); -+ } -+ IBusUnicodeBlock *block = -+ ibus_unicode_block_new ("start", -+ data->start, -+ "end", -+ data->end, -+ "name", -+ data->name ? g_strdup (data->name) -+ : g_strdup (""), -+ NULL); -+ data->list = g_slist_append (data->list, block); -+} -+ -+static void -+unicode_data_reset (UnicodeData *data) -+{ -+ g_return_if_fail (data != NULL); -+ data->code = 0; -+ g_clear_pointer (&data->name, g_free); -+ g_clear_pointer (&data->alias, g_free); -+ data->start = 0; -+ data->end = 0; -+} -+ -+static gboolean -+ucd_names_list_parse_comment (const gchar *line) -+{ -+ static gboolean has_version = FALSE; -+ -+ if (has_version) -+ return TRUE; -+ if (strlen (line) > 4 && strncmp (line, "@@@", 3) == 0) { -+ gchar **elements = g_strsplit (line, "\t", -1); -+ if (strncmp (elements[1], NAMES_LIST_SUBJECT, -+ strlen (NAMES_LIST_SUBJECT)) == 0) { -+ unicode_version = -+ g_strdup (elements[1] + strlen (NAMES_LIST_SUBJECT) + 1); -+ has_version = TRUE; -+ } -+ g_strfreev (elements); -+ } -+ return TRUE; -+} -+ -+static gboolean -+ucd_names_list_parse_alias (const gchar *line, -+ UnicodeData *data) -+{ -+ g_return_val_if_fail (line != NULL, FALSE); -+ g_return_val_if_fail (data != NULL, FALSE); -+ -+ if (*line == '\0') -+ return FALSE; -+ data->alias = g_strdup (line); -+ return TRUE; -+} -+ -+static gboolean -+ucd_names_list_parse_indent_line (const gchar *line, -+ UnicodeData *data) -+{ -+ g_return_val_if_fail (line != NULL, FALSE); -+ -+ switch (*line) { -+ case '\0': -+ return FALSE; -+ case '=': -+ line++; -+ while (*line == ' ') line++; -+ return ucd_names_list_parse_alias (line, data); -+ default:; -+ } -+ return TRUE; -+} -+ -+static gboolean -+ucd_names_list_parse_line (const gchar *line, -+ UnicodeData *data) -+{ -+ g_return_val_if_fail (line != NULL, FALSE); -+ -+ switch (*line) { -+ case '\0': -+ return TRUE; -+ case ';': -+ return TRUE; -+ case '@': -+ return ucd_names_list_parse_comment (line); -+ case '\t': -+ return ucd_names_list_parse_indent_line (line + 1, data); -+ default:; -+ } -+ if (g_ascii_isxdigit (*line)) { -+ gchar **elements = g_strsplit (line, "\t", -1); -+ gunichar code; -+ gchar *name; -+ -+ if (g_strv_length (elements) < 2) { -+ g_strfreev (elements); -+ return FALSE; -+ } -+ code = g_ascii_strtoull (elements[0], NULL, 16); -+ name = g_strdup (elements[1]); -+ if (data->name) { -+ unicode_data_new_object (data); -+ unicode_data_reset (data); -+ } -+ data->code = code; -+ data->name = name; -+ } -+ return TRUE; -+} -+ -+static gboolean -+ucd_blocks_parse_comment (const gchar *line) -+{ -+ static gboolean has_version = FALSE; -+ -+ g_return_val_if_fail (line != NULL, FALSE); -+ -+ if (has_version) -+ return TRUE; -+ while (*line == ' ') line++; -+ if (strlen (line) > strlen (BLOCKS_SUBJECT) && -+ strncmp (line, BLOCKS_SUBJECT, strlen (BLOCKS_SUBJECT)) == 0) { -+ unicode_version = g_strdup (line + strlen (BLOCKS_SUBJECT) + 1); -+ has_version = TRUE; -+ } -+ return TRUE; -+} -+ -+static gboolean -+ucd_blocks_parse_line (const gchar *line, -+ UnicodeData *data) -+{ -+ g_return_val_if_fail (line != NULL, FALSE); -+ -+ switch (*line) { -+ case '\0': -+ return TRUE; -+ case '#': -+ return ucd_blocks_parse_comment (line + 1); -+ default:; -+ } -+ if (g_ascii_isxdigit (*line)) { -+ gchar *endptr = NULL; -+ gunichar start = g_ascii_strtoull (line, &endptr, 16); -+ gunichar end; -+ gchar *name = NULL; -+ -+ if (endptr == NULL || *endptr == '\0') -+ return FALSE; -+ while (*endptr == '.') endptr++; -+ line = endptr; -+ endptr = NULL; -+ end = g_ascii_strtoull (line, &endptr, 16); -+ if (endptr == NULL || *endptr == '\0') -+ return FALSE; -+ while (*endptr == ';') endptr++; -+ while (*endptr == ' ') endptr++; -+ if (*endptr == '\0') -+ return FALSE; -+ name = g_strdup (endptr); -+ if (data->name) { -+ unicode_block_new_object (data); -+ unicode_data_reset (data); -+ } -+ data->start = start; -+ data->end = end; -+ data->name = name; -+ } -+ return TRUE; -+} -+ -+static gboolean -+ucd_parse_file (const gchar *filename, -+ GSList **list, -+ UCDType type) -+{ -+ UnicodeData data = { 0, }; -+ gchar *content = NULL; -+ gsize length = 0; -+ GError *error = NULL; -+ gchar *head, *end, *line; -+ int n = 1; -+ -+ g_return_val_if_fail (filename != NULL, FALSE); -+ g_return_val_if_fail (list != NULL, FALSE); -+ -+ if (!g_file_get_contents (filename, &content, &length, &error)) { -+ g_warning ("Failed to load %s: %s", filename, error->message); -+ goto failed_to_parse_ucd_names_list; -+ } -+ head = end = content; -+ while (*end == '\n' && end - content < length) { -+ end++; -+ n++; -+ } -+ head = end; -+ while (end - content < length) { -+ while (*end != '\n' && end - content < length) -+ end++; -+ if (end - content >= length) -+ break; -+ line = g_strndup (head, end - head); -+ switch (type) { -+ case UCD_NAMES_LIST: -+ if (!ucd_names_list_parse_line (line, &data)) { -+ g_warning ("parse error #%d in %s version %s: %s", -+ n, filename, -+ unicode_version ? unicode_version : "(null)", -+ line); -+ } -+ break; -+ case UCD_BLOCKS: -+ if (!ucd_blocks_parse_line (line, &data)) { -+ g_warning ("parse error #%d in %s version %s: %s", -+ n, filename, -+ unicode_version ? unicode_version : "(null)", -+ line); -+ } -+ break; -+ default: -+ g_abort (); -+ } -+ while (*end == '\n' && end - content < length) { -+ end++; -+ n++; -+ } -+ g_free (line); -+ head = end; -+ } -+ if (data.name != NULL) { -+ switch (type) { -+ case UCD_NAMES_LIST: -+ unicode_data_new_object (&data); -+ break; -+ case UCD_BLOCKS: -+ unicode_block_new_object (&data); -+ break; -+ default:; -+ } -+ unicode_data_reset (&data); -+ } -+ g_free (content); -+ *list = data.list; -+ return TRUE; -+ -+failed_to_parse_ucd_names_list: -+ if (error) -+ g_error_free (error); -+ g_clear_pointer (&content, g_free); -+ *list = data.list; -+ return FALSE; -+} -+ -+static void -+block_list_dump (IBusUnicodeBlock *block, -+ GString *buff) -+{ -+ g_return_if_fail (buff != NULL); -+ -+ g_string_append (buff, " /* TRANSLATORS: You might refer the " \ -+ "translations from gucharmap with\n" \ -+ " the following command:\n" \ -+ " msgmerge -C gucharmap.po ibus.po " \ -+ "ibus.pot */\n"); -+ gchar *line = g_strdup_printf (" N_(\"%s\"),\n", -+ ibus_unicode_block_get_name (block)); -+ g_string_append (buff, line); -+} -+ -+static void -+ucd_block_translatable_save (const gchar *filename, -+ GSList *blocks_list) -+{ -+ gchar *content = NULL; -+ gsize length = 0; -+ GError *error = NULL; -+ gchar *p; -+ GString *buff = NULL; -+ int i; -+ GSList *list = blocks_list; -+ -+ g_return_if_fail (filename != NULL); -+ g_return_if_fail (list != NULL); -+ -+ if (!g_file_get_contents (__FILE__, &content, &length, &error)) { -+ g_warning ("Failed to load %s: %s", __FILE__, error->message); -+ g_clear_pointer (&error, g_error_free); -+ return; -+ } -+ -+ buff = g_string_new (NULL); -+ p = content; -+ for (i = 0; i < LICENSE_LINES; i++, p++) { -+ if ((p = strchr (p, '\n')) == NULL) -+ break; -+ } -+ if (p != NULL) { -+ g_string_append (buff, g_strndup (content, p - content)); -+ g_string_append_c (buff, '\n'); -+ } -+ g_clear_pointer (&content, g_free); -+ -+ g_string_append (buff, g_strdup ("\n")); -+ g_string_append (buff, g_strdup_printf ("/* This file is generated by %s. */", __FILE__)); -+ g_string_append (buff, g_strdup ("\n")); -+ g_string_append (buff, g_strdup ("include \n")); -+ g_string_append (buff, g_strdup ("\n")); -+ g_string_append (buff, g_strdup ("#ifndef __IBUS_UNICODE_GEN_H_\n")); -+ g_string_append (buff, g_strdup ("#define __IBUS_UNICODE_GEN_H_\n")); -+ g_string_append (buff, g_strdup ("const static char *unicode_blocks[] = {\n")); -+ g_slist_foreach (list, (GFunc)block_list_dump, buff); -+ g_string_append (buff, g_strdup ("};\n")); -+ g_string_append (buff, g_strdup ("#endif\n")); -+ -+ if (!g_file_set_contents (filename, buff->str, -1, &error)) { -+ g_warning ("Failed to save emoji category file %s: %s", filename, error->message); -+ g_error_free (error); -+ } -+ -+ g_string_free (buff, TRUE); -+} -+ -+int -+main (int argc, char *argv[]) -+{ -+ gchar *prgname; -+ gchar *input_names_list = NULL; -+ gchar *input_blocks = NULL; -+ gchar *output_names_list = NULL; -+ gchar *output_blocks = NULL; -+ gchar *output_blocks_trans = NULL; -+ GOptionEntry entries[] = { -+ { "input-names-list", 'n', 0, G_OPTION_ARG_STRING, &input_names_list, -+ "Parse NamesList.txt FILE in unicode.org ", -+ "FILE" -+ }, -+ { "input-blocks", 'b', 0, G_OPTION_ARG_STRING, &input_blocks, -+ "Parse Blocks.txt FILE in unicode.org ", -+ "FILE" -+ }, -+ { "output-names-list", 'o', 0, G_OPTION_ARG_STRING, &output_names_list, -+ "Save the Unicode data as FILE", -+ "FILE" -+ }, -+ { "output-blocks", 'B', 0, G_OPTION_ARG_STRING, &output_blocks, -+ "Save the Unicode block list as FILE", -+ "FILE" -+ }, -+ { "output-blocks-trans", 'C', 0, G_OPTION_ARG_STRING, -+ &output_blocks_trans, -+ "Save the translatable Unicode blocks as FILE", -+ "FILE" -+ }, -+ { NULL } -+ }; -+ GOptionContext *context; -+ GError *error = NULL; -+ GSList *names_list = NULL; -+ GSList *blocks_list = NULL; -+ -+#ifdef HAVE_LOCALE_H -+ /* To output emoji warnings. */ -+ setlocale (LC_ALL, ""); -+#endif -+ -+ prgname = g_path_get_basename (argv[0]); -+ g_set_prgname (prgname); -+ g_free (prgname); -+ -+ context = g_option_context_new (NULL); -+ g_option_context_add_main_entries (context, entries, NULL); -+ -+ if (argc < 3) { -+ g_print ("%s", g_option_context_get_help (context, TRUE, NULL)); -+ g_option_context_free (context); -+ return -1; -+ } -+ -+ if (!g_option_context_parse (context, &argc, &argv, &error)) { -+ g_warning ("Failed options: %s", error->message); -+ g_error_free (error); -+ return -1; -+ } -+ g_option_context_free (context); -+ -+ if (input_names_list) { -+ ucd_parse_file (input_names_list, &names_list, UCD_NAMES_LIST); -+ g_free (input_names_list); -+ } -+ if (output_names_list && names_list) -+ ibus_unicode_data_save (output_names_list, names_list); -+ g_free (output_names_list); -+ -+ if (input_blocks) { -+ ucd_parse_file (input_blocks, &blocks_list, UCD_BLOCKS); -+ g_free (input_blocks); -+ } -+ if (output_blocks && blocks_list) -+ ibus_unicode_block_save (output_blocks, blocks_list); -+ if (output_blocks_trans && blocks_list) -+ ucd_block_translatable_save (output_blocks_trans, blocks_list); -+ g_free (output_blocks); -+ -+ g_free (unicode_version); -+ return 0; -+} -diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala -index f3e9f15c..555ea68f 100644 ---- a/ui/gtk3/emojier.vala -+++ b/ui/gtk3/emojier.vala -@@ -2,7 +2,7 @@ - * - * ibus - The Input Bus - * -- * Copyright (c) 2017 Takao Fujiwara -+ * Copyright (c) 2017-2018 Takao Fujiwara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -20,7 +20,7 @@ - * USA - */ - --class IBusEmojier : Gtk.ApplicationWindow { -+public class IBusEmojier : Gtk.ApplicationWindow { - private class EEntry : Gtk.SearchEntry { - public EEntry() { - GLib.Object( -@@ -99,15 +99,70 @@ class IBusEmojier : Gtk.ApplicationWindow { - } - } - private class EWhiteLabel : Gtk.Label { -+ private int m_minimum_width = 0; -+ private int m_natural_width = 0; -+ private int m_minimum_height = 0; -+ private int m_natural_height = 0; - public EWhiteLabel(string text) { - GLib.Object( - name : "IBusEmojierWhiteLabel" - ); -- if (text != "") -- set_label(text); -+ set_label(text); -+ } -+ public override void get_preferred_width(out int minimum_width, -+ out int natural_width) { -+ if (m_minimum_height == 0 && m_natural_height == 0) { -+ base.get_preferred_height(out m_minimum_height, -+ out m_natural_height); -+ } -+ var text = get_label(); -+ var ch = text.get_char(); -+ if (text.length == 1 && ch == '\t') { -+ m_minimum_width = minimum_width = m_minimum_height; -+ m_natural_width = natural_width = m_natural_height; -+ return; -+ } -+ base.get_preferred_width(out minimum_width, out natural_width); -+ if (text.length == 1 && (ch == '\n' || ch == '\r')) { -+ minimum_width /= 2; -+ natural_width /= 2; -+ m_minimum_width = minimum_width; -+ m_natural_width = natural_width; -+ return; -+ } -+ if (minimum_width < m_minimum_height) -+ minimum_width = m_minimum_height; -+ if (natural_width < m_natural_height) -+ natural_width = m_natural_height; -+ m_minimum_width = minimum_width; -+ m_natural_width = natural_width; -+ } -+ public override void get_preferred_height(out int minimum_height, -+ out int natural_height) { -+ if (m_minimum_width == 0 && m_natural_width == 0) { -+ base.get_preferred_width(out m_minimum_width, -+ out m_natural_width); -+ } -+ var text = get_label(); -+ var ch = text.get_char(); -+ if (text.length == 1 && ch == '\v') { -+ m_minimum_height = minimum_height = m_minimum_width; -+ m_natural_height = natural_height = m_natural_width; -+ return; -+ } -+ base.get_preferred_height(out minimum_height, out natural_height); -+ if (text.length == 1 && (ch == '\n' || ch == '\r')) { -+ minimum_height /= 2; -+ natural_height /= 2; -+ m_minimum_height = minimum_height; -+ m_natural_height = natural_height; -+ return; -+ } -+ m_minimum_height = minimum_height; -+ m_natural_height = natural_height; - } - } -- private class ESelectedLabel : Gtk.Label { -+ private class ESelectedLabel : EWhiteLabel { - public ESelectedLabel(string text) { - GLib.Object( - name : "IBusEmojierSelectedLabel" -@@ -116,7 +171,7 @@ class IBusEmojier : Gtk.ApplicationWindow { - set_label(text); - } - } -- private class EGoldLabel : Gtk.Label { -+ private class EGoldLabel : EWhiteLabel { - public EGoldLabel(string text) { - GLib.Object( - name : "IBusEmojierGoldLabel" -@@ -167,6 +222,7 @@ class IBusEmojier : Gtk.ApplicationWindow { - } - private class ETitleLabelBox : Gtk.HeaderBar { - private Gtk.Label m_lang_label; -+ private Gtk.Label m_title_label; - - public ETitleLabelBox(string title) { - GLib.Object( -@@ -177,9 +233,9 @@ class IBusEmojier : Gtk.ApplicationWindow { - ); - var vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 0); - set_custom_title(vbox); -- var label = new Gtk.Label(title); -- label.get_style_context().add_class(Gtk.STYLE_CLASS_TITLE); -- vbox.pack_start(label, true, false, 0); -+ m_title_label = new Gtk.Label(title); -+ m_title_label.get_style_context().add_class(Gtk.STYLE_CLASS_TITLE); -+ vbox.pack_start(m_title_label, true, false, 0); - m_lang_label = new Gtk.Label(null); - m_lang_label.get_style_context().add_class( - Gtk.STYLE_CLASS_SUBTITLE); -@@ -194,10 +250,19 @@ class IBusEmojier : Gtk.ApplicationWindow { - menu_button.set_tooltip_text(_("Menu")); - pack_end(menu_button); - } -+ public new void set_title(string title) { -+ m_title_label.set_text(title); -+ } - public void set_lang_label(string str) { - m_lang_label.set_text(str); - } - } -+ private class LoadProgressObject : GLib.Object { -+ public LoadProgressObject() { -+ } -+ public signal void deserialize_unicode(uint done, uint total); -+ } -+ - - private enum TravelDirection { - NONE, -@@ -207,6 +272,7 @@ class IBusEmojier : Gtk.ApplicationWindow { - private const uint EMOJI_GRID_PAGE = 10; - private const string EMOJI_CATEGORY_FAVORITES = N_("Favorites"); - private const string EMOJI_CATEGORY_OTHERS = N_("Others"); -+ private const string EMOJI_CATEGORY_UNICODE = N_("Open Unicode choice"); - private const unichar[] EMOJI_VARIANT_LIST = { - 0x1f3fb, 0x1f3fc, 0x1f3fd, 0x1f3fe, 0x1f3ff, 0x200d }; - -@@ -223,6 +289,8 @@ class IBusEmojier : Gtk.ApplicationWindow { - private static uint m_partial_match_length; - private static uint m_partial_match_condition; - private static bool m_show_emoji_variant = false; -+ private static int m_default_window_width; -+ private static int m_default_window_height; - private static GLib.HashTable>? - m_annotation_to_emojis_dict; - private static GLib.HashTable? -@@ -231,6 +299,14 @@ class IBusEmojier : Gtk.ApplicationWindow { - m_category_to_emojis_dict; - private static GLib.HashTable>? - m_emoji_to_emoji_variants_dict; -+ private static GLib.HashTable? -+ m_unicode_to_data_dict; -+ private static GLib.HashTable>? -+ m_name_to_unicodes_dict; -+ private static GLib.SList m_unicode_block_list; -+ private static bool m_show_unicode = false; -+ private static LoadProgressObject m_unicode_progress_object; -+ private static bool m_loaded_unicode = false; - - private ThemedRGBA m_rgba; - private Gtk.Box m_vbox; -@@ -246,7 +322,7 @@ class IBusEmojier : Gtk.ApplicationWindow { - private string? m_result; - private string? m_unicode_point = null; - private bool m_candidate_panel_is_visible; -- private int m_category_active_index; -+ private int m_category_active_index = -1; - private IBus.LookupTable m_lookup_table; - private Gtk.Label[] m_candidates; - private bool m_enter_notify_enable = true; -@@ -254,6 +330,9 @@ class IBusEmojier : Gtk.ApplicationWindow { - private uint m_entry_notify_disable_id; - protected static double m_mouse_x; - protected static double m_mouse_y; -+ private Gtk.ProgressBar m_unicode_progress_bar; -+ private Gtk.Label m_unicode_percent_label; -+ private double m_unicode_percent; - - public signal void candidate_clicked(uint index, uint button, uint state); - -@@ -402,6 +481,8 @@ class IBusEmojier : Gtk.ApplicationWindow { - if (m_annotation_to_emojis_dict == null) { - reload_emoji_dict(); - } -+ -+ get_load_progress_object(); - } - - -@@ -433,6 +514,13 @@ class IBusEmojier : Gtk.ApplicationWindow { - m_emoji_to_emoji_variants_dict = - new GLib.HashTable>(GLib.str_hash, - GLib.str_equal); -+ m_unicode_to_data_dict = -+ new GLib.HashTable( -+ GLib.direct_hash, -+ GLib.direct_equal); -+ m_name_to_unicodes_dict = -+ new GLib.HashTable>(GLib.str_hash, -+ GLib.str_equal); - } - - -@@ -482,6 +570,10 @@ class IBusEmojier : Gtk.ApplicationWindow { - private static string utf8_code_point(string str) { - var buff = new GLib.StringBuilder(); - int length = str.char_count(); -+ if (length == 0) { -+ buff.append("U+%04X".printf(0)); -+ return buff.str; -+ } - for (int i = 0; i < length; i++) { - unichar ch = str.get_char(0); - if (i == 0) -@@ -644,6 +736,72 @@ class IBusEmojier : Gtk.ApplicationWindow { - } - - -+ private static void make_unicode_block_dict() { -+ m_unicode_block_list = IBus.UnicodeBlock.load( -+ Config.PKGDATADIR + "/dicts/unicode-blocks.dict"); -+ foreach (unowned IBus.UnicodeBlock block in m_unicode_block_list) { -+ unowned string name = block.get_name(); -+ if (m_emoji_max_seq_len < name.length) -+ m_emoji_max_seq_len = name.length; -+ } -+ } -+ -+ -+ private static void make_unicode_name_dict(Object source_object) { -+ IBus.UnicodeData.load_async( -+ Config.PKGDATADIR + "/dicts/unicode-names.dict", -+ source_object, -+ null, -+ (IBus.UnicodeDataLoadAsyncFinish)make_unicode_name_dict_finish); -+ } -+ -+ private static void -+ make_unicode_name_dict_finish(GLib.SList unicode_list) { -+ if (unicode_list == null) -+ return; -+ foreach (IBus.UnicodeData data in unicode_list) { -+ update_unicode_to_data_dict(data); -+ update_name_to_unicodes_dict(data); -+ } -+ GLib.List names = -+ m_name_to_unicodes_dict.get_keys(); -+ foreach (unowned string name in names) { -+ if (m_emoji_max_seq_len < name.length) -+ m_emoji_max_seq_len = name.length; -+ } -+ m_loaded_unicode = true; -+ } -+ -+ -+ private static void update_unicode_to_data_dict(IBus.UnicodeData data) { -+ unichar code = data.get_code(); -+ m_unicode_to_data_dict.replace(code, data); -+ } -+ -+ -+ private static void update_name_to_unicodes_dict(IBus.UnicodeData data) { -+ unichar code = data.get_code(); -+ string[] names = {data.get_name().down(), data.get_alias().down()}; -+ foreach (unowned string name in names) { -+ if (name == "") -+ continue; -+ bool has_code = false; -+ GLib.SList hits = -+ m_name_to_unicodes_dict.lookup(name).copy(); -+ foreach (unichar hit_code in hits) { -+ if (hit_code == code) { -+ has_code = true; -+ break; -+ } -+ } -+ if (!has_code) { -+ hits.append(code); -+ m_name_to_unicodes_dict.replace(name, hits.copy()); -+ } -+ } -+ } -+ -+ - private void set_fixed_size() { - resize(20, 1); - } -@@ -665,6 +823,7 @@ class IBusEmojier : Gtk.ApplicationWindow { - m_scrolled_window = new EScrolledWindow(); - set_fixed_size(); - -+ m_title.set_title(_("Emoji Choice")); - string language = - IBus.get_language_name(m_current_lang_id); - m_title.set_lang_label(language); -@@ -677,12 +836,12 @@ class IBusEmojier : Gtk.ApplicationWindow { - Gtk.Adjustment adjustment = m_scrolled_window.get_vadjustment(); - m_list_box.set_adjustment(adjustment); - m_list_box.row_activated.connect((box, gtkrow) => { -- m_category_active_index = 0; -+ m_category_active_index = -1; - EBoxRow row = gtkrow as EBoxRow; - show_emoji_for_category(row.text); - }); - -- uint n = 1; -+ uint n = 0; - if (m_favorites.length > 0) { - EBoxRow row = new EBoxRow(EMOJI_CATEGORY_FAVORITES); - EPaddedLabelBox widget = -@@ -716,9 +875,19 @@ class IBusEmojier : Gtk.ApplicationWindow { - if (n++ == m_category_active_index) - m_list_box.select_row(row); - } -+ if (m_unicode_block_list.length() > 0) { -+ EBoxRow row = new EBoxRow(EMOJI_CATEGORY_UNICODE); -+ EPaddedLabelBox widget = -+ new EPaddedLabelBox(_(EMOJI_CATEGORY_UNICODE), -+ Gtk.Align.CENTER); -+ row.add(widget); -+ m_list_box.add(row); -+ if (n++ == m_category_active_index) -+ m_list_box.select_row(row); -+ } - - m_scrolled_window.show_all(); -- if (m_category_active_index == 0) -+ if (m_category_active_index == -1) - m_list_box.unselect_all(); - m_list_box.invalidate_filter(); - m_list_box.set_selection_mode(Gtk.SelectionMode.SINGLE); -@@ -733,6 +902,11 @@ class IBusEmojier : Gtk.ApplicationWindow { - m_lookup_table.append_candidate(text); - } - m_backward = category; -+ } else if (category == EMOJI_CATEGORY_UNICODE) { -+ m_category_active_index = -1; -+ m_show_unicode = true; -+ show_unicode_blocks(); -+ return; - } else { - unowned GLib.SList emojis = - m_category_to_emojis_dict.lookup(category); -@@ -764,6 +938,126 @@ class IBusEmojier : Gtk.ApplicationWindow { - } - - -+ private void show_unicode_blocks() { -+ m_show_unicode = true; -+ if (m_default_window_width == 0 && m_default_window_height == 0) -+ get_size(out m_default_window_width, out m_default_window_height); -+ remove_all_children(); -+ set_fixed_size(); -+ -+ m_title.set_title(_("Unicode Choice")); -+ EPaddedLabelBox label = -+ new EPaddedLabelBox(_("Bring back emoji choice"), -+ Gtk.Align.CENTER, -+ TravelDirection.BACKWARD); -+ Gtk.Button button = new Gtk.Button(); -+ button.add(label); -+ m_vbox.add(button); -+ button.show_all(); -+ button.button_press_event.connect((w, e) => { -+ m_category_active_index = -1; -+ m_show_unicode = false; -+ hide_candidate_panel(); -+ return true; -+ }); -+ m_scrolled_window = new EScrolledWindow(); -+ m_title.set_lang_label(""); -+ m_vbox.add(m_scrolled_window); -+ Gtk.Viewport viewport = new Gtk.Viewport(null, null); -+ m_scrolled_window.add(viewport); -+ -+ m_list_box = new EListBox(); -+ viewport.add(m_list_box); -+ Gtk.Adjustment adjustment = m_scrolled_window.get_vadjustment(); -+ m_list_box.set_adjustment(adjustment); -+ m_list_box.row_activated.connect((box, gtkrow) => { -+ m_category_active_index = -1; -+ EBoxRow row = gtkrow as EBoxRow; -+ show_unicode_for_block(row.text); -+ }); -+ -+ uint n = 0; -+ foreach (unowned IBus.UnicodeBlock block in m_unicode_block_list) { -+ string name = block.get_name(); -+ EBoxRow row = new EBoxRow(name); -+ EPaddedLabelBox widget = -+ new EPaddedLabelBox(_(name), Gtk.Align.CENTER); -+ row.add(widget); -+ m_list_box.add(row); -+ if (n++ == m_category_active_index) { -+ m_list_box.select_row(row); -+ } -+ } -+ -+ set_size_request(-1, m_default_window_height + 100); -+ m_scrolled_window.set_policy(Gtk.PolicyType.NEVER, -+ Gtk.PolicyType.AUTOMATIC); -+ m_scrolled_window.show_all(); -+ if (m_category_active_index == -1) -+ m_list_box.unselect_all(); -+ m_list_box.invalidate_filter(); -+ m_list_box.set_selection_mode(Gtk.SelectionMode.SINGLE); -+ } -+ -+ private void show_unicode_for_block(string block_name) { -+ if (!m_loaded_unicode) { -+ remove_all_children(); -+ set_fixed_size(); -+ m_unicode_progress_bar = new Gtk.ProgressBar(); -+ m_unicode_progress_bar.set_ellipsize(Pango.EllipsizeMode.MIDDLE); -+ m_unicode_progress_bar.set_halign(Gtk.Align.CENTER); -+ m_unicode_progress_bar.set_valign(Gtk.Align.CENTER); -+ m_vbox.add(m_unicode_progress_bar); -+ m_unicode_progress_bar.show(); -+ var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 5); -+ hbox.set_halign(Gtk.Align.CENTER); -+ hbox.set_valign(Gtk.Align.CENTER); -+ m_vbox.add(hbox); -+ var label = new Gtk.Label(_("Loading a Unicode dictionary:")); -+ hbox.pack_start(label, false, true, 0); -+ m_unicode_percent_label = new Gtk.Label(""); -+ hbox.pack_start(m_unicode_percent_label, false, true, 0); -+ hbox.show_all(); -+ -+ m_unicode_progress_object.deserialize_unicode.connect((i, n) => { -+ m_unicode_percent = (double)i / n; -+ }); -+ GLib.Timeout.add(100, () => { -+ m_unicode_progress_bar.set_fraction(m_unicode_percent); -+ m_unicode_percent_label.set_text( -+ "%.0f%%\n".printf(m_unicode_percent * 100)); -+ m_unicode_progress_bar.show(); -+ m_unicode_percent_label.show(); -+ if (m_loaded_unicode) { -+ show_unicode_for_block(block_name); -+ } -+ return !m_loaded_unicode; -+ }); -+ return; -+ } -+ unichar start = 0; -+ unichar end = 0; -+ foreach (unowned IBus.UnicodeBlock block in m_unicode_block_list) { -+ string name = block.get_name(); -+ if (block_name == name) { -+ start = block.get_start(); -+ end = block.get_end(); -+ } -+ } -+ m_lookup_table.clear(); -+ for (unichar ch = start; ch < end; ch++) { -+ unowned IBus.UnicodeData? data = -+ m_unicode_to_data_dict.lookup(ch); -+ if (data == null) -+ continue; -+ IBus.Text text = new IBus.Text.from_unichar(ch); -+ m_lookup_table.append_candidate(text); -+ } -+ m_backward = block_name; -+ show_candidate_panel(); -+ } -+ -+ - private void show_arrow_buttons() { - Gtk.Button next_button = new Gtk.Button(); - next_button.clicked.connect(() => { -@@ -840,6 +1134,7 @@ class IBusEmojier : Gtk.ApplicationWindow { - lookup_emojis_from_annotation(string annotation) { - GLib.SList? total_emojis = null; - unowned GLib.SList? sub_emojis = null; -+ unowned GLib.SList? sub_unicodes = null; - int length = annotation.length; - if (m_has_partial_match && length >= m_partial_match_length) { - foreach (unowned string key in -@@ -877,6 +1172,22 @@ class IBusEmojier : Gtk.ApplicationWindow { - foreach (unowned string emoji in sub_emojis) - total_emojis.append(emoji); - } -+ if (length >= m_partial_match_length) { -+ foreach (unowned string key in m_name_to_unicodes_dict.get_keys()) { -+ bool matched = false; -+ if (key.index_of(annotation) >= 0) -+ matched = true; -+ if (!matched) -+ continue; -+ sub_unicodes = m_name_to_unicodes_dict.lookup(key); -+ foreach (unichar code in sub_unicodes) { -+ string ch = code.to_string(); -+ if (total_emojis.find_custom(ch, GLib.strcmp) == null) { -+ total_emojis.append(ch); -+ } -+ } -+ } -+ } - return total_emojis; - } - -@@ -1049,58 +1360,99 @@ class IBusEmojier : Gtk.ApplicationWindow { - grid.show_all(); - string text = m_lookup_table.get_candidate(cursor).text; - unowned IBus.EmojiData? data = m_emoji_to_data_dict.lookup(text); -- if (data == null) { -- // TODO: Provide a custom description and annotation for -- // the favorite emojis. -- EPaddedLabelBox widget = new EPaddedLabelBox( -- _("Description: %s").printf(_("None")), -- Gtk.Align.START); -- m_vbox.add(widget); -- widget.show_all(); -- show_code_point_description(text); -+ if (data != null) { -+ show_emoji_description(data, text); - return; -- } else { -- unowned string description = data.get_description(); -- EPaddedLabelBox widget = new EPaddedLabelBox( -- _("Description: %s").printf(description), -- Gtk.Align.START); -- m_vbox.add(widget); -- widget.show_all(); - } -- unowned GLib.SList? annotations = -- data.get_annotations(); -- var buff = new GLib.StringBuilder(); -- int i = 0; -- foreach (unowned string annotation in annotations) { -- if (i++ == 0) -- buff.append_printf(_("Annotations: %s"), annotation); -- else -- buff.append_printf(" | %s", annotation); -- if (buff.str.char_count() > 30) { -- EPaddedLabelBox widget = -- new EPaddedLabelBox(buff.str, -- Gtk.Align.START); -- m_vbox.add(widget); -- widget.show_all(); -- buff.erase(); -+ if (text.char_count() <= 1) { -+ unichar code = text.get_char(); -+ unowned IBus.UnicodeData? udata = -+ m_unicode_to_data_dict.lookup(code); -+ if (udata != null) { -+ show_unicode_description(udata, text); -+ return; - } - } -- if (buff.str != "") { -- EPaddedLabelBox widget = new EPaddedLabelBox(buff.str, -- Gtk.Align.START); -+ // TODO: Provide a custom description and annotation for -+ // the favorite emojis. -+ EPaddedLabelBox widget = new EPaddedLabelBox( -+ _("Description: %s").printf(_("None")), -+ Gtk.Align.START); -+ m_vbox.add(widget); -+ widget.show_all(); -+ show_code_point_description(text); -+ } -+ } -+ -+ -+ private void show_emoji_description(IBus.EmojiData data, -+ string text) { -+ unowned string description = data.get_description(); -+ { -+ EPaddedLabelBox widget = new EPaddedLabelBox( -+ _("Description: %s").printf(description), -+ Gtk.Align.START); -+ m_vbox.add(widget); -+ widget.show_all(); -+ } -+ unowned GLib.SList? annotations = -+ data.get_annotations(); -+ var buff = new GLib.StringBuilder(); -+ int i = 0; -+ foreach (unowned string annotation in annotations) { -+ if (i++ == 0) -+ buff.append_printf(_("Annotations: %s"), annotation); -+ else -+ buff.append_printf(" | %s", annotation); -+ if (buff.str.char_count() > 30) { -+ EPaddedLabelBox widget = -+ new EPaddedLabelBox(buff.str, -+ Gtk.Align.START); - m_vbox.add(widget); - widget.show_all(); -+ buff.erase(); - } -- show_code_point_description(text); - } -+ if (buff.str != "") { -+ EPaddedLabelBox widget = new EPaddedLabelBox(buff.str, -+ Gtk.Align.START); -+ m_vbox.add(widget); -+ widget.show_all(); -+ } -+ show_code_point_description(text); -+ } -+ -+ private void show_unicode_description(IBus.UnicodeData data, -+ string text) { -+ unowned string name = data.get_name(); -+ { -+ EPaddedLabelBox widget = new EPaddedLabelBox( -+ _("Name: %s").printf(name), -+ Gtk.Align.START); -+ m_vbox.add(widget); -+ widget.show_all(); -+ } -+ unowned string alias = data.get_alias(); -+ { -+ EPaddedLabelBox widget = new EPaddedLabelBox( -+ _("Alias: %s").printf(alias), -+ Gtk.Align.START); -+ m_vbox.add(widget); -+ widget.show_all(); -+ } -+ show_code_point_description(text); - } - - - private void hide_candidate_panel() { - m_enter_notify_enable = true; - m_candidate_panel_is_visible = false; -- if (m_loop.is_running()) -- show_category_list(); -+ if (m_loop.is_running()) { -+ if (m_show_unicode) -+ show_unicode_blocks(); -+ else -+ show_category_list(); -+ } - } - - -@@ -1165,19 +1517,41 @@ class IBusEmojier : Gtk.ApplicationWindow { - } - - -- private void category_list_cursor_move(uint keyval) { -+ private bool category_list_cursor_move(uint keyval) { - GLib.List list = m_list_box.get_children(); -- if (keyval == Gdk.Key.Down) { -- m_category_active_index = -- ++m_category_active_index % ((int)list.length() + 1); -- } else if (keyval == Gdk.Key.Up) { -+ int length = (int)list.length(); -+ if (length == 0) -+ return false; -+ switch(keyval) { -+ case Gdk.Key.Down: -+ if (++m_category_active_index == length) -+ m_category_active_index = 0; -+ break; -+ case Gdk.Key.Up: - if (--m_category_active_index < 0) -- m_category_active_index = (int)list.length(); -+ m_category_active_index = length - 1; -+ break; -+ case Gdk.Key.Home: -+ m_category_active_index = 0; -+ break; -+ case Gdk.Key.End: -+ m_category_active_index = length - 1; -+ break; - } -- Gtk.Adjustment adjustment = m_list_box.get_adjustment(); -- m_scrolled_window.set_hadjustment(new Gtk.Adjustment(0, 0, 0, 0, 0, 0)); -- m_scrolled_window.set_vadjustment(adjustment); -- show_category_list(); -+ var row = m_list_box.get_selected_row(); -+ if (row != null) -+ m_list_box.unselect_row(row); -+ if (m_category_active_index >= 0) { -+ row = m_list_box.get_row_at_index(m_category_active_index); -+ m_list_box.select_row(row); -+ } else { -+ row = m_list_box.get_row_at_index(0); -+ } -+ Gtk.Allocation alloc = { 0, 0, 0, 0 }; -+ row.get_allocation(out alloc); -+ var adjustment = m_scrolled_window.get_vadjustment(); -+ adjustment.clamp_page(alloc.y, alloc.y + alloc.height); -+ return true; - } - - -@@ -1211,7 +1585,7 @@ class IBusEmojier : Gtk.ApplicationWindow { - keyval = Gdk.Key.Up; - else if (keyval == Gdk.Key.Right) - keyval = Gdk.Key.Down; -- category_list_cursor_move(keyval); -+ return category_list_cursor_move(keyval); - } - return true; - } -@@ -1227,7 +1601,7 @@ class IBusEmojier : Gtk.ApplicationWindow { - else if (keyval == Gdk.Key.Up) - candidate_panel_cursor_up(); - } else { -- category_list_cursor_move(keyval); -+ return category_list_cursor_move(keyval); - } - return true; - } -@@ -1262,12 +1636,25 @@ class IBusEmojier : Gtk.ApplicationWindow { - ? true : false); - return true; - } -+ if (!m_candidate_panel_is_visible) -+ return category_list_cursor_move(keyval); - return false; - } - - - private bool key_press_escape() { -- if (m_backward_index >= 0 && m_backward != null) { -+ if (m_show_unicode) { -+ if (m_candidate_panel_is_visible) { -+ m_candidate_panel_is_visible = false; -+ show_unicode_blocks(); -+ return true; -+ } else { -+ m_show_unicode = false; -+ m_category_active_index = -1; -+ hide_candidate_panel(); -+ return true; -+ } -+ } else if (m_backward_index >= 0 && m_backward != null) { - show_emoji_for_category(m_backward); - return true; - } else if (m_candidate_panel_is_visible) { -@@ -1287,10 +1674,13 @@ class IBusEmojier : Gtk.ApplicationWindow { - if (m_candidate_panel_is_visible) { - uint index = m_lookup_table.get_cursor_pos(); - candidate_panel_select_index(index); -- } else if (m_category_active_index > 0) { -+ } else if (m_category_active_index >= 0) { - Gtk.ListBoxRow gtkrow = m_list_box.get_selected_row(); - EBoxRow row = gtkrow as EBoxRow; -- show_emoji_for_category(row.text); -+ if (m_show_unicode) -+ show_unicode_for_block(row.text); -+ else -+ show_emoji_for_category(row.text); - } - return true; - } -@@ -1380,6 +1770,7 @@ class IBusEmojier : Gtk.ApplicationWindow { - m_candidate_panel_is_visible = false; - m_result = null; - m_enter_notify_enable = true; -+ m_show_unicode = false; - - /* Let gtk recalculate the window size. */ - resize(1, 1); -@@ -1399,8 +1790,9 @@ class IBusEmojier : Gtk.ApplicationWindow { - * prevention logic: - * https://mail.gnome.org/archives/gtk-devel-list/2017-May/msg00026.html - */ -- uint32 timestamp = event.get_time(); -- present_with_time(timestamp); -+ //uint32 timestamp = event.get_time(); -+ //present_with_time(timestamp); -+ present_centralize(event); - - Gdk.Device pointer; - #if VALA_0_34 -@@ -1646,18 +2038,24 @@ class IBusEmojier : Gtk.ApplicationWindow { - Gtk.Allocation allocation; - get_allocation(out allocation); - Gdk.Rectangle monitor_area; -+ Gdk.Rectangle work_area; - #if VALA_0_34 - Gdk.Display display = Gdk.Display.get_default(); - Gdk.Monitor monitor = display.get_monitor_at_window(this.get_window()); - monitor_area = monitor.get_geometry(); -+ work_area = monitor.get_workarea(); - #else - Gdk.Screen screen = Gdk.Screen.get_default(); - int monitor_num = screen.get_monitor_at_window(this.get_window()); - screen.get_monitor_geometry(monitor_num, out monitor_area); -+ work_area = screen.get_monitor_workarea(monitor_num); - #endif - int x = (monitor_area.x + monitor_area.width - allocation.width)/2; - int y = (monitor_area.y + monitor_area.height - - allocation.height)/2; -+ // Do not hide a bottom panel in XFCE4 -+ if (work_area.y < y) -+ y = work_area.y; - move(x, y); - - uint32 timestamp = event.get_time(); -@@ -1723,7 +2121,6 @@ class IBusEmojier : Gtk.ApplicationWindow { - string? favorite = unowned_favorites[i]; - // Avoid gsetting value error by manual setting - GLib.return_if_fail(favorite != null); -- GLib.return_if_fail(favorite != ""); - m_favorites += favorite; - } - for(int i = 0; i < unowned_favorite_annotations.length; i++) { -@@ -1733,4 +2130,19 @@ class IBusEmojier : Gtk.ApplicationWindow { - } - update_favorite_emoji_dict(); - } -+ -+ -+ private static GLib.Object get_load_progress_object() { -+ if (m_unicode_progress_object == null) -+ m_unicode_progress_object = new LoadProgressObject(); -+ return m_unicode_progress_object as GLib.Object; -+ } -+ -+ -+ public static void load_unicode_dict() { -+ if (m_unicode_block_list.length() == 0) -+ make_unicode_block_dict(); -+ if (m_name_to_unicodes_dict.size() == 0) -+ make_unicode_name_dict(IBusEmojier.get_load_progress_object()); -+ } - } -diff --git a/ui/gtk3/emojierapp.vala b/ui/gtk3/emojierapp.vala -index 6615f22b..d816352e 100644 ---- a/ui/gtk3/emojierapp.vala -+++ b/ui/gtk3/emojierapp.vala -@@ -176,6 +176,8 @@ public class EmojiApplication : Application { - m_settings_emoji.get_strv("favorites"), - m_settings_emoji.get_strv("favorite-annotations")); - -+ IBusEmojier.load_unicode_dict(); -+ - activate_dialog(command_line); - - return Posix.EXIT_SUCCESS; -diff --git a/ui/gtk3/ibusemojidialog.h b/ui/gtk3/ibusemojidialog.h -index ed8886a8..3b420b21 100644 ---- a/ui/gtk3/ibusemojidialog.h -+++ b/ui/gtk3/ibusemojidialog.h -@@ -1,7 +1,7 @@ - /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ - /* vim:set et sts=4: */ - /* bus - The Input Bus -- * Copyright (C) 2017 Takao Fujiwara -+ * Copyright (C) 2017-2018 Takao Fujiwara - * Copyright (C) 2017 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or -@@ -196,5 +196,12 @@ void ibus_emojier_set_partial_match_length - */ - void ibus_emojier_set_partial_match_condition - (gint condition); -+/** -+ * ibus_emojier_load_unicode_dict: -+ * -+ * Load the dictionary of #IBusUnicodeData. -+ */ -+void ibus_emojier_load_unicode_dict (void); -+ - G_END_DECLS - #endif -diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala -index 4f032f6f..bcb3ed75 100644 ---- a/ui/gtk3/panel.vala -+++ b/ui/gtk3/panel.vala -@@ -3,7 +3,7 @@ - * ibus - The Input Bus - * - * Copyright(c) 2011-2014 Peng Huang -- * Copyright(c) 2015-2017 Takao Fujwiara -+ * Copyright(c) 2015-2018 Takao Fujwiara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -871,6 +871,7 @@ class Panel : IBus.PanelService { - IBusEmojier.set_annotation_lang( - m_settings_emoji.get_string("lang")); - m_emojier_set_emoji_lang_id = 0; -+ IBusEmojier.load_unicode_dict(); - return false; - }); - } --- -2.14.3 - -From 4cfd5ad7c6d071cfef6c7d678cc027ea480b8fc9 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 6 Feb 2018 11:02:09 +0900 -Subject: [PATCH] Fix typo in ibusunicode.c - -Review URL: https://codereview.appspot.com/340740043 ---- - src/ibusunicode.c | 5 +++-- - ui/gtk3/emojier.vala | 4 ---- - 2 files changed, 3 insertions(+), 6 deletions(-) - -diff --git a/src/ibusunicode.c b/src/ibusunicode.c -index 8559819d..aac9c135 100644 ---- a/src/ibusunicode.c -+++ b/src/ibusunicode.c -@@ -412,7 +412,8 @@ ibus_unicode_data_list_deserialize (GVariant *variant, - IBUS_UNICODE_DESERIALIZE_SIGNALL_STR, - G_OBJECT_TYPE (source_object)); - if (!has_signal) { -- const gchar type_name = g_type_name (source_object); -+ const gchar *type_name = -+ g_type_name (G_OBJECT_TYPE (source_object)); - g_warning ("GObject %s does not have the signal \"%s\"", - type_name ? type_name : "(null)", - IBUS_UNICODE_DESERIALIZE_SIGNALL_STR); -@@ -677,7 +678,7 @@ ibus_unicode_block_class_init (IBusUnicodeBlockClass *class) - GObjectClass *gobject_class = G_OBJECT_CLASS (class); - IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class); - -- object_class->destroy = (IBusObjectDestroyFunc) ibus_unicode_data_destroy; -+ object_class->destroy = (IBusObjectDestroyFunc) ibus_unicode_block_destroy; - gobject_class->set_property = - (GObjectSetPropertyFunc) ibus_unicode_block_set_property; - gobject_class->get_property = -diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala -index 555ea68f..0bf34da8 100644 ---- a/ui/gtk3/emojier.vala -+++ b/ui/gtk3/emojier.vala -@@ -1373,8 +1373,6 @@ public class IBusEmojier : Gtk.ApplicationWindow { - return; - } - } -- // TODO: Provide a custom description and annotation for -- // the favorite emojis. - EPaddedLabelBox widget = new EPaddedLabelBox( - _("Description: %s").printf(_("None")), - Gtk.Align.START); -@@ -1790,8 +1788,6 @@ public class IBusEmojier : Gtk.ApplicationWindow { - * prevention logic: - * https://mail.gnome.org/archives/gtk-devel-list/2017-May/msg00026.html - */ -- //uint32 timestamp = event.get_time(); -- //present_with_time(timestamp); - present_centralize(event); - - Gdk.Device pointer; --- -2.14.3 - -From fb07f64764f18f702221ff5574b2fd2193f051f0 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 20 Feb 2018 17:25:07 +0900 -Subject: [PATCH] Implement ibus-extension-gtk3 for the global keybinding - -Currently IBus panel (ibus-ui-gtk3) is not available in GNOME and Plasma -so the emoji and unicode point typings are not available in GNOME and Plasma. -The workaround `ibus emoji` command is available but it put the selected -character into the copy buffer and users have to paste the character. - -Originaly the emoji feature was implemented in IBus GtkIMModule but -it had several problems; the first is the keybinding is hard-coded -and IBus GtkIMModule does not use GSettings for the customized settings. -The second is the feature was available for GTK applications. -The third is that XKB input sources uses gtk-im-context-simple -but not ibus in GNOME desktop so users have to add an IM input sources -to enable IBus for the XKB input sources. The fourth is the feature -was available for IBusEngineSimple only and other IBus IMEs need to -inherit that class to get the emoji feature. The fifth is that -emoji typing is available for English only since IBusEngineSimple -had the feature. The sixth is that the default one dimension lookup -window was not useful to choose an emoji and needed two dimensions -lookup window. - -And the implementation was moved from IBus GtkIMModule to IBus panel -to fix above problems. -But users have to use `ibus emoji` at present if ibus-ui-gtk3 -is not available. - -Now I think to move the emoji feature from ibus-ui-gtk3 to another -IBus component; ibus-extension-gtk3 which manages the Ctrl-Shift-e. -GNOME and Plasma desktops still do not show the GUI menu but -the shortcut key is available in this implementation. - -BUG=RHBZ#1430501 -R=Shawn.P.Huang@gmail.com - -Review URL: https://codereview.appspot.com/339300043 ---- - bindings/vala/IBus-1.0-custom.vala | 4 + - bus/Makefile.am | 7 +- - bus/ibusimpl.c | 82 ++- - bus/main.c | 25 +- - bus/marshalers.list | 1 + - bus/panelproxy.c | 57 +- - bus/panelproxy.h | 20 +- - src/Makefile.am | 4 +- - src/ibus.h | 1 + - src/ibusmarshalers.list | 1 + - src/ibuspanelservice.c | 81 ++- - src/ibuspanelservice.h | 15 +- - src/ibusserializable.c | 7 +- - src/ibusserializable.h | 18 +- - src/ibusshare.c | 4 +- - src/ibusshare.h | 17 +- - src/ibusxevent.c | 1004 ++++++++++++++++++++++++++++++++++++ - src/ibusxevent.h | 294 +++++++++++ - src/tests/runtest | 1 + - ui/gtk3/Makefile.am | 59 ++- - ui/gtk3/bindingcommon.vala | 215 ++++++++ - ui/gtk3/candidatearea.vala | 102 ---- - ui/gtk3/extension.vala | 124 +++++ - ui/gtk3/gtkextension.xml.in | 12 + - ui/gtk3/iconwidget.vala | 103 ++++ - ui/gtk3/panel.vala | 408 +++------------ - ui/gtk3/panelbinding.vala | 335 ++++++++++++ - 27 files changed, 2506 insertions(+), 495 deletions(-) - create mode 100644 src/ibusxevent.c - create mode 100644 src/ibusxevent.h - create mode 100644 ui/gtk3/bindingcommon.vala - create mode 100644 ui/gtk3/extension.vala - create mode 100644 ui/gtk3/gtkextension.xml.in - create mode 100644 ui/gtk3/panelbinding.vala - -diff --git a/bindings/vala/IBus-1.0-custom.vala b/bindings/vala/IBus-1.0-custom.vala -index 144d75e2..cf1fc3fa 100644 ---- a/bindings/vala/IBus-1.0-custom.vala -+++ b/bindings/vala/IBus-1.0-custom.vala -@@ -6,4 +6,8 @@ namespace IBus { - [CCode (cname = "ibus_text_new_from_static_string", has_construct_function = false)] - public Text.from_static_string (string str); - } -+ public class XEvent : IBus.Serializable { -+ [CCode (cname = "ibus_x_event_new", has_construct_function = true)] -+ public XEvent (string first_property_name, ...); -+ } - } -diff --git a/bus/Makefile.am b/bus/Makefile.am -index 864ba923..8bcc8e16 100644 ---- a/bus/Makefile.am -+++ b/bus/Makefile.am -@@ -3,7 +3,8 @@ - # ibus - The Input Bus - # - # Copyright (c) 2007-2013 Peng Huang --# Copyright (c) 2007-2013 Red Hat, Inc. -+# Copyright (c) 2013-2018 Takao Fujiwara -+# Copyright (c) 2007-2018 Red Hat, Inc. - # - # This library is free software; you can redistribute it and/or - # modify it under the terms of the GNU Lesser General Public -@@ -105,6 +106,10 @@ marshalers.c: marshalers.h marshalers.list - $(GLIB_GENMARSHAL) --prefix=bus_marshal $(srcdir)/marshalers.list --body --internal) > $@.tmp && \ - mv $@.tmp $@ - -+if ENABLE_EMOJI_DICT -+AM_CFLAGS += -DEMOJI_DICT -+endif -+ - - if ENABLE_TESTS - TESTS = \ -diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c -index f99307ad..58d205cf 100644 ---- a/bus/ibusimpl.c -+++ b/bus/ibusimpl.c -@@ -2,7 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2008-2013 Red Hat, Inc. -+ * Copyright (C) 2011-2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -73,6 +74,7 @@ struct _BusIBusImpl { - - BusInputContext *focused_context; - BusPanelProxy *panel; -+ BusPanelProxy *extension; - - /* a default keymap of ibus-daemon (usually "us") which is used only - * when use_sys_layout is FALSE. */ -@@ -290,12 +292,37 @@ _panel_destroy_cb (BusPanelProxy *panel, - g_assert (BUS_IS_PANEL_PROXY (panel)); - g_assert (BUS_IS_IBUS_IMPL (ibus)); - -- g_return_if_fail (ibus->panel == panel); -- -- ibus->panel = NULL; -+ if (ibus->panel == panel) -+ ibus->panel = NULL; -+ else if (ibus->extension == panel) -+ ibus->extension = NULL; -+ else -+ g_return_if_reached (); - g_object_unref (panel); - } - -+static void -+_panel_panel_extension_cb (BusPanelProxy *panel, -+ GVariant *parameters, -+ BusIBusImpl *ibus) -+{ -+ if (!ibus->extension) { -+ g_warning ("Panel extension is not running."); -+ return; -+ } -+ -+ g_return_if_fail (BUS_IS_IBUS_IMPL (ibus)); -+ g_return_if_fail (BUS_IS_PANEL_PROXY (ibus->extension)); -+ -+ /* Use the DBus method because it seems any DBus signal, -+ * g_dbus_message_new_signal(), cannot be reached to the server. */ -+ g_dbus_proxy_call (G_DBUS_PROXY (ibus->extension), -+ "PanelExtensionReceived", -+ parameters, -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, NULL, NULL, NULL); -+} -+ - static void - _registry_changed_cb (IBusRegistry *registry, - BusIBusImpl *ibus) -@@ -317,33 +344,47 @@ _dbus_name_owner_changed_cb (BusDBusImpl *dbus, - const gchar *new_name, - BusIBusImpl *ibus) - { -+ PanelType panel_type = PANEL_TYPE_NONE; -+ - g_assert (BUS_IS_DBUS_IMPL (dbus)); - g_assert (name != NULL); - g_assert (old_name != NULL); - g_assert (new_name != NULL); - g_assert (BUS_IS_IBUS_IMPL (ibus)); - -- if (g_strcmp0 (name, IBUS_SERVICE_PANEL) == 0) { -+ if (!g_strcmp0 (name, IBUS_SERVICE_PANEL)) -+ panel_type = PANEL_TYPE_PANEL; -+ else if (!g_strcmp0 (name, IBUS_SERVICE_PANEL_EXTENSION)) -+ panel_type = PANEL_TYPE_EXTENSION; -+ -+ if (panel_type != PANEL_TYPE_NONE) { - if (g_strcmp0 (new_name, "") != 0) { - /* a Panel process is started. */ - BusConnection *connection; - BusInputContext *context = NULL; -- -- if (ibus->panel != NULL) { -- ibus_proxy_destroy ((IBusProxy *) ibus->panel); -- /* panel should be NULL after destroy. See _panel_destroy_cb for details. */ -- g_assert (ibus->panel == NULL); -+ BusPanelProxy **panel = (panel_type == PANEL_TYPE_PANEL) ? -+ &ibus->panel : &ibus->extension; -+ -+ if (*panel != NULL) { -+ ibus_proxy_destroy ((IBusProxy *)(*panel)); -+ /* panel should be NULL after destroy. See _panel_destroy_cb -+ * for details. */ -+ g_assert (*panel == NULL); - } - - connection = bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, new_name); - g_return_if_fail (connection != NULL); - -- ibus->panel = bus_panel_proxy_new (connection); -+ *panel = bus_panel_proxy_new (connection, panel_type); - -- g_signal_connect (ibus->panel, -+ g_signal_connect (*panel, - "destroy", - G_CALLBACK (_panel_destroy_cb), - ibus); -+ g_signal_connect (*panel, -+ "panel-extension", -+ G_CALLBACK (_panel_panel_extension_cb), -+ ibus); - - if (ibus->focused_context != NULL) { - context = ibus->focused_context; -@@ -355,14 +396,13 @@ _dbus_name_owner_changed_cb (BusDBusImpl *dbus, - if (context != NULL) { - BusEngineProxy *engine; - -- bus_panel_proxy_focus_in (ibus->panel, context); -+ bus_panel_proxy_focus_in (*panel, context); - - engine = bus_input_context_get_engine (context); - if (engine != NULL) { - IBusPropList *prop_list = - bus_engine_proxy_get_properties (engine); -- bus_panel_proxy_register_properties (ibus->panel, -- prop_list); -+ bus_panel_proxy_register_properties (*panel, prop_list); - } - } - } -@@ -403,6 +443,7 @@ bus_ibus_impl_init (BusIBusImpl *ibus) - ibus->contexts = NULL; - ibus->focused_context = NULL; - ibus->panel = NULL; -+ ibus->extension = NULL; - - ibus->keymap = ibus_keymap_get ("us"); - -@@ -635,6 +676,8 @@ bus_ibus_impl_set_focused_context (BusIBusImpl *ibus, - - if (ibus->panel != NULL) - bus_panel_proxy_focus_out (ibus->panel, ibus->focused_context); -+ if (ibus->extension != NULL) -+ bus_panel_proxy_focus_out (ibus->extension, ibus->focused_context); - - bus_input_context_get_content_type (ibus->focused_context, - &purpose, &hints); -@@ -658,6 +701,8 @@ bus_ibus_impl_set_focused_context (BusIBusImpl *ibus, - - if (ibus->panel != NULL) - bus_panel_proxy_focus_in (ibus->panel, context); -+ if (ibus->extension != NULL) -+ bus_panel_proxy_focus_in (ibus->extension, context); - } - - if (engine != NULL) -@@ -846,8 +891,13 @@ _context_destroy_cb (BusInputContext *context, - bus_ibus_impl_set_focused_context (ibus, NULL); - - if (ibus->panel && -- bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS) -+ bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS) { - bus_panel_proxy_destroy_context (ibus->panel, context); -+ } -+ if (ibus->extension && -+ bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS) { -+ bus_panel_proxy_destroy_context (ibus->extension, context); -+ } - - ibus->contexts = g_list_remove (ibus->contexts, context); - g_object_unref (context); -diff --git a/bus/main.c b/bus/main.c -index 6ad60179..5b2589b1 100644 ---- a/bus/main.c -+++ b/bus/main.c -@@ -2,7 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2008-2013 Red Hat, Inc. -+ * Copyright (C) 2013-2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -42,6 +43,7 @@ static gboolean xim = FALSE; - static gboolean replace = FALSE; - static gboolean restart = FALSE; - static gchar *panel = "default"; -+static gchar *panel_extension = "default"; - static gchar *config = "default"; - static gchar *desktop = "gnome"; - -@@ -60,6 +62,7 @@ static const GOptionEntry entries[] = - { "xim", 'x', 0, G_OPTION_ARG_NONE, &xim, "execute ibus XIM server.", NULL }, - { "desktop", 'n', 0, G_OPTION_ARG_STRING, &desktop, "specify the name of desktop session. [default=gnome]", "name" }, - { "panel", 'p', 0, G_OPTION_ARG_STRING, &panel, "specify the cmdline of panel program. pass 'disable' not to start a panel program.", "cmdline" }, -+ { "panel-extension", 'E', 0, G_OPTION_ARG_STRING, &panel_extension, "specify the cmdline of panel extension program. pass 'disable' not to start an extension program.", "cmdline" }, - { "config", 'c', 0, G_OPTION_ARG_STRING, &config, "specify the cmdline of config program. pass 'disable' not to start a config program.", "cmdline" }, - { "address", 'a', 0, G_OPTION_ARG_STRING, &g_address, "specify the address of ibus daemon.", "address" }, - { "replace", 'r', 0, G_OPTION_ARG_NONE, &replace, "if there is an old ibus-daemon is running, it will be replaced.", NULL }, -@@ -268,7 +271,27 @@ main (gint argc, gchar **argv) - if (!execute_cmdline (panel)) - exit (-1); - } -+ -+#ifdef EMOJI_DICT -+ if (g_strcmp0 (panel_extension, "default") == 0) { -+ BusComponent *component; -+ component = bus_ibus_impl_lookup_component_by_name ( -+ BUS_DEFAULT_IBUS, IBUS_SERVICE_PANEL_EXTENSION); -+ if (component) { -+ bus_component_set_restart (component, restart); -+ } -+ if (component == NULL || -+ !bus_component_start (component, g_verbose)) { -+ g_printerr ("Can not execute default panel program\n"); -+ exit (-1); -+ } -+ } else if (g_strcmp0 (panel_extension, "disable") != 0 && -+ g_strcmp0 (panel_extension, "") != 0) { -+ if (!execute_cmdline (panel_extension)) -+ exit (-1); -+ } - } -+#endif - - /* execute ibus xim server */ - if (xim) { -diff --git a/bus/marshalers.list b/bus/marshalers.list -index c032cdaa..437c6fee 100644 ---- a/bus/marshalers.list -+++ b/bus/marshalers.list -@@ -12,4 +12,5 @@ VOID:STRING - VOID:STRING,INT - VOID:UINT,UINT - VOID:UINT,UINT,UINT -+VOID:VARIANT - VOID:VOID -diff --git a/bus/panelproxy.c b/bus/panelproxy.c -index 8381d7dc..c3908fcf 100644 ---- a/bus/panelproxy.c -+++ b/bus/panelproxy.c -@@ -2,8 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2014 Peng Huang -- * Copyright (C) 2017 Takao Fujiwara -- * Copyright (C) 2008-2014 Red Hat, Inc. -+ * Copyright (C) 2017-2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -51,6 +51,7 @@ enum { - PROPERTY_SHOW, - PROPERTY_HIDE, - COMMIT_TEXT, -+ PANEL_EXTENSION, - LAST_SIGNAL, - }; - -@@ -59,6 +60,7 @@ struct _BusPanelProxy { - - /* instance members */ - BusInputContext *focused_context; -+ PanelType panel_type; - }; - - struct _BusPanelProxyClass { -@@ -110,22 +112,39 @@ static void bus_panel_proxy_commit_text - G_DEFINE_TYPE(BusPanelProxy, bus_panel_proxy, IBUS_TYPE_PROXY) - - BusPanelProxy * --bus_panel_proxy_new (BusConnection *connection) -+bus_panel_proxy_new (BusConnection *connection, -+ PanelType panel_type) - { -+ const gchar *path = NULL; -+ GObject *obj; -+ BusPanelProxy *panel; -+ - g_assert (BUS_IS_CONNECTION (connection)); - -- GObject *obj; -+ switch (panel_type) { -+ case PANEL_TYPE_PANEL: -+ path = IBUS_PATH_PANEL; -+ break; -+ case PANEL_TYPE_EXTENSION: -+ path = IBUS_PATH_PANEL_EXTENSION; -+ break; -+ default: -+ g_return_val_if_reached (NULL); -+ } -+ - obj = g_initable_new (BUS_TYPE_PANEL_PROXY, - NULL, - NULL, -- "g-object-path", IBUS_PATH_PANEL, -+ "g-object-path", path, - "g-interface-name", IBUS_INTERFACE_PANEL, - "g-connection", bus_connection_get_dbus_connection (connection), - "g-default-timeout", g_gdbus_timeout, - "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL); - -- return BUS_PANEL_PROXY (obj); -+ panel = BUS_PANEL_PROXY (obj); -+ panel->panel_type = panel_type; -+ return panel; - } - - static void -@@ -231,6 +250,16 @@ bus_panel_proxy_class_init (BusPanelProxyClass *class) - bus_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - IBUS_TYPE_TEXT); -+ -+ panel_signals[PANEL_EXTENSION] = -+ g_signal_new (I_("panel-extension"), -+ G_TYPE_FROM_CLASS (class), -+ G_SIGNAL_RUN_LAST, -+ 0, -+ NULL, NULL, -+ bus_marshal_VOID__VARIANT, -+ G_TYPE_NONE, 1, -+ G_TYPE_VARIANT); - } - - static void -@@ -337,6 +366,15 @@ bus_panel_proxy_g_signal (GDBusProxy *proxy, - return; - } - -+ if (g_strcmp0 ("PanelExtension", signal_name) == 0) { -+ if (panel->panel_type != PANEL_TYPE_PANEL) { -+ g_warning ("Wrong signal"); -+ return; -+ } -+ g_signal_emit (panel, panel_signals[PANEL_EXTENSION], 0, parameters); -+ return; -+ } -+ - /* shound not be reached */ - g_return_if_reached (); - } -@@ -832,3 +870,10 @@ bus_panel_proxy_destroy_context (BusPanelProxy *panel, - - g_object_unref (context); - } -+ -+PanelType -+bus_panel_proxy_get_panel_type (BusPanelProxy *panel) -+{ -+ g_assert (BUS_IS_PANEL_PROXY (panel)); -+ return panel->panel_type; -+} -diff --git a/bus/panelproxy.h b/bus/panelproxy.h -index 5002f86d..b5a7af17 100644 ---- a/bus/panelproxy.h -+++ b/bus/panelproxy.h -@@ -2,7 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2014 Peng Huang -- * Copyright (C) 2008-2014 Red Hat, Inc. -+ * Copyright (C) 2017-2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -50,12 +51,25 @@ - - G_BEGIN_DECLS - -+typedef enum -+{ -+ PANEL_TYPE_NONE, -+ PANEL_TYPE_PANEL, -+ PANEL_TYPE_EXTENSION -+} PanelType; -+ - typedef struct _BusPanelProxy BusPanelProxy; - typedef struct _BusPanelProxyClass BusPanelProxyClass; - - GType bus_panel_proxy_get_type (void); --BusPanelProxy *bus_panel_proxy_new (BusConnection *connection); -+BusPanelProxy *bus_panel_proxy_new (BusConnection *connection, -+ PanelType panel_type); - -+gboolean bus_panel_proxy_send_signal (BusPanelProxy *panel, -+ const gchar *interface_name, -+ const gchar *signal_name, -+ GVariant *parameters, -+ GError **error); - /* functions that invoke D-Bus methods of the panel component. */ - void bus_panel_proxy_focus_in (BusPanelProxy *panel, - BusInputContext *context); -@@ -119,6 +133,8 @@ void bus_panel_proxy_set_content_type - (BusPanelProxy *panel, - guint purpose, - guint hints); -+PanelType bus_panel_proxy_get_panel_type -+ (BusPanelProxy *panel); - G_END_DECLS - #endif - -diff --git a/src/Makefile.am b/src/Makefile.am -index 1ba418d8..72ec05ab 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -3,7 +3,7 @@ - # ibus - The Input Bus - # - # Copyright (c) 2007-2015 Peng Huang --# Copyright (c) 2015-2017 Takao Fujiwara -+# Copyright (c) 2015-2018 Takao Fujiwara - # Copyright (c) 2007-2017 Red Hat, Inc. - # - # This library is free software; you can redistribute it and/or -@@ -103,6 +103,7 @@ ibus_sources = \ - ibustext.c \ - ibusunicode.c \ - ibusutil.c \ -+ ibusxevent.c \ - ibusxml.c \ - $(NULL) - libibus_1_0_la_SOURCES = \ -@@ -155,6 +156,7 @@ ibus_headers = \ - ibustypes.h \ - ibusunicode.h \ - ibusutil.h \ -+ ibusxevent.h \ - ibusxml.h \ - $(NULL) - ibusincludedir = $(includedir)/ibus-@IBUS_API_VERSION@ -diff --git a/src/ibus.h b/src/ibus.h -index 8011729f..b15dded9 100644 ---- a/src/ibus.h -+++ b/src/ibus.h -@@ -59,6 +59,7 @@ - #include - #include - #include -+#include - - #ifndef IBUS_DISABLE_DEPRECATED - #include -diff --git a/src/ibusmarshalers.list b/src/ibusmarshalers.list -index 918bc7f7..8d91937e 100644 ---- a/src/ibusmarshalers.list -+++ b/src/ibusmarshalers.list -@@ -24,4 +24,5 @@ VOID:STRING,STRING,STRING - VOID:UINT - VOID:UINT,POINTER - VOID:POINTER,UINT -+VOID:VARIANT - OBJECT:STRING -diff --git a/src/ibuspanelservice.c b/src/ibuspanelservice.c -index 33949fa1..f37b91c3 100644 ---- a/src/ibuspanelservice.c -+++ b/src/ibuspanelservice.c -@@ -25,6 +25,10 @@ - #include "ibusmarshalers.h" - #include "ibusinternal.h" - -+#define IBUS_PANEL_SERVICE_GET_PRIVATE(o) \ -+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_PANEL_SERVICE, \ -+ IBusPanelServicePrivate)) -+ - enum { - UPDATE_PREEDIT_TEXT, - UPDATE_AUXILIARY_TEXT, -@@ -52,6 +56,7 @@ enum { - STATE_CHANGED, - DESTROY_CONTEXT, - SET_CONTENT_TYPE, -+ PANEL_EXTENSION_RECEIVED, - LAST_SIGNAL, - }; - -@@ -146,6 +151,9 @@ static void ibus_panel_service_set_content_type - (IBusPanelService *panel, - guint purpose, - guint hints); -+static void ibus_panel_service_panel_extension_received -+ (IBusPanelService *panel, -+ GVariant *data); - - G_DEFINE_TYPE (IBusPanelService, ibus_panel_service, IBUS_TYPE_SERVICE) - -@@ -212,6 +220,9 @@ static const gchar introspection_xml[] = - " " - " " - " " -+ " " -+ " " -+ " " - /* Signals */ - " " - " " -@@ -235,6 +246,9 @@ static const gchar introspection_xml[] = - " " - " " - " " -+ " " -+ " " -+ " " - " " - ""; - -@@ -274,6 +288,8 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class) - class->update_preedit_text = ibus_panel_service_update_preedit_text; - class->update_property = ibus_panel_service_update_property; - class->set_content_type = ibus_panel_service_set_content_type; -+ class->panel_extension_received = -+ ibus_panel_service_panel_extension_received; - - class->cursor_down_lookup_table = ibus_panel_service_not_implemented; - class->cursor_up_lookup_table = ibus_panel_service_not_implemented; -@@ -891,6 +907,30 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class) - 2, - G_TYPE_UINT, - G_TYPE_UINT); -+ -+ /** -+ * IBusPanelService::panel-extension-received: -+ * @panel: An #IBusPanelService -+ * @data: A #GVariant -+ * -+ * Emitted when the client application get the ::panel-extension-received. -+ * Implement the member function -+ * IBusPanelServiceClass::panel_extension_received in extended class to -+ * receive this signal. -+ * -+ * Argument @user_data is ignored in this function. -+ * -+ */ -+ panel_signals[PANEL_EXTENSION_RECEIVED] = -+ g_signal_new (I_("panel-extension-received"), -+ G_TYPE_FROM_CLASS (gobject_class), -+ G_SIGNAL_RUN_LAST, -+ G_STRUCT_OFFSET (IBusPanelServiceClass, panel_extension_received), -+ NULL, NULL, -+ _ibus_marshal_VOID__VARIANT, -+ G_TYPE_NONE, -+ 1, -+ G_TYPE_VARIANT); - } - - static void -@@ -1088,6 +1128,24 @@ ibus_panel_service_service_method_call (IBusService *service, - return; - } - -+ if (g_strcmp0 (method_name, "PanelExtensionReceived") == 0) { -+ GVariant *variant = NULL; -+ g_variant_get (parameters, "(v)", &variant); -+ if (variant == NULL) { -+ g_dbus_method_invocation_return_error ( -+ invocation, -+ G_DBUS_ERROR, -+ G_DBUS_ERROR_FAILED, -+ "PanelExtensionReceived method gives NULL"); -+ return; -+ } -+ g_signal_emit (panel, panel_signals[PANEL_EXTENSION_RECEIVED], 0, -+ variant); -+ g_variant_unref (variant); -+ g_dbus_method_invocation_return_value (invocation, NULL); -+ return; -+ } -+ - const static struct { - const gchar *name; - const gint signal_id; -@@ -1259,6 +1317,13 @@ ibus_panel_service_set_content_type (IBusPanelService *panel, - ibus_panel_service_not_implemented(panel); - } - -+static void -+ibus_panel_service_panel_extension_received (IBusPanelService *panel, -+ GVariant *data) -+{ -+ ibus_panel_service_not_implemented(panel); -+} -+ - IBusPanelService * - ibus_panel_service_new (GDBusConnection *connection) - { -@@ -1347,6 +1412,21 @@ ibus_panel_service_commit_text (IBusPanelService *panel, - } - } - -+void -+ibus_panel_service_panel_extension (IBusPanelService *panel, -+ GVariant *variant) -+{ -+ g_return_if_fail (IBUS_IS_PANEL_SERVICE (panel)); -+ g_return_if_fail (variant); -+ -+ ibus_service_emit_signal ((IBusService *) panel, -+ NULL, -+ IBUS_INTERFACE_PANEL, -+ "PanelExtension", -+ g_variant_new ("(v)", variant), -+ NULL); -+} -+ - #define DEFINE_FUNC(name, Name) \ - void \ - ibus_panel_service_##name (IBusPanelService *panel) \ -@@ -1364,4 +1444,3 @@ DEFINE_FUNC (cursor_up, CursorUp) - DEFINE_FUNC (page_down, PageDown) - DEFINE_FUNC (page_up, PageUp) - #undef DEFINE_FUNC -- -diff --git a/src/ibuspanelservice.h b/src/ibuspanelservice.h -index a5b13c73..60ef842b 100644 ---- a/src/ibuspanelservice.h -+++ b/src/ibuspanelservice.h -@@ -2,7 +2,7 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (c) 2009-2014 Google Inc. All rights reserved. -- * Copyright (c) 2017 Takao Fujiwara -+ * Copyright (c) 2017-2018 Takao Fujiwara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -128,6 +128,9 @@ struct _IBusPanelServiceClass { - gint y, - gint w, - gint h); -+ void (* panel_extension_received) -+ (IBusPanelService *panel, -+ GVariant *data); - - /*< private >*/ - /* padding */ -@@ -242,5 +245,15 @@ void ibus_panel_service_property_hide (IBusPanelService *panel, - void ibus_panel_service_commit_text (IBusPanelService *panel, - IBusText *text); - -+/** -+ * ibus_panel_service_panel_extension: -+ * @panel: An #IBusPanelService -+ * @data: (transfer full): A #GVariant data which is sent to a panel extension. -+ * -+ * Notify that a data is sent -+ * by sending a "PanelExtension" message to IBus panel extension service. -+ */ -+void ibus_panel_service_panel_extension (IBusPanelService *panel, -+ GVariant *data); - G_END_DECLS - #endif -diff --git a/src/ibusserializable.c b/src/ibusserializable.c -index d7f867f4..a377b613 100644 ---- a/src/ibusserializable.c -+++ b/src/ibusserializable.c -@@ -2,7 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2010 Peng Huang -- * Copyright (C) 2008-2010 Red Hat, Inc. -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -251,7 +252,7 @@ ibus_serializable_copy (IBusSerializable *object) - } - - GVariant * --ibus_serializable_serialize (IBusSerializable *object) -+ibus_serializable_serialize_object (IBusSerializable *object) - { - g_return_val_if_fail (IBUS_IS_SERIALIZABLE (object), FALSE); - gboolean retval; -@@ -267,7 +268,7 @@ ibus_serializable_serialize (IBusSerializable *object) - } - - IBusSerializable * --ibus_serializable_deserialize (GVariant *variant) -+ibus_serializable_deserialize_object (GVariant *variant) - { - g_return_val_if_fail (variant != NULL, NULL); - -diff --git a/src/ibusserializable.h b/src/ibusserializable.h -index 4327eaee..102de1bd 100644 ---- a/src/ibusserializable.h -+++ b/src/ibusserializable.h -@@ -2,7 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2008-2013 Red Hat, Inc. -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -248,10 +249,10 @@ void ibus_serializable_remove_qattachment - * - * See also: IBusSerializableCopyFunc(). - */ --IBusSerializable *ibus_serializable_copy (IBusSerializable *serializable); -+IBusSerializable *ibus_serializable_copy (IBusSerializable *serializable); - - /** -- * ibus_serializable_serialize: -+ * ibus_serializable_serialize_object: - * @serializable: An #IBusSerializable. - * - * Serialize an #IBusSerializable to a #GVariant. -@@ -261,10 +262,11 @@ IBusSerializable *ibus_serializable_copy (IBusSerializable *ser - * - * See also: IBusSerializableCopyFunc(). - */ --GVariant *ibus_serializable_serialize (IBusSerializable *serializable); -+GVariant *ibus_serializable_serialize_object -+ (IBusSerializable *serializable); - - /** -- * ibus_serializable_deserialize: -+ * ibus_serializable_deserialize_object: - * @variant: A #GVariant. - * - * Deserialize a #GVariant to an #IBusSerializable/ -@@ -274,7 +276,11 @@ GVariant *ibus_serializable_serialize (IBusSerializable *ser - * - * See also: IBusSerializableCopyFunc(). - */ --IBusSerializable *ibus_serializable_deserialize (GVariant *variant); -+IBusSerializable *ibus_serializable_deserialize_object -+ (GVariant *variant); -+ -+#define ibus_serializable_serialize ibus_serializable_serialize_object -+#define ibus_serializable_deserialize ibus_serializable_deserialize_object - - G_END_DECLS - #endif -diff --git a/src/ibusshare.c b/src/ibusshare.c -index b793a962..d7724a6b 100644 ---- a/src/ibusshare.c -+++ b/src/ibusshare.c -@@ -2,7 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2010 Peng Huang -- * Copyright (C) 2008-2010 Red Hat, Inc. -+ * Copyright (C) 2015-2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -287,6 +288,7 @@ ibus_init (void) - IBUS_TYPE_ENGINE_DESC; - IBUS_TYPE_OBSERVED_PATH; - IBUS_TYPE_REGISTRY; -+ IBUS_TYPE_X_EVENT; - } - - static GMainLoop *main_loop = NULL; -diff --git a/src/ibusshare.h b/src/ibusshare.h -index f3e2011e..757d915b 100644 ---- a/src/ibusshare.h -+++ b/src/ibusshare.h -@@ -2,7 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2008-2013 Red Hat, Inc. -+ * Copyright (C) 2015-2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -65,6 +66,13 @@ - */ - #define IBUS_SERVICE_PANEL "org.freedesktop.IBus.Panel" - -+/** -+ * IBUS_SERVICE_PANEL_EXTENSION: -+ * -+ * Address of IBus panel extension service. -+ */ -+#define IBUS_SERVICE_PANEL_EXTENSION "org.freedesktop.IBus.Panel.Extension" -+ - /** - * IBUS_SERVICE_CONFIG: - * -@@ -100,6 +108,13 @@ - */ - #define IBUS_PATH_PANEL "/org/freedesktop/IBus/Panel" - -+/** -+ * IBUS_PATH_PANEL_EXTENSION: -+ * -+ * D-Bus path for IBus panel. -+ */ -+#define IBUS_PATH_PANEL_EXTENSION "/org/freedesktop/IBus/Panel/Extension" -+ - /** - * IBUS_PATH_CONFIG: - * -diff --git a/src/ibusxevent.c b/src/ibusxevent.c -new file mode 100644 -index 00000000..dea80272 ---- /dev/null -+++ b/src/ibusxevent.c -@@ -0,0 +1,1004 @@ -+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -+/* vim:set et sts=4: */ -+/* ibus - The Input Bus -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2018 Red Hat, Inc. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -+ * USA -+ */ -+#include "ibusinternal.h" -+#include "ibusxevent.h" -+ -+#define IBUS_X_EVENT_VERSION 1 -+#define IBUS_X_EVENT_GET_PRIVATE(o) \ -+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_X_EVENT, IBusXEventPrivate)) -+ -+enum { -+ PROP_0, -+ PROP_VERSION, -+ PROP_EVENT_TYPE, -+ PROP_WINDOW, -+ PROP_SEND_EVENT, -+ PROP_SERIAL, -+ PROP_TIME, -+ PROP_STATE, -+ PROP_KEYVAL, -+ PROP_LENGTH, -+ PROP_STRING, -+ PROP_HARDWARE_KEYCODE, -+ PROP_GROUP, -+ PROP_IS_MODIFIER, -+ PROP_ROOT, -+ PROP_SUBWINDOW, -+ PROP_X, -+ PROP_Y, -+ PROP_X_ROOT, -+ PROP_Y_ROOT, -+ PROP_SAME_SCREEN, -+ PROP_PURPOSE -+}; -+ -+ -+struct _IBusXEventPrivate { -+ guint version; -+ guint32 time; -+ guint state; -+ guint keyval; -+ gint length; -+ gchar *string; -+ guint16 hardware_keycode; -+ guint8 group; -+ gboolean is_modifier; -+ guint root; -+ guint subwindow; -+ gint x; -+ gint y; -+ gint x_root; -+ gint y_root; -+ gboolean same_screen; -+ gchar *purpose; -+}; -+ -+/* functions prototype */ -+static void ibus_x_event_destroy (IBusXEvent *event); -+static void ibus_x_event_set_property (IBusXEvent *event, -+ guint prop_id, -+ const GValue *value, -+ GParamSpec *pspec); -+static void ibus_x_event_get_property (IBusXEvent *event, -+ guint prop_id, -+ GValue *value, -+ GParamSpec *pspec); -+static gboolean ibus_x_event_serialize (IBusXEvent *event, -+ GVariantBuilder *builder); -+static gint ibus_x_event_deserialize (IBusXEvent *event, -+ GVariant *variant); -+static gboolean ibus_x_event_copy (IBusXEvent *dest, -+ const IBusXEvent *src); -+ -+G_DEFINE_TYPE (IBusXEvent, ibus_x_event, IBUS_TYPE_SERIALIZABLE) -+ -+static void -+ibus_x_event_class_init (IBusXEventClass *class) -+{ -+ GObjectClass *gobject_class = G_OBJECT_CLASS (class); -+ IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class); -+ IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class); -+ -+ gobject_class->set_property = -+ (GObjectSetPropertyFunc) ibus_x_event_set_property; -+ gobject_class->get_property = -+ (GObjectGetPropertyFunc) ibus_x_event_get_property; -+ -+ object_class->destroy = (IBusObjectDestroyFunc) ibus_x_event_destroy; -+ -+ serializable_class->serialize = -+ (IBusSerializableSerializeFunc) ibus_x_event_serialize; -+ serializable_class->deserialize = -+ (IBusSerializableDeserializeFunc) ibus_x_event_deserialize; -+ serializable_class->copy = -+ (IBusSerializableCopyFunc) ibus_x_event_copy; -+ -+ /* install properties */ -+ /** -+ * IBusXEvent:version: -+ * -+ * Version of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_VERSION, -+ g_param_spec_uint ("version", -+ "version", -+ "version", -+ 0, -+ G_MAXUINT32, -+ IBUS_X_EVENT_VERSION, -+ G_PARAM_READABLE)); -+ -+ /** -+ * IBusXEvent:event-type: -+ * -+ * IBusXEventType of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_EVENT_TYPE, -+ g_param_spec_int ("event-type", -+ "event type", -+ "event type", -+ -1, -+ G_MAXINT32, -+ -1, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:window: -+ * -+ * window of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_WINDOW, -+ g_param_spec_uint ("window", -+ "window", -+ "window", -+ 0, -+ G_MAXUINT32, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:send-event: -+ * -+ * send_event of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_SEND_EVENT, -+ g_param_spec_int ("send-event", -+ "send event", -+ "send event", -+ 0, -+ G_MAXINT8, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:serial: -+ * -+ * serial of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_SERIAL, -+ g_param_spec_ulong ("serial", -+ "serial", -+ "serial", -+ 0, -+ G_MAXUINT64, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:time: -+ * -+ * time of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_TIME, -+ g_param_spec_uint ("time", -+ "time", -+ "time", -+ 0, -+ G_MAXUINT32, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:state: -+ * -+ * state of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_STATE, -+ g_param_spec_uint ("state", -+ "state", -+ "state", -+ 0, -+ G_MAXUINT32, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:keyval: -+ * -+ * keyval of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_KEYVAL, -+ g_param_spec_uint ("keyval", -+ "keyval", -+ "keyval", -+ 0, -+ G_MAXUINT32, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:length: -+ * -+ * keyval of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_LENGTH, -+ g_param_spec_int ("length", -+ "length", -+ "length", -+ -1, -+ G_MAXINT32, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:string: -+ * -+ * string of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_STRING, -+ g_param_spec_string ("string", -+ "string", -+ "string", -+ "", -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:hardware-keycode: -+ * -+ * hardware keycode of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_HARDWARE_KEYCODE, -+ g_param_spec_uint ("hardware-keycode", -+ "hardware keycode", -+ "hardware keycode", -+ 0, -+ G_MAXUINT16, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:group: -+ * -+ * group of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_GROUP, -+ g_param_spec_uint ("group", -+ "group", -+ "group", -+ 0, -+ G_MAXUINT8, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:is-modifier: -+ * -+ * is_modifier of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_IS_MODIFIER, -+ g_param_spec_boolean ("is-modifier", -+ "is modifier", -+ "is modifier", -+ FALSE, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:root: -+ * -+ * root window of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_ROOT, -+ g_param_spec_uint ("root", -+ "root", -+ "root", -+ 0, -+ G_MAXUINT32, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:subwindow: -+ * -+ * subwindow of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_SUBWINDOW, -+ g_param_spec_uint ("subwindow", -+ "subwindow", -+ "subwindow", -+ 0, -+ G_MAXUINT32, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:x: -+ * -+ * x of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_X, -+ g_param_spec_int ("x", -+ "x", -+ "x", -+ G_MININT32, -+ G_MAXINT32, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:y: -+ * -+ * x of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_Y, -+ g_param_spec_int ("y", -+ "y", -+ "y", -+ G_MININT32, -+ G_MAXINT32, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:x-root: -+ * -+ * root-x of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_X_ROOT, -+ g_param_spec_int ("x-root", -+ "x root", -+ "x root", -+ G_MININT32, -+ G_MAXINT32, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:y-root: -+ * -+ * root-y of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_Y_ROOT, -+ g_param_spec_int ("y-root", -+ "y root", -+ "y root", -+ G_MININT32, -+ G_MAXINT32, -+ 0, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:same-screen: -+ * -+ * same_screen of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_SAME_SCREEN, -+ g_param_spec_boolean ("same-screen", -+ "same screen", -+ "same screen", -+ TRUE, -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ /** -+ * IBusXEvent:purpose: -+ * -+ * purpose of this IBusXEvent. -+ */ -+ g_object_class_install_property (gobject_class, -+ PROP_PURPOSE, -+ g_param_spec_string ("purpose", -+ "purpose", -+ "purpose", -+ "", -+ G_PARAM_READWRITE | -+ G_PARAM_CONSTRUCT_ONLY)); -+ -+ g_type_class_add_private (class, sizeof (IBusXEventPrivate)); -+} -+ -+static void -+ibus_x_event_init (IBusXEvent *event) -+{ -+ event->priv = IBUS_X_EVENT_GET_PRIVATE (event); -+ event->priv->version = IBUS_X_EVENT_VERSION; -+} -+ -+static void -+ibus_x_event_destroy (IBusXEvent *event) -+{ -+ g_clear_pointer (&event->priv->string, g_free); -+ -+ IBUS_OBJECT_CLASS(ibus_x_event_parent_class)->destroy (IBUS_OBJECT (event)); -+} -+ -+static void -+ibus_x_event_set_property (IBusXEvent *event, -+ guint prop_id, -+ const GValue *value, -+ GParamSpec *pspec) -+{ -+ IBusXEventPrivate *priv = event->priv; -+ -+ switch (prop_id) { -+ case PROP_EVENT_TYPE: -+ event->event_type = g_value_get_int (value); -+ break; -+ case PROP_WINDOW: -+ event->window = g_value_get_uint (value); -+ break; -+ case PROP_SEND_EVENT: -+ event->send_event = g_value_get_int (value); -+ break; -+ case PROP_SERIAL: -+ event->serial = g_value_get_ulong (value); -+ break; -+ case PROP_TIME: -+ priv->time = g_value_get_uint (value); -+ break; -+ case PROP_STATE: -+ priv->state = g_value_get_uint (value); -+ break; -+ case PROP_KEYVAL: -+ priv->keyval = g_value_get_uint (value); -+ break; -+ case PROP_LENGTH: -+ priv->length = g_value_get_int (value); -+ break; -+ case PROP_STRING: -+ g_free (priv->string); -+ priv->string = g_value_dup_string (value); -+ break; -+ case PROP_HARDWARE_KEYCODE: -+ priv->hardware_keycode = g_value_get_uint (value); -+ break; -+ case PROP_GROUP: -+ priv->group = g_value_get_uint (value); -+ break; -+ case PROP_IS_MODIFIER: -+ priv->is_modifier = g_value_get_boolean (value); -+ break; -+ case PROP_ROOT: -+ priv->root = g_value_get_uint (value); -+ break; -+ case PROP_SUBWINDOW: -+ priv->subwindow = g_value_get_uint (value); -+ break; -+ case PROP_X: -+ priv->x = g_value_get_int (value); -+ break; -+ case PROP_Y: -+ priv->y = g_value_get_int (value); -+ break; -+ case PROP_X_ROOT: -+ priv->x_root = g_value_get_int (value); -+ break; -+ case PROP_Y_ROOT: -+ priv->y_root = g_value_get_int (value); -+ break; -+ case PROP_SAME_SCREEN: -+ priv->same_screen = g_value_get_boolean (value); -+ break; -+ case PROP_PURPOSE: -+ g_free (priv->purpose); -+ priv->purpose = g_value_dup_string (value); -+ break; -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (event, prop_id, pspec); -+ } -+} -+ -+static void -+ibus_x_event_get_property (IBusXEvent *event, -+ guint prop_id, -+ GValue *value, -+ GParamSpec *pspec) -+{ -+ IBusXEventPrivate *priv = event->priv; -+ switch (prop_id) { -+ case PROP_VERSION: -+ g_value_set_uint (value, priv->version); -+ break; -+ case PROP_EVENT_TYPE: -+ g_value_set_int (value, event->event_type); -+ break; -+ case PROP_WINDOW: -+ g_value_set_uint (value, event->window); -+ break; -+ case PROP_SEND_EVENT: -+ g_value_set_int (value, event->send_event); -+ break; -+ case PROP_SERIAL: -+ g_value_set_ulong (value, event->serial); -+ break; -+ case PROP_TIME: -+ g_value_set_uint (value, priv->time); -+ break; -+ case PROP_STATE: -+ g_value_set_uint (value, priv->state); -+ break; -+ case PROP_KEYVAL: -+ g_value_set_uint (value, priv->keyval); -+ break; -+ case PROP_LENGTH: -+ g_value_set_int (value, priv->length); -+ break; -+ case PROP_STRING: -+ g_value_set_string (value, priv->string); -+ break; -+ case PROP_HARDWARE_KEYCODE: -+ g_value_set_uint (value, priv->hardware_keycode); -+ break; -+ case PROP_GROUP: -+ g_value_set_uint (value, priv->group); -+ break; -+ case PROP_IS_MODIFIER: -+ g_value_set_boolean (value, priv->is_modifier); -+ break; -+ case PROP_ROOT: -+ g_value_set_uint (value, priv->root); -+ break; -+ case PROP_SUBWINDOW: -+ g_value_set_uint (value, priv->subwindow); -+ break; -+ case PROP_X: -+ g_value_set_int (value, priv->x); -+ break; -+ case PROP_Y: -+ g_value_set_int (value, priv->y); -+ break; -+ case PROP_X_ROOT: -+ g_value_set_int (value, priv->x_root); -+ break; -+ case PROP_Y_ROOT: -+ g_value_set_int (value, priv->y_root); -+ break; -+ case PROP_SAME_SCREEN: -+ g_value_set_boolean (value, priv->same_screen); -+ break; -+ case PROP_PURPOSE: -+ g_value_set_string (value, priv->purpose); -+ break; -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (event, prop_id, pspec); -+ } -+} -+ -+static gboolean -+ibus_x_event_serialize (IBusXEvent *event, -+ GVariantBuilder *builder) -+{ -+ gboolean retval; -+ IBusXEventPrivate *priv; -+ -+ retval = IBUS_SERIALIZABLE_CLASS (ibus_x_event_parent_class)-> -+ serialize ((IBusSerializable *)event, builder); -+ g_return_val_if_fail (retval, FALSE); -+ /* End dict iter */ -+ -+ priv = event->priv; -+#define NOTNULL(s) ((s) != NULL ? (s) : "") -+ /* If you will add a new property, you can append it at the end and -+ * you should not change the serialized order of name, longname, -+ * description, ... because the order is also used in other applications -+ * likes ibus-qt. */ -+ g_variant_builder_add (builder, "u", priv->version); -+ g_variant_builder_add (builder, "u", event->event_type); -+ g_variant_builder_add (builder, "u", event->window); -+ g_variant_builder_add (builder, "i", event->send_event); -+ g_variant_builder_add (builder, "t", event->serial); -+ g_variant_builder_add (builder, "u", priv->time); -+ g_variant_builder_add (builder, "u", priv->state); -+ g_variant_builder_add (builder, "u", priv->keyval); -+ g_variant_builder_add (builder, "i", priv->length); -+ g_variant_builder_add (builder, "s", NOTNULL (priv->string)); -+ g_variant_builder_add (builder, "u", priv->hardware_keycode); -+ g_variant_builder_add (builder, "u", priv->group); -+ g_variant_builder_add (builder, "b", priv->is_modifier); -+ g_variant_builder_add (builder, "u", priv->root); -+ g_variant_builder_add (builder, "u", priv->subwindow); -+ g_variant_builder_add (builder, "i", priv->x); -+ g_variant_builder_add (builder, "i", priv->y); -+ g_variant_builder_add (builder, "i", priv->x_root); -+ g_variant_builder_add (builder, "i", priv->y_root); -+ g_variant_builder_add (builder, "b", priv->same_screen); -+ g_variant_builder_add (builder, "s", NOTNULL (priv->purpose)); -+#undef NOTNULL -+ -+ return TRUE; -+} -+ -+static gint -+ibus_x_event_deserialize (IBusXEvent *event, -+ GVariant *variant) -+{ -+ gint retval; -+ IBusXEventPrivate *priv; -+ -+ retval = IBUS_SERIALIZABLE_CLASS (ibus_x_event_parent_class)-> -+ deserialize ((IBusSerializable *)event, variant); -+ g_return_val_if_fail (retval, 0); -+ -+ priv = event->priv; -+ /* If you will add a new property, you can append it at the end and -+ * you should not change the serialized order of name, longname, -+ * description, ... because the order is also used in other applications -+ * likes ibus-qt. */ -+ g_variant_get_child (variant, retval++, "u", &priv->version); -+ g_variant_get_child (variant, retval++, "u", &event->event_type); -+ g_variant_get_child (variant, retval++, "u", &event->window); -+ g_variant_get_child (variant, retval++, "i", &event->send_event); -+ g_variant_get_child (variant, retval++, "t", &event->serial); -+ g_variant_get_child (variant, retval++, "u", &priv->time); -+ g_variant_get_child (variant, retval++, "u", &priv->state); -+ g_variant_get_child (variant, retval++, "u", &priv->keyval); -+ g_variant_get_child (variant, retval++, "i", &priv->length); -+ ibus_g_variant_get_child_string (variant, retval++, -+ &priv->string); -+ g_variant_get_child (variant, retval++, "u", &priv->hardware_keycode); -+ g_variant_get_child (variant, retval++, "u", &priv->group); -+ g_variant_get_child (variant, retval++, "b", &priv->is_modifier); -+ g_variant_get_child (variant, retval++, "u", &priv->root); -+ g_variant_get_child (variant, retval++, "u", &priv->subwindow); -+ g_variant_get_child (variant, retval++, "i", &priv->x); -+ g_variant_get_child (variant, retval++, "i", &priv->y); -+ g_variant_get_child (variant, retval++, "i", &priv->x_root); -+ g_variant_get_child (variant, retval++, "i", &priv->y_root); -+ g_variant_get_child (variant, retval++, "b", &priv->same_screen); -+ ibus_g_variant_get_child_string (variant, retval++, -+ &priv->purpose); -+ -+ return retval; -+} -+ -+static gboolean -+ibus_x_event_copy (IBusXEvent *dest, -+ const IBusXEvent *src) -+{ -+ gboolean retval; -+ IBusXEventPrivate *dest_priv = dest->priv; -+ IBusXEventPrivate *src_priv = src->priv; -+ -+ retval = IBUS_SERIALIZABLE_CLASS (ibus_x_event_parent_class)-> -+ copy ((IBusSerializable *)dest, (IBusSerializable *)src); -+ g_return_val_if_fail (retval, FALSE); -+ -+ dest_priv->version = src_priv->version; -+ dest->event_type = src->event_type; -+ dest->window = src->window; -+ dest->send_event = src->send_event; -+ dest->serial = src->serial; -+ dest_priv->time = src_priv->time; -+ dest_priv->state = src_priv->state; -+ dest_priv->keyval = src_priv->keyval; -+ dest_priv->length = src_priv->length; -+ dest_priv->string = g_strdup (src_priv->string); -+ dest_priv->hardware_keycode = src_priv->hardware_keycode; -+ dest_priv->group = src_priv->group; -+ dest_priv->is_modifier = src_priv->is_modifier; -+ dest_priv->root = src_priv->root; -+ dest_priv->subwindow = src_priv->subwindow; -+ dest_priv->x = src_priv->x; -+ dest_priv->y = src_priv->y; -+ dest_priv->x_root = src_priv->x_root; -+ dest_priv->y_root = src_priv->y_root; -+ dest_priv->same_screen = src_priv->same_screen; -+ dest_priv->purpose = g_strdup (src_priv->purpose); -+ -+ return TRUE; -+} -+ -+IBusXEvent * -+ibus_x_event_new (const gchar *first_property_name, -+ ...) -+{ -+ va_list var_args; -+ IBusXEvent *event; -+ -+ va_start (var_args, first_property_name); -+ event = (IBusXEvent *) g_object_new_valist (IBUS_TYPE_X_EVENT, -+ first_property_name, -+ var_args); -+ va_end (var_args); -+ g_assert (event->priv->version != 0); -+ g_assert (event->event_type != IBUS_X_EVENT_NOTHING); -+ return event; -+} -+ -+guint -+ibus_x_event_get_version (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ return event->priv->version; -+} -+ -+IBusXEventType -+ibus_x_event_get_event_type (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ return event->event_type; -+} -+ -+guint32 -+ibus_x_event_get_window (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ return event->window; -+} -+ -+gint8 -+ibus_x_event_get_send_event (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), -1); -+ return event->send_event; -+} -+ -+gulong -+ibus_x_event_get_serial (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ return event->serial; -+} -+ -+guint32 -+ibus_x_event_get_time (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (0); -+ } -+ return event->priv->time; -+} -+ -+guint -+ibus_x_event_get_state (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (0); -+ } -+ return event->priv->state; -+} -+ -+guint -+ibus_x_event_get_keyval (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (0); -+ } -+ return event->priv->keyval; -+} -+ -+gint -+ibus_x_event_get_length (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), -1); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (-1); -+ } -+ return event->priv->length; -+} -+ -+const gchar * -+ibus_x_event_get_string (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), ""); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (""); -+ } -+ return event->priv->string; -+} -+ -+guint16 -+ibus_x_event_get_hardware_keycode (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (0); -+ } -+ return event->priv->hardware_keycode; -+} -+ -+guint8 -+ibus_x_event_get_group (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (0); -+ } -+ return event->priv->group; -+} -+ -+gboolean -+ibus_x_event_get_is_modifier (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (0); -+ } -+ return event->priv->is_modifier; -+} -+ -+guint32 -+ibus_x_event_get_root (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (0); -+ } -+ return event->priv->root; -+} -+ -+guint32 -+ibus_x_event_get_subwindow (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (0); -+ } -+ return event->priv->subwindow; -+} -+ -+gint -+ibus_x_event_get_x (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (0); -+ } -+ return event->priv->x; -+} -+ -+gint -+ibus_x_event_get_y (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (0); -+ } -+ return event->priv->y; -+} -+ -+gint -+ibus_x_event_get_x_root (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (0); -+ } -+ return event->priv->x_root; -+} -+ -+gint -+ibus_x_event_get_y_root (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), 0); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (0); -+ } -+ return event->priv->y_root; -+} -+ -+gboolean -+ibus_x_event_get_same_screen (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), TRUE); -+ switch (event->event_type) { -+ case IBUS_X_EVENT_KEY_PRESS: -+ case IBUS_X_EVENT_KEY_RELEASE: -+ break; -+ default: -+ g_return_val_if_reached (TRUE); -+ } -+ return event->priv->same_screen; -+} -+ -+const gchar * -+ibus_x_event_get_purpose (IBusXEvent *event) -+{ -+ g_return_val_if_fail (IBUS_IS_X_EVENT (event), ""); -+ return event->priv->purpose; -+} -diff --git a/src/ibusxevent.h b/src/ibusxevent.h -new file mode 100644 -index 00000000..f35f14e4 ---- /dev/null -+++ b/src/ibusxevent.h -@@ -0,0 +1,294 @@ -+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ -+/* vim:set et sts=4: */ -+/* ibus - The Input Bus -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2018 Red Hat, Inc. -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -+ * USA -+ */ -+ -+#if !defined (__IBUS_H_INSIDE__) && !defined (IBUS_COMPILATION) -+#error "Only can be included directly" -+#endif -+ -+#ifndef __IBUS_X_EVENT_H_ -+#define __IBUS_X_EVENT_H_ -+ -+/** -+ * SECTION: ibusxevent -+ * @short_description: XEvent wrapper object -+ * @title: IBusXEvent -+ * @stability: Unstable -+ * -+ * An IBusXEvent provides a wrapper of XEvent. -+ * -+ * see_also: #IBusComponent, #IBusEngineDesc -+ */ -+ -+#include "ibusserializable.h" -+ -+/* -+ * Type macros. -+ */ -+ -+/* define GOBJECT macros */ -+#define IBUS_TYPE_X_EVENT \ -+ (ibus_x_event_get_type ()) -+#define IBUS_X_EVENT(obj) \ -+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), IBUS_TYPE_X_EVENT, IBusXEvent)) -+#define IBUS_X_EVENT_CLASS(klass) \ -+ (G_TYPE_CHECK_CLASS_CAST ((klass), IBUS_TYPE_X_EVENT, IBusXEventClass)) -+#define IBUS_IS_X_EVENT(obj) \ -+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IBUS_TYPE_X_EVENT)) -+#define IBUS_IS_X_EVENT_CLASS(klass) \ -+ (G_TYPE_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_X_EVENT)) -+#define IBUS_X_EVENT_GET_CLASS(obj) \ -+ (G_TYPE_INSTANCE_GET_CLASS ((obj), IBUS_TYPE_X_EVENT, IBusXEventClass)) -+ -+G_BEGIN_DECLS -+ -+typedef struct _IBusXEvent IBusXEvent; -+typedef struct _IBusXEventClass IBusXEventClass; -+typedef struct _IBusXEventPrivate IBusXEventPrivate; -+ -+typedef enum { -+ IBUS_X_EVENT_NOTHING = -1, -+ IBUS_X_EVENT_KEY_PRESS = 0, -+ IBUS_X_EVENT_KEY_RELEASE = 1, -+ IBUS_X_EVENT_OTHER = 2, -+ IBUS_X_EVENT_EVENT_LAST /* helper variable for decls */ -+} IBusXEventType; -+ -+/** -+ * IBusXEvent: -+ * @type: event type -+ * -+ * IBusEngine properties. -+ */ -+struct _IBusXEvent { -+ /*< private >*/ -+ IBusSerializable parent; -+ IBusXEventPrivate *priv; -+ -+ /* instance members */ -+ /*< public >*/ -+ IBusXEventType event_type; -+ guint window; -+ gint8 send_event; -+ gulong serial; -+}; -+ -+struct _IBusXEventClass { -+ /*< private >*/ -+ IBusSerializableClass parent; -+ -+ /* class members */ -+ /*< public >*/ -+ -+ /*< private >*/ -+ /* padding */ -+ gpointer pdummy[10]; -+}; -+ -+GType ibus_x_event_get_type (void); -+ -+/** -+ * ibus_x_event_new: -+ * @first_property_name: Name of the first property. -+ * @...: the NULL-terminated arguments of the properties and values. -+ * -+ * Create a new #IBusXEvent. -+ * -+ * Returns: A newly allocated #IBusXEvent. E.g. -+ * ibus_x_event_new ("event-type", IBUS_X_EVENT_KEY_PRESS, NULL); -+ */ -+IBusXEvent * ibus_x_event_new (const gchar -+ *first_property_name, -+ ...); -+ -+/** -+ * ibus_x_event_get_version: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: Version of #IBusXEvent -+ */ -+guint ibus_x_event_get_version (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_event_type: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: IBusXEventType of #IBusXEvent -+ */ -+IBusXEventType ibus_x_event_get_event_type (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_window: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: XID of #IBusXEvent -+ */ -+guint32 ibus_x_event_get_window (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_send_event: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: send_event of #IBusXEvent -+ */ -+gint8 ibus_x_event_get_send_event (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_serial: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: serial of #IBusXEvent -+ */ -+gulong ibus_x_event_get_serial (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_time: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: time of #IBusXEvent -+ */ -+guint32 ibus_x_event_get_time (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_state: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: state of #IBusXEvent -+ */ -+guint ibus_x_event_get_state (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_keyval: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: keyval of #IBusXEvent -+ */ -+guint ibus_x_event_get_keyval (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_length: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: length of #IBusXEvent -+ */ -+gint ibus_x_event_get_length (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_string: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: string of #IBusXEvent -+ */ -+const gchar * ibus_x_event_get_string (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_hardware_keycode: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: hardware keycode of #IBusXEvent -+ */ -+guint16 ibus_x_event_get_hardware_keycode -+ (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_group: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: group of #IBusXEvent -+ */ -+guint8 ibus_x_event_get_group (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_is_modifier: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: is_modifier of #IBusXEvent -+ */ -+gboolean ibus_x_event_get_is_modifier -+ (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_subwindow: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: subwindow of #IBusXEvent -+ */ -+guint32 ibus_x_event_get_subwindow (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_root: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: root window of #IBusXEvent -+ */ -+guint32 ibus_x_event_get_root (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_x: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: x of #IBusXEvent -+ */ -+gint ibus_x_event_get_x (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_y: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: y of #IBusXEvent -+ */ -+gint ibus_x_event_get_y (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_x_root: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: x-root of #IBusXEvent -+ */ -+gint ibus_x_event_get_x_root (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_y_root: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: y-root of #IBusXEvent -+ */ -+gint ibus_x_event_get_y_root (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_same_screen: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: same_screen of #IBusXEvent -+ */ -+gboolean ibus_x_event_get_same_screen -+ (IBusXEvent *event); -+ -+/** -+ * ibus_x_event_get_purpose: -+ * @event: An #IBusXEvent. -+ * -+ * Returns: purpose of #IBusXEvent -+ */ -+const gchar * ibus_x_event_get_purpose (IBusXEvent *event); -+ -+G_END_DECLS -+#endif -diff --git a/src/tests/runtest b/src/tests/runtest -index 91c4e95f..0e43fee5 100755 ---- a/src/tests/runtest -+++ b/src/tests/runtest -@@ -106,6 +106,7 @@ test -d $tstdir || mkdir $tstdir - --daemonize \ - --cache=none \ - --panel=disable \ -+ --panel-extension=disable \ - --config=default \ - --verbose; - -diff --git a/ui/gtk3/Makefile.am b/ui/gtk3/Makefile.am -index 786b80e6..0a8f4200 100644 ---- a/ui/gtk3/Makefile.am -+++ b/ui/gtk3/Makefile.am -@@ -3,8 +3,8 @@ - # ibus - The Input Bus - # - # Copyright (c) 2007-2015 Peng Huang --# Copyright (c) 2015-2017 Takao Fujwiara --# Copyright (c) 2007-2017 Red Hat, Inc. -+# Copyright (c) 2015-2018 Takao Fujwiara -+# Copyright (c) 2007-2018 Red Hat, Inc. - # - # This library is free software; you can redistribute it and/or - # modify it under the terms of the GNU Lesser General Public -@@ -30,7 +30,7 @@ component_DATA = \ - $(NULL) - componentdir = $(pkgdatadir)/component - --gtkpanel.xml: gtkpanel.xml.in -+%.xml: %.xml.in - $(AM_V_GEN) sed \ - -e 's|@VERSION[@]|$(VERSION)|g' \ - -e 's|@libexecdir[@]|$(libexecdir)|g' $< > $@.tmp && \ -@@ -108,6 +108,7 @@ libexec_PROGRAMS = ibus-ui-gtk3 - - ibus_ui_gtk3_SOURCES = \ - application.vala \ -+ bindingcommon.vala \ - candidatearea.vala \ - candidatepanel.vala \ - emojier.vala \ -@@ -155,9 +156,12 @@ EXTRA_DIST = \ - $(emoji_headers) \ - $(man_seven_in_files) \ - emojierapp.vala \ -+ extension.vala \ -+ gtkextension.xml.in \ - gtkpanel.xml.in \ - notification-item.xml \ - notification-watcher.xml \ -+ panelbinding.vala \ - $(NULL) - - if ENABLE_EMOJI_DICT -@@ -167,10 +171,8 @@ libexec_PROGRAMS += ibus-ui-emojier - - ibus_ui_emojier_VALASOURCES = \ - emojierapp.vala \ -- candidatearea.vala \ - emojier.vala \ - iconwidget.vala \ -- pango.vala \ - separator.vala \ - $(NULL) - ibus_ui_emojier_SOURCES = \ -@@ -198,6 +200,53 @@ emojierapp.o: $(srcdir)/emojierapp.c - $(AM_V_CC_no)$(COMPILE) -c -o $@ $< - $(NULL) - -+component_DATA += gtkextension.xml -+CLEANFILES += gtkextension.xml -+libexec_PROGRAMS += ibus-extension-gtk3 -+ -+ibus_extension_gtk3_VALASOURCES = \ -+ bindingcommon.vala \ -+ emojier.vala \ -+ extension.vala \ -+ iconwidget.vala \ -+ keybindingmanager.vala \ -+ panelbinding.vala \ -+ $(NULL) -+ibus_extension_gtk3_SOURCES = \ -+ $(ibus_extension_gtk3_VALASOURCES:.vala=.c) \ -+ $(NULL) -+ -+ibus_extension_gtk3_LDADD = \ -+ $(AM_LDADD) \ -+ $(NULL) -+ibus_extension_gtk3_VALAFLAGS = \ -+ $(AM_VALAFLAGS) \ -+ $(NULL) -+ -+# This line and foo_VALASOURCES line can delete the duplicated entries -+# of emojier.c: emojier.vala -+extension.c: $(ibus_extension_gtk3_VALASOURCES) -+ $(AM_V_VALAC)$(am__cd) $(srcdir) && $(VALAC) $(AM_VALAFLAGS) \ -+$(VALAFLAGS) -C $(ibus_extension_gtk3_VALASOURCES) -+ $(NULL) -+# make dist creates .c files in a different srcdir -+extension.o: $(srcdir)/extension.c -+ $(AM_V_CC)source='$<' object='$@' libtool=no \ -+ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ -+ $(AM_V_CC_no)$(COMPILE) -c -o $@ $< -+ $(NULL) -+# of emojier.c: emojier.vala -+panelbinding.c: $(ibus_extension_gtk3_VALASOURCES) -+ $(AM_V_VALAC)$(am__cd) $(srcdir) && $(VALAC) $(AM_VALAFLAGS) \ -+$(VALAFLAGS) -C $(ibus_extension_gtk3_VALASOURCES) -+ $(NULL) -+# make dist creates .c files in a different srcdir -+panelbinding.o: $(srcdir)/panelbinding.c -+ $(AM_V_CC)source='$<' object='$@' libtool=no \ -+ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \ -+ $(AM_V_CC_no)$(COMPILE) -c -o $@ $< -+ $(NULL) -+ - man_seven_files = $(man_seven_in_files:.7.in=.7) - man_seven_DATA =$(man_seven_files:.7=.7.gz) - man_sevendir = $(mandir)/man7 -diff --git a/ui/gtk3/bindingcommon.vala b/ui/gtk3/bindingcommon.vala -new file mode 100644 -index 00000000..4171f29d ---- /dev/null -+++ b/ui/gtk3/bindingcommon.vala -@@ -0,0 +1,215 @@ -+/* vim:set et sts=4 sw=4: -+ * -+ * ibus - The Input Bus -+ * -+ * Copyright(c) 2018 Peng Huang -+ * Copyright(c) 2018 Takao Fujwiara -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -+ * USA -+ */ -+ -+/* This file depends on keybindingmanager.vala */ -+ -+class BindingCommon { -+ public enum KeyEventFuncType { -+ ANY, -+ IME_SWITCHER, -+ EMOJI_TYPING, -+ } -+ -+ public class Keybinding : GLib.Object { -+ public Keybinding(uint keysym, -+ Gdk.ModifierType modifiers, -+ bool reverse, -+ KeyEventFuncType ftype) { -+ this.keysym = keysym; -+ this.modifiers = modifiers; -+ this.reverse = reverse; -+ this.ftype = ftype; -+ } -+ -+ public uint keysym { get; set; } -+ public Gdk.ModifierType modifiers { get; set; } -+ public bool reverse { get; set; } -+ public KeyEventFuncType ftype { get; set; } -+ } -+ -+ public delegate void KeybindingFuncHandlerFunc(Gdk.Event event); -+ -+ public static void -+ keybinding_manager_bind(KeybindingManager keybinding_manager, -+ ref GLib.List keybindings, -+ string? accelerator, -+ KeyEventFuncType ftype, -+ KeybindingManager.KeybindingHandlerFunc -+ handler_normal, -+ KeybindingManager.KeybindingHandlerFunc? -+ handler_reverse) { -+ uint switch_keysym = 0; -+ Gdk.ModifierType switch_modifiers = 0; -+ Gdk.ModifierType reverse_modifier = Gdk.ModifierType.SHIFT_MASK; -+ Keybinding keybinding; -+ -+ Gtk.accelerator_parse(accelerator, -+ out switch_keysym, out switch_modifiers); -+ -+ // Map virtual modifiers to (i.e. Mod2, Mod3, ...) -+ const Gdk.ModifierType VIRTUAL_MODIFIERS = ( -+ Gdk.ModifierType.SUPER_MASK | -+ Gdk.ModifierType.HYPER_MASK | -+ Gdk.ModifierType.META_MASK); -+ if ((switch_modifiers & VIRTUAL_MODIFIERS) != 0) { -+ // workaround a bug in gdk vapi vala > 0.18 -+ // https://bugzilla.gnome.org/show_bug.cgi?id=677559 -+#if VALA_0_18 -+ Gdk.Keymap.get_default().map_virtual_modifiers( -+ ref switch_modifiers); -+#else -+ if ((switch_modifiers & Gdk.ModifierType.SUPER_MASK) != 0) -+ switch_modifiers |= Gdk.ModifierType.MOD4_MASK; -+ if ((switch_modifiers & Gdk.ModifierType.HYPER_MASK) != 0) -+ switch_modifiers |= Gdk.ModifierType.MOD4_MASK; -+#endif -+ switch_modifiers &= ~VIRTUAL_MODIFIERS; -+ } -+ -+ if (switch_keysym == 0 && switch_modifiers == 0) { -+ warning("Parse accelerator '%s' failed!", accelerator); -+ return; -+ } -+ -+ keybinding = new Keybinding(switch_keysym, -+ switch_modifiers, -+ false, -+ ftype); -+ keybindings.append(keybinding); -+ -+ keybinding_manager.bind(switch_keysym, switch_modifiers, -+ handler_normal); -+ if (ftype == KeyEventFuncType.EMOJI_TYPING) { -+ return; -+ } -+ -+ // accelerator already has Shift mask -+ if ((switch_modifiers & reverse_modifier) != 0) { -+ return; -+ } -+ -+ switch_modifiers |= reverse_modifier; -+ -+ keybinding = new Keybinding(switch_keysym, -+ switch_modifiers, -+ true, -+ ftype); -+ keybindings.append(keybinding); -+ -+ if (ftype == KeyEventFuncType.IME_SWITCHER) { -+ keybinding_manager.bind(switch_keysym, switch_modifiers, -+ handler_reverse); -+ } -+ return; -+ } -+ -+ public static void -+ unbind_switch_shortcut(KeyEventFuncType ftype, -+ GLib.List keybindings) { -+ var keybinding_manager = KeybindingManager.get_instance(); -+ -+ while (keybindings != null) { -+ Keybinding keybinding = keybindings.data; -+ -+ if (ftype == KeyEventFuncType.ANY || -+ ftype == keybinding.ftype) { -+ keybinding_manager.unbind(keybinding.keysym, -+ keybinding.modifiers); -+ } -+ keybindings = keybindings.next; -+ } -+ } -+ -+ public static void -+ set_custom_font(GLib.Settings? settings_panel, -+ GLib.Settings? settings_emoji, -+ ref Gtk.CssProvider? css_provider) { -+ Gdk.Display display = Gdk.Display.get_default(); -+ Gdk.Screen screen = (display != null) ? -+ display.get_default_screen() : null; -+ -+ if (screen == null) { -+ warning("Could not open display."); -+ return; -+ } -+ -+ if (settings_emoji != null) { -+ string emoji_font = settings_emoji.get_string("font"); -+ if (emoji_font == null) { -+ warning("No config emoji:font."); -+ return; -+ } -+ IBusEmojier.set_emoji_font(emoji_font); -+ } -+ -+ if (settings_panel == null) -+ return; -+ -+ bool use_custom_font = settings_panel.get_boolean("use-custom-font"); -+ -+ if (css_provider != null) { -+ Gtk.StyleContext.remove_provider_for_screen(screen, -+ css_provider); -+ css_provider = null; -+ } -+ -+ if (use_custom_font == false) { -+ return; -+ } -+ -+ string custom_font = settings_panel.get_string("custom-font"); -+ if (custom_font == null) { -+ warning("No config panel:custom-font."); -+ return; -+ } -+ -+ Pango.FontDescription font_desc = -+ Pango.FontDescription.from_string(custom_font); -+ string font_family = font_desc.get_family(); -+ int font_size = font_desc.get_size() / Pango.SCALE; -+ string data; -+ -+ if (Gtk.MAJOR_VERSION < 3 || -+ (Gtk.MAJOR_VERSION == 3 && Gtk.MINOR_VERSION < 20)) { -+ data = "GtkLabel { font: %s; }".printf(custom_font); -+ } else { -+ data = "label { font-family: %s; font-size: %dpt; }" -+ .printf(font_family, font_size); -+ } -+ -+ css_provider = new Gtk.CssProvider(); -+ -+ try { -+ css_provider.load_from_data(data, -1); -+ } catch (GLib.Error e) { -+ warning("Failed css_provider_from_data: %s: %s", custom_font, -+ e.message); -+ return; -+ } -+ -+ Gtk.StyleContext.add_provider_for_screen( -+ screen, -+ css_provider, -+ Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); -+ } -+} -diff --git a/ui/gtk3/candidatearea.vala b/ui/gtk3/candidatearea.vala -index e162a960..f590cf3a 100644 ---- a/ui/gtk3/candidatearea.vala -+++ b/ui/gtk3/candidatearea.vala -@@ -21,108 +21,6 @@ - * USA - */ - --class ThemedRGBA { -- public Gdk.RGBA *normal_fg { get; set; } -- public Gdk.RGBA *normal_bg { get; set; } -- public Gdk.RGBA *selected_fg { get; set; } -- public Gdk.RGBA *selected_bg { get; set; } -- -- private Gtk.StyleContext m_style_context; -- -- public ThemedRGBA(Gtk.Widget widget) { -- this.normal_fg = null; -- this.normal_bg = null; -- this.selected_fg = null; -- this.selected_bg = null; -- -- /* Use the color of Gtk.TextView instead of Gtk.Label -- * because the selected label "color" is not configured -- * in "Adwaita" theme and the selected label "background-color" -- * is not configured in "Maia" theme. -- * https://github.com/ibus/ibus/issues/1871 -- */ -- Gtk.WidgetPath widget_path = new Gtk.WidgetPath(); -- widget_path.append_type(typeof(Gtk.TextView)); -- m_style_context = new Gtk.StyleContext(); -- m_style_context.set_path(widget_path); -- m_style_context.add_class(Gtk.STYLE_CLASS_VIEW); -- -- /* "-gtk-secondary-caret-color" value is different -- * if the parent widget is set in "Menta" theme. -- */ -- m_style_context.set_parent(widget.get_style_context()); -- -- get_rgba(); -- -- m_style_context.changed.connect(() => { get_rgba(); }); -- } -- -- ~ThemedRGBA() { -- reset_rgba(); -- } -- -- private void reset_rgba() { -- if (this.normal_fg != null) { -- this.normal_fg.free(); -- this.normal_fg = null; -- } -- if (this.normal_bg != null) { -- this.normal_bg.free(); -- this.normal_bg = null; -- } -- if (this.selected_fg != null) { -- this.selected_fg.free(); -- this.selected_fg = null; -- } -- if (this.selected_bg != null) { -- this.selected_bg.free(); -- this.selected_bg = null; -- } -- } -- -- private void get_rgba() { -- reset_rgba(); -- Gdk.RGBA *normal_fg = null; -- Gdk.RGBA *normal_bg = null; -- Gdk.RGBA *selected_fg = null; -- Gdk.RGBA *selected_bg = null; -- m_style_context.get(Gtk.StateFlags.NORMAL, -- "color", -- out normal_fg); -- m_style_context.get(Gtk.StateFlags.SELECTED, -- "color", -- out selected_fg); -- -- string bg_prop = "background-color"; -- m_style_context.get(Gtk.StateFlags.NORMAL, -- bg_prop, -- out normal_bg); -- m_style_context.get(Gtk.StateFlags.SELECTED, -- bg_prop, -- out selected_bg); -- if (normal_bg.red == selected_bg.red && -- normal_bg.green == selected_bg.green && -- normal_bg.blue == selected_bg.blue && -- normal_bg.alpha == selected_bg.alpha) { -- normal_bg.free(); -- normal_bg = null; -- normal_bg.free(); -- normal_bg = null; -- bg_prop = "-gtk-secondary-caret-color"; -- m_style_context.get(Gtk.StateFlags.NORMAL, -- bg_prop, -- out normal_bg); -- m_style_context.get(Gtk.StateFlags.SELECTED, -- bg_prop, -- out selected_bg); -- } -- this.normal_fg = normal_fg; -- this.normal_bg = normal_bg; -- this.selected_fg = selected_fg; -- this.selected_bg = selected_bg; -- } --} -- - class CandidateArea : Gtk.Box { - private bool m_vertical; - private Gtk.Label[] m_labels; -diff --git a/ui/gtk3/extension.vala b/ui/gtk3/extension.vala -new file mode 100644 -index 00000000..a170280b ---- /dev/null -+++ b/ui/gtk3/extension.vala -@@ -0,0 +1,124 @@ -+/* vim:set et sts=4 sw=4: -+ * -+ * ibus - The Input Bus -+ * -+ * Copyright(c) 2018 Peng Huang -+ * Copyright(c) 2018 Takao Fujiwara -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -+ * USA -+ */ -+ -+class ExtensionGtk { -+ private IBus.Bus m_bus; -+ private PanelBinding m_panel; -+ -+ public ExtensionGtk(string[] argv) { -+ GLib.Intl.bindtextdomain(Config.GETTEXT_PACKAGE, -+ Config.GLIB_LOCALE_DIR); -+ GLib.Intl.bind_textdomain_codeset(Config.GETTEXT_PACKAGE, "UTF-8"); -+ IBus.init(); -+ Gtk.init(ref argv); -+ -+ m_bus = new IBus.Bus(); -+ -+ m_bus.connected.connect(bus_connected); -+ m_bus.disconnected.connect(bus_disconnected); -+ -+ if (m_bus.is_connected()) { -+ init(); -+ } -+ } -+ -+ private void init() { -+ DBusConnection connection = m_bus.get_connection(); -+ connection.signal_subscribe("org.freedesktop.DBus", -+ "org.freedesktop.DBus", -+ "NameAcquired", -+ "/org/freedesktop/DBus", -+ IBus.SERVICE_PANEL_EXTENSION, -+ DBusSignalFlags.NONE, -+ bus_name_acquired_cb); -+ connection.signal_subscribe("org.freedesktop.DBus", -+ "org.freedesktop.DBus", -+ "NameLost", -+ "/org/freedesktop/DBus", -+ IBus.SERVICE_PANEL_EXTENSION, -+ DBusSignalFlags.NONE, -+ bus_name_lost_cb); -+ var flags = -+ IBus.BusNameFlag.ALLOW_REPLACEMENT | -+ IBus.BusNameFlag.REPLACE_EXISTING; -+ m_bus.request_name(IBus.SERVICE_PANEL_EXTENSION, flags); -+ } -+ -+ public int run() { -+ Gtk.main(); -+ return 0; -+ } -+ -+ private void bus_name_acquired_cb(DBusConnection connection, -+ string sender_name, -+ string object_path, -+ string interface_name, -+ string signal_name, -+ Variant parameters) { -+ debug("signal_name = %s", signal_name); -+ m_panel = new PanelBinding(m_bus); -+ m_panel.load_settings(); -+ } -+ -+ private void bus_name_lost_cb(DBusConnection connection, -+ string sender_name, -+ string object_path, -+ string interface_name, -+ string signal_name, -+ Variant parameters) { -+ // "Destroy" dbus method was called before this callback is called. -+ // "Destroy" dbus method -> ibus_service_destroy() -+ // -> g_dbus_connection_unregister_object() -+ // -> g_object_unref(m_panel) will be called later with an idle method, -+ // which was assigned in the arguments of -+ // g_dbus_connection_register_object() -+ debug("signal_name = %s", signal_name); -+ -+ // unref m_panel -+ m_panel.disconnect_signals(); -+ m_panel = null; -+ } -+ -+ private void bus_disconnected(IBus.Bus bus) { -+ debug("connection is lost."); -+ Gtk.main_quit(); -+ } -+ -+ private void bus_connected(IBus.Bus bus) { -+ init(); -+ } -+ -+ public static void main(string[] argv) { -+ // https://bugzilla.redhat.com/show_bug.cgi?id=1226465#c20 -+ // In /etc/xdg/plasma-workspace/env/gtk3_scrolling.sh -+ // Plasma deskop sets this variable and prevents Super-space, -+ // and Ctrl-Shift-e when ibus-ui-gtk3 runs after the -+ // desktop is launched. -+ GLib.Environment.unset_variable("GDK_CORE_DEVICE_EVENTS"); -+ // for Gdk.X11.get_default_xdisplay() -+ Gdk.set_allowed_backends("x11"); -+ -+ ExtensionGtk extension = new ExtensionGtk(argv); -+ extension.run(); -+ } -+} -diff --git a/ui/gtk3/gtkextension.xml.in b/ui/gtk3/gtkextension.xml.in -new file mode 100644 -index 00000000..b8157c97 ---- /dev/null -+++ b/ui/gtk3/gtkextension.xml.in -@@ -0,0 +1,12 @@ -+ -+ -+ -+ org.freedesktop.IBus.Panel.Extension -+ Gtk Panel Extension Component -+ @libexecdir@/ibus-extension-gtk3 -+ @VERSION@ -+ Takao Fujiwara <takao.fujiwara1@gmail.com> -+ GPL -+ https://github.com/ibus/ibus/wiki -+ ibus -+ -diff --git a/ui/gtk3/iconwidget.vala b/ui/gtk3/iconwidget.vala -index d322650c..36643c74 100644 ---- a/ui/gtk3/iconwidget.vala -+++ b/ui/gtk3/iconwidget.vala -@@ -3,6 +3,7 @@ - * ibus - The Input Bus - * - * Copyright(c) 2011-2014 Peng Huang -+ * Copyright(c) 2018 Takao Fujiwara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -20,6 +21,108 @@ - * USA - */ - -+class ThemedRGBA { -+ public Gdk.RGBA *normal_fg { get; set; } -+ public Gdk.RGBA *normal_bg { get; set; } -+ public Gdk.RGBA *selected_fg { get; set; } -+ public Gdk.RGBA *selected_bg { get; set; } -+ -+ private Gtk.StyleContext m_style_context; -+ -+ public ThemedRGBA(Gtk.Widget widget) { -+ this.normal_fg = null; -+ this.normal_bg = null; -+ this.selected_fg = null; -+ this.selected_bg = null; -+ -+ /* Use the color of Gtk.TextView instead of Gtk.Label -+ * because the selected label "color" is not configured -+ * in "Adwaita" theme and the selected label "background-color" -+ * is not configured in "Maia" theme. -+ * https://github.com/ibus/ibus/issues/1871 -+ */ -+ Gtk.WidgetPath widget_path = new Gtk.WidgetPath(); -+ widget_path.append_type(typeof(Gtk.TextView)); -+ m_style_context = new Gtk.StyleContext(); -+ m_style_context.set_path(widget_path); -+ m_style_context.add_class(Gtk.STYLE_CLASS_VIEW); -+ -+ /* "-gtk-secondary-caret-color" value is different -+ * if the parent widget is set in "Menta" theme. -+ */ -+ m_style_context.set_parent(widget.get_style_context()); -+ -+ get_rgba(); -+ -+ m_style_context.changed.connect(() => { get_rgba(); }); -+ } -+ -+ ~ThemedRGBA() { -+ reset_rgba(); -+ } -+ -+ private void reset_rgba() { -+ if (this.normal_fg != null) { -+ this.normal_fg.free(); -+ this.normal_fg = null; -+ } -+ if (this.normal_bg != null) { -+ this.normal_bg.free(); -+ this.normal_bg = null; -+ } -+ if (this.selected_fg != null) { -+ this.selected_fg.free(); -+ this.selected_fg = null; -+ } -+ if (this.selected_bg != null) { -+ this.selected_bg.free(); -+ this.selected_bg = null; -+ } -+ } -+ -+ private void get_rgba() { -+ reset_rgba(); -+ Gdk.RGBA *normal_fg = null; -+ Gdk.RGBA *normal_bg = null; -+ Gdk.RGBA *selected_fg = null; -+ Gdk.RGBA *selected_bg = null; -+ m_style_context.get(Gtk.StateFlags.NORMAL, -+ "color", -+ out normal_fg); -+ m_style_context.get(Gtk.StateFlags.SELECTED, -+ "color", -+ out selected_fg); -+ -+ string bg_prop = "background-color"; -+ m_style_context.get(Gtk.StateFlags.NORMAL, -+ bg_prop, -+ out normal_bg); -+ m_style_context.get(Gtk.StateFlags.SELECTED, -+ bg_prop, -+ out selected_bg); -+ if (normal_bg.red == selected_bg.red && -+ normal_bg.green == selected_bg.green && -+ normal_bg.blue == selected_bg.blue && -+ normal_bg.alpha == selected_bg.alpha) { -+ normal_bg.free(); -+ normal_bg = null; -+ normal_bg.free(); -+ normal_bg = null; -+ bg_prop = "-gtk-secondary-caret-color"; -+ m_style_context.get(Gtk.StateFlags.NORMAL, -+ bg_prop, -+ out normal_bg); -+ m_style_context.get(Gtk.StateFlags.SELECTED, -+ bg_prop, -+ out selected_bg); -+ } -+ this.normal_fg = normal_fg; -+ this.normal_bg = normal_bg; -+ this.selected_fg = selected_fg; -+ this.selected_bg = selected_bg; -+ } -+} -+ - class IconWidget: Gtk.Image { - /** - * IconWidget: -diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala -index bcb3ed75..d9238c89 100644 ---- a/ui/gtk3/panel.vala -+++ b/ui/gtk3/panel.vala -@@ -22,39 +22,16 @@ - */ - - class Panel : IBus.PanelService { -- private class Keybinding { -- public Keybinding(uint keysym, -- Gdk.ModifierType modifiers, -- bool reverse, -- KeyEventFuncType ftype) { -- this.keysym = keysym; -- this.modifiers = modifiers; -- this.reverse = reverse; -- this.ftype = ftype; -- } -- -- public uint keysym { get; set; } -- public Gdk.ModifierType modifiers { get; set; } -- public bool reverse { get; set; } -- public KeyEventFuncType ftype { get; set; } -- } - - private enum IconType { - STATUS_ICON, - INDICATOR, - } - -- private enum KeyEventFuncType { -- ANY, -- IME_SWITCHER, -- EMOJI_TYPING, -- } -- - private IBus.Bus m_bus; - private GLib.Settings m_settings_general = null; - private GLib.Settings m_settings_hotkey = null; - private GLib.Settings m_settings_panel = null; -- private GLib.Settings m_settings_emoji = null; - private IconType m_icon_type = IconType.STATUS_ICON; - private Indicator m_indicator; - #if INDICATOR -@@ -73,10 +50,6 @@ class Panel : IBus.PanelService { - private CandidatePanel m_candidate_panel; - private Switcher m_switcher; - private uint m_switcher_focus_set_engine_id; -- private IBusEmojier? m_emojier; -- private uint m_emojier_set_emoji_lang_id; -- private uint m_emojier_focus_commit_text_id; -- private string[] m_emojier_favorites = {}; - private PropertyManager m_property_manager; - private PropertyPanel m_property_panel; - private GLib.Pid m_setup_pid = 0; -@@ -108,7 +81,8 @@ class Panel : IBus.PanelService { - private ulong m_activate_id; - private ulong m_registered_status_notifier_item_id; - -- private GLib.List m_keybindings = new GLib.List(); -+ private GLib.List m_keybindings = -+ new GLib.List(); - - public Panel(IBus.Bus bus) { - GLib.assert(bus.is_connected()); -@@ -147,8 +121,6 @@ class Panel : IBus.PanelService { - m_switcher.set_popup_delay_time((uint) m_switcher_delay_time); - } - -- bind_emoji_shortcut(); -- - m_property_manager = new PropertyManager(); - m_property_manager.property_activate.connect((w, k, s) => { - property_activate(k, s); -@@ -168,7 +140,9 @@ class Panel : IBus.PanelService { - if (m_indicator != null) - m_indicator.unregister_connection(); - #endif -- unbind_switch_shortcut(KeyEventFuncType.ANY); -+ BindingCommon.unbind_switch_shortcut( -+ BindingCommon.KeyEventFuncType.ANY, m_keybindings); -+ m_keybindings = null; - } - - private void init_settings() { -@@ -176,7 +150,6 @@ class Panel : IBus.PanelService { - m_settings_hotkey = - new GLib.Settings("org.freedesktop.ibus.general.hotkey"); - m_settings_panel = new GLib.Settings("org.freedesktop.ibus.panel"); -- m_settings_emoji = new GLib.Settings("org.freedesktop.ibus.panel.emoji"); - - m_settings_general.changed["preload-engines"].connect((key) => { - update_engines(m_settings_general.get_strv(key), -@@ -205,16 +178,23 @@ class Panel : IBus.PanelService { - }); - - m_settings_hotkey.changed["triggers"].connect((key) => { -- unbind_switch_shortcut(KeyEventFuncType.IME_SWITCHER); -+ BindingCommon.unbind_switch_shortcut( -+ BindingCommon.KeyEventFuncType.IME_SWITCHER, -+ m_keybindings); -+ m_keybindings = null; - bind_switch_shortcut(); - }); - - m_settings_panel.changed["custom-font"].connect((key) => { -- set_custom_font(); -+ BindingCommon.set_custom_font(m_settings_panel, -+ null, -+ ref m_css_provider); - }); - - m_settings_panel.changed["use-custom-font"].connect((key) => { -- set_custom_font(); -+ BindingCommon.set_custom_font(m_settings_panel, -+ null, -+ ref m_css_provider); - }); - - m_settings_panel.changed["show-icon-on-systray"].connect((key) => { -@@ -245,39 +225,6 @@ class Panel : IBus.PanelService { - m_settings_panel.changed["property-icon-delay-time"].connect((key) => { - set_property_icon_delay_time(); - }); -- -- m_settings_emoji.changed["hotkey"].connect((key) => { -- unbind_switch_shortcut(KeyEventFuncType.EMOJI_TYPING); -- bind_emoji_shortcut(); -- }); -- -- m_settings_emoji.changed["font"].connect((key) => { -- set_custom_font(); -- }); -- -- m_settings_emoji.changed["favorites"].connect((key) => { -- set_emoji_favorites(); -- }); -- -- m_settings_emoji.changed["favorite-annotations"].connect((key) => { -- set_emoji_favorites(); -- }); -- -- m_settings_emoji.changed["lang"].connect((key) => { -- set_emoji_lang(); -- }); -- -- m_settings_emoji.changed["has-partial-match"].connect((key) => { -- set_emoji_partial_match(); -- }); -- -- m_settings_emoji.changed["partial-match-length"].connect((key) => { -- set_emoji_partial_match(); -- }); -- -- m_settings_emoji.changed["partial-match-condition"].connect((key) => { -- set_emoji_partial_match(); -- }); - } - - private void popup_menu_at_area_window(Gtk.Menu menu, -@@ -409,120 +356,40 @@ class Panel : IBus.PanelService { - m_status_icon.set_from_icon_name("ibus-keyboard"); - } - -- private void keybinding_manager_bind(KeybindingManager keybinding_manager, -- string? accelerator, -- KeyEventFuncType ftype) { -- uint switch_keysym = 0; -- Gdk.ModifierType switch_modifiers = 0; -- Gdk.ModifierType reverse_modifier = Gdk.ModifierType.SHIFT_MASK; -- Keybinding keybinding; -- -- Gtk.accelerator_parse(accelerator, -- out switch_keysym, out switch_modifiers); -- -- // Map virtual modifiers to (i.e. Mod2, Mod3, ...) -- const Gdk.ModifierType VIRTUAL_MODIFIERS = ( -- Gdk.ModifierType.SUPER_MASK | -- Gdk.ModifierType.HYPER_MASK | -- Gdk.ModifierType.META_MASK); -- if ((switch_modifiers & VIRTUAL_MODIFIERS) != 0) { -- // workaround a bug in gdk vapi vala > 0.18 -- // https://bugzilla.gnome.org/show_bug.cgi?id=677559 --#if VALA_0_18 -- Gdk.Keymap.get_default().map_virtual_modifiers( -- ref switch_modifiers); --#else -- if ((switch_modifiers & Gdk.ModifierType.SUPER_MASK) != 0) -- switch_modifiers |= Gdk.ModifierType.MOD4_MASK; -- if ((switch_modifiers & Gdk.ModifierType.HYPER_MASK) != 0) -- switch_modifiers |= Gdk.ModifierType.MOD4_MASK; --#endif -- switch_modifiers &= ~VIRTUAL_MODIFIERS; -- } -- -- if (switch_keysym == 0 && switch_modifiers == 0) { -- warning("Parse accelerator '%s' failed!", accelerator); -- return; -- } -- -- keybinding = new Keybinding(switch_keysym, -- switch_modifiers, -- false, -- ftype); -- m_keybindings.append(keybinding); -- -- /* Workaround not to free the pointer of handle_engine_switch() */ -- if (ftype == KeyEventFuncType.IME_SWITCHER) { -- keybinding_manager.bind(switch_keysym, switch_modifiers, -- (e) => handle_engine_switch(e, false)); -- } else if (ftype == KeyEventFuncType.EMOJI_TYPING) { -- keybinding_manager.bind(switch_keysym, switch_modifiers, -- (e) => handle_emoji_typing(e)); -- return; -- } -- -- // accelerator already has Shift mask -- if ((switch_modifiers & reverse_modifier) != 0) { -- return; -- } -- -- switch_modifiers |= reverse_modifier; -- -- keybinding = new Keybinding(switch_keysym, -- switch_modifiers, -- true, -- ftype); -- m_keybindings.append(keybinding); -- -- if (ftype == KeyEventFuncType.IME_SWITCHER) { -- keybinding_manager.bind(switch_keysym, switch_modifiers, -- (e) => handle_engine_switch(e, true)); -- } -- } -- - private void bind_switch_shortcut() { - string[] accelerators = m_settings_hotkey.get_strv("triggers"); - - var keybinding_manager = KeybindingManager.get_instance(); - - foreach (var accelerator in accelerators) { -- keybinding_manager_bind(keybinding_manager, -- accelerator, -- KeyEventFuncType.IME_SWITCHER); -- } -- } -- -- private void bind_emoji_shortcut() { --#if EMOJI_DICT -- string[] accelerators = m_settings_emoji.get_strv("hotkey"); -- -- var keybinding_manager = KeybindingManager.get_instance(); -- -- foreach (var accelerator in accelerators) { -- keybinding_manager_bind(keybinding_manager, -- accelerator, -- KeyEventFuncType.EMOJI_TYPING); -+ BindingCommon.keybinding_manager_bind( -+ keybinding_manager, -+ ref m_keybindings, -+ accelerator, -+ BindingCommon.KeyEventFuncType.IME_SWITCHER, -+ handle_engine_switch_normal, -+ handle_engine_switch_reverse); - } --#endif - } - -- private void unbind_switch_shortcut(KeyEventFuncType ftype) { -+/* -+ public static void -+ unbind_switch_shortcut(KeyEventFuncType ftype, -+ GLib.List keybindings) { - var keybinding_manager = KeybindingManager.get_instance(); - -- unowned GLib.List keybindings = m_keybindings; -- - while (keybindings != null) { - Keybinding keybinding = keybindings.data; - -- if (ftype == KeyEventFuncType.ANY || ftype == keybinding.ftype) { -+ if (ftype == KeyEventFuncType.ANY || -+ ftype == keybinding.ftype) { - keybinding_manager.unbind(keybinding.keysym, - keybinding.modifiers); - } - keybindings = keybindings.next; - } -- -- m_keybindings = null; - } -+*/ - - /** - * panel_get_engines_from_xkb: -@@ -670,69 +537,6 @@ class Panel : IBus.PanelService { - m_settings_general.set_strv("preload-engines", names); - } - -- private void set_custom_font() { -- Gdk.Display display = Gdk.Display.get_default(); -- Gdk.Screen screen = (display != null) ? -- display.get_default_screen() : null; -- -- if (screen == null) { -- warning("Could not open display."); -- return; -- } -- -- string emoji_font = m_settings_emoji.get_string("font"); -- if (emoji_font == null) { -- warning("No config emoji:font."); -- return; -- } -- IBusEmojier.set_emoji_font(emoji_font); -- -- bool use_custom_font = m_settings_panel.get_boolean("use-custom-font"); -- -- if (m_css_provider != null) { -- Gtk.StyleContext.remove_provider_for_screen(screen, -- m_css_provider); -- m_css_provider = null; -- } -- -- if (use_custom_font == false) { -- return; -- } -- -- string custom_font = m_settings_panel.get_string("custom-font"); -- if (custom_font == null) { -- warning("No config panel:custom-font."); -- return; -- } -- -- Pango.FontDescription font_desc = -- Pango.FontDescription.from_string(custom_font); -- string font_family = font_desc.get_family(); -- int font_size = font_desc.get_size() / Pango.SCALE; -- string data; -- -- if (Gtk.MAJOR_VERSION < 3 || -- (Gtk.MAJOR_VERSION == 3 && Gtk.MINOR_VERSION < 20)) { -- data = "GtkLabel { font: %s; }".printf(custom_font); -- } else { -- data = "label { font-family: %s; font-size: %dpt; }" -- .printf(font_family, font_size); -- } -- -- m_css_provider = new Gtk.CssProvider(); -- -- try { -- m_css_provider.load_from_data(data, -1); -- } catch (GLib.Error e) { -- warning("Failed css_provider_from_data: %s: %s", custom_font, -- e.message); -- return; -- } -- -- Gtk.StyleContext.add_provider_for_screen(screen, -- m_css_provider, -- Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); -- } - - private void set_switcher_delay_time() { - m_switcher_delay_time = -@@ -855,35 +659,6 @@ class Panel : IBus.PanelService { - m_settings_panel.get_int("property-icon-delay-time"); - } - -- private void set_emoji_favorites() { -- m_emojier_favorites = m_settings_emoji.get_strv("favorites"); -- IBusEmojier.set_favorites( -- m_emojier_favorites, -- m_settings_emoji.get_strv("favorite-annotations")); -- } -- -- private void set_emoji_lang() { -- if (m_emojier_set_emoji_lang_id > 0) { -- GLib.Source.remove(m_emojier_set_emoji_lang_id); -- m_emojier_set_emoji_lang_id = 0; -- } -- m_emojier_set_emoji_lang_id = GLib.Idle.add(() => { -- IBusEmojier.set_annotation_lang( -- m_settings_emoji.get_string("lang")); -- m_emojier_set_emoji_lang_id = 0; -- IBusEmojier.load_unicode_dict(); -- return false; -- }); -- } -- -- private void set_emoji_partial_match() { -- IBusEmojier.set_partial_match( -- m_settings_emoji.get_boolean("has-partial-match")); -- IBusEmojier.set_partial_match_length( -- m_settings_emoji.get_int("partial-match-length")); -- IBusEmojier.set_partial_match_condition( -- m_settings_emoji.get_int("partial-match-condition")); -- } - - private int compare_versions(string version1, string version2) { - string[] version1_list = version1.split("."); -@@ -985,12 +760,16 @@ class Panel : IBus.PanelService { - set_use_xmodmap(); - update_engines(m_settings_general.get_strv("preload-engines"), - m_settings_general.get_strv("engines-order")); -- unbind_switch_shortcut(KeyEventFuncType.ANY); -+ BindingCommon.unbind_switch_shortcut( -+ BindingCommon.KeyEventFuncType.ANY, -+ m_keybindings); -+ m_keybindings = null; - bind_switch_shortcut(); -- bind_emoji_shortcut(); - set_switcher_delay_time(); - set_embed_preedit_text(); -- set_custom_font(); -+ BindingCommon.set_custom_font(m_settings_panel, -+ null, -+ ref m_css_provider); - set_show_icon_on_systray(); - set_lookup_table_orientation(); - set_show_property_panel(); -@@ -998,9 +777,6 @@ class Panel : IBus.PanelService { - set_follow_input_cursor_when_always_shown_property_panel(); - set_xkb_icon_rgba(); - set_property_icon_delay_time(); -- set_emoji_favorites(); -- set_emoji_lang(); -- set_emoji_partial_match(); - } - - /** -@@ -1037,10 +813,6 @@ class Panel : IBus.PanelService { - GLib.Source.remove(m_preload_engines_id); - m_preload_engines_id = 0; - } -- if (m_emojier_set_emoji_lang_id > 0) { -- GLib.Source.remove(m_emojier_set_emoji_lang_id); -- m_emojier_set_emoji_lang_id = 0; -- } - } - - private void engine_contexts_insert(IBus.EngineDesc engine) { -@@ -1091,7 +863,15 @@ class Panel : IBus.PanelService { - set_engine(engine); - } - -- private void handle_engine_switch(Gdk.Event event, bool revert) { -+ private void handle_engine_switch_normal(Gdk.Event event) { -+ handle_engine_switch(event, false); -+ } -+ -+ private void handle_engine_switch_reverse(Gdk.Event event) { -+ handle_engine_switch(event, true); -+ } -+ -+ private void handle_engine_switch(Gdk.Event event, bool reverse) { - // Do not need switch IME - if (m_engines.length <= 1) - return; -@@ -1105,12 +885,12 @@ class Panel : IBus.PanelService { - bool pressed = KeybindingManager.primary_modifier_still_pressed( - event, primary_modifiers); - -- if (revert) { -+ if (reverse) { - modifiers &= ~Gdk.ModifierType.SHIFT_MASK; - } - - if (pressed && m_switcher_delay_time >= 0) { -- int i = revert ? m_engines.length - 1 : 1; -+ int i = reverse ? m_engines.length - 1 : 1; - - /* The flag of m_switcher.is_running avoids the following problem: - * -@@ -1132,28 +912,11 @@ class Panel : IBus.PanelService { - this.switcher_focus_set_engine(); - } - } else { -- int i = revert ? m_engines.length - 1 : 1; -+ int i = reverse ? m_engines.length - 1 : 1; - switch_engine(i); - } - } - -- private void show_emojier(Gdk.Event event) { -- m_emojier = new IBusEmojier(); -- string emoji = m_emojier.run(m_real_current_context_path, event); -- if (emoji == null) { -- m_emojier = null; -- return; -- } -- this.emojier_focus_commit(); -- } -- -- private void handle_emoji_typing(Gdk.Event event) { -- if (m_emojier != null && m_emojier.is_running()) { -- m_emojier.present_centralize(event); -- return; -- } -- show_emojier(event); -- } - - private void run_preload_engines(IBus.EngineDesc[] engines, int index) { - string[] names = {}; -@@ -1393,7 +1156,18 @@ class Panel : IBus.PanelService { - event.key.window = Gdk.get_default_root_window(); - event.key.window.ref(); - } -- handle_emoji_typing(event); -+ IBus.XEvent xevent = new IBus.XEvent( -+ "event-type", IBus.XEventType.KEY_PRESS, -+ "window", -+ (event.key.window as Gdk.X11.Window).get_xid(), -+ "time", event.key.time, -+ "purpose", "emoji"); -+ /* new GLib.Variant("(sv)", "emoji", xevent.serialize_object()) -+ * will call g_variant_unref() for the child variant by vala. -+ * I have no idea not to unref the object so integrated -+ * the purpose to IBus.XEvent above. -+ */ -+ panel_extension(xevent.serialize_object()); - }); - m_sys_menu.append(item); - #endif -@@ -1557,67 +1331,6 @@ class Panel : IBus.PanelService { - } - } - -- private bool emojier_focus_commit_real() { -- if (m_emojier == null) -- return true; -- string selected_string = m_emojier.get_selected_string(); -- string prev_context_path = m_emojier.get_input_context_path(); -- if (selected_string != null && -- prev_context_path != "" && -- prev_context_path == m_current_context_path) { -- IBus.Text text = new IBus.Text.from_string(selected_string); -- commit_text(text); -- m_emojier = null; -- bool has_favorite = false; -- foreach (unowned string favorite in m_emojier_favorites) { -- if (favorite == selected_string) { -- has_favorite = true; -- break; -- } -- } -- if (!has_favorite) { -- m_emojier_favorites += selected_string; -- m_settings_emoji.set_strv("favorites", m_emojier_favorites); -- } -- return true; -- } -- -- return false; -- } -- -- private void emojier_focus_commit() { -- if (m_emojier == null) -- return; -- string selected_string = m_emojier.get_selected_string(); -- string prev_context_path = m_emojier.get_input_context_path(); -- if (selected_string == null && -- prev_context_path != "" && -- m_emojier.is_running()) { -- var context = GLib.MainContext.default(); -- if (m_emojier_focus_commit_text_id > 0 && -- context.find_source_by_id(m_emojier_focus_commit_text_id) -- != null) { -- GLib.Source.remove(m_emojier_focus_commit_text_id); -- } -- m_emojier_focus_commit_text_id = GLib.Timeout.add(100, () => { -- // focus_in is comming before switcher returns -- emojier_focus_commit_real(); -- m_emojier_focus_commit_text_id = -1; -- return false; -- }); -- } else { -- if (emojier_focus_commit_real()) { -- var context = GLib.MainContext.default(); -- if (m_emojier_focus_commit_text_id > 0 && -- context.find_source_by_id(m_emojier_focus_commit_text_id) -- != null) { -- GLib.Source.remove(m_emojier_focus_commit_text_id); -- } -- m_emojier_focus_commit_text_id = -1; -- } -- } -- } -- - public override void focus_in(string input_context_path) { - m_current_context_path = input_context_path; - -@@ -1632,7 +1345,6 @@ class Panel : IBus.PanelService { - m_real_current_context_path = m_current_context_path; - m_property_panel.focus_in(); - this.switcher_focus_set_engine(); -- this.emojier_focus_commit(); - } - - if (m_use_global_engine) -diff --git a/ui/gtk3/panelbinding.vala b/ui/gtk3/panelbinding.vala -new file mode 100644 -index 00000000..50700121 ---- /dev/null -+++ b/ui/gtk3/panelbinding.vala -@@ -0,0 +1,335 @@ -+/* vim:set et sts=4 sw=4: -+ * -+ * ibus - The Input Bus -+ * -+ * Copyright(c) 2018 Peng Huang -+ * Copyright(c) 2018 Takao Fujwiara -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -+ * USA -+ */ -+ -+class PanelBinding : IBus.PanelService { -+ private IBus.Bus m_bus; -+ private GLib.Settings m_settings_panel = null; -+ private GLib.Settings m_settings_emoji = null; -+ private string m_current_context_path = ""; -+ private string m_real_current_context_path = ""; -+ private IBusEmojier? m_emojier; -+ private uint m_emojier_set_emoji_lang_id; -+ private uint m_emojier_focus_commit_text_id; -+ private string[] m_emojier_favorites = {}; -+ private Gtk.CssProvider m_css_provider; -+ private const uint PRELOAD_ENGINES_DELAY_TIME = 30000; -+ private GLib.List m_keybindings = -+ new GLib.List(); -+ -+ public PanelBinding(IBus.Bus bus) { -+ GLib.assert(bus.is_connected()); -+ // Chain up base class constructor -+ GLib.Object(connection : bus.get_connection(), -+ object_path : IBus.PATH_PANEL_EXTENSION); -+ -+ m_bus = bus; -+ -+ init_settings(); -+ -+ bind_emoji_shortcut(); -+ } -+ -+ -+ ~PanelBinding() { -+ BindingCommon.unbind_switch_shortcut( -+ BindingCommon.KeyEventFuncType.ANY, -+ m_keybindings); -+ } -+ -+ -+ private void init_settings() { -+ m_settings_panel = new GLib.Settings("org.freedesktop.ibus.panel"); -+ m_settings_emoji = new GLib.Settings("org.freedesktop.ibus.panel.emoji"); -+ -+ m_settings_panel.changed["custom-font"].connect((key) => { -+ BindingCommon.set_custom_font(m_settings_panel, -+ m_settings_emoji, -+ ref m_css_provider); -+ }); -+ -+ m_settings_panel.changed["use-custom-font"].connect((key) => { -+ BindingCommon.set_custom_font(m_settings_panel, -+ m_settings_emoji, -+ ref m_css_provider); -+ }); -+ -+ m_settings_emoji.changed["hotkey"].connect((key) => { -+ BindingCommon.unbind_switch_shortcut( -+ BindingCommon.KeyEventFuncType.EMOJI_TYPING, -+ m_keybindings); -+ bind_emoji_shortcut(); -+ }); -+ -+ m_settings_emoji.changed["font"].connect((key) => { -+ BindingCommon.set_custom_font(m_settings_panel, -+ m_settings_emoji, -+ ref m_css_provider); -+ }); -+ -+ m_settings_emoji.changed["favorites"].connect((key) => { -+ set_emoji_favorites(); -+ }); -+ -+ m_settings_emoji.changed["favorite-annotations"].connect((key) => { -+ set_emoji_favorites(); -+ }); -+ -+ m_settings_emoji.changed["lang"].connect((key) => { -+ set_emoji_lang(); -+ }); -+ -+ m_settings_emoji.changed["has-partial-match"].connect((key) => { -+ set_emoji_partial_match(); -+ }); -+ -+ m_settings_emoji.changed["partial-match-length"].connect((key) => { -+ set_emoji_partial_match(); -+ }); -+ -+ m_settings_emoji.changed["partial-match-condition"].connect((key) => { -+ set_emoji_partial_match(); -+ }); -+ } -+ -+ -+ private void bind_emoji_shortcut() { -+#if EMOJI_DICT -+ string[] accelerators = m_settings_emoji.get_strv("hotkey"); -+ -+ var keybinding_manager = KeybindingManager.get_instance(); -+ -+ foreach (var accelerator in accelerators) { -+ BindingCommon.keybinding_manager_bind( -+ keybinding_manager, -+ ref m_keybindings, -+ accelerator, -+ BindingCommon.KeyEventFuncType.EMOJI_TYPING, -+ handle_emoji_typing, -+ null); -+ } -+#endif -+ } -+ -+ -+ private void set_emoji_favorites() { -+ m_emojier_favorites = m_settings_emoji.get_strv("favorites"); -+ IBusEmojier.set_favorites( -+ m_emojier_favorites, -+ m_settings_emoji.get_strv("favorite-annotations")); -+ } -+ -+ -+ private void set_emoji_lang() { -+ if (m_emojier_set_emoji_lang_id > 0) { -+ GLib.Source.remove(m_emojier_set_emoji_lang_id); -+ m_emojier_set_emoji_lang_id = 0; -+ } -+ m_emojier_set_emoji_lang_id = GLib.Idle.add(() => { -+ IBusEmojier.set_annotation_lang( -+ m_settings_emoji.get_string("lang")); -+ m_emojier_set_emoji_lang_id = 0; -+ IBusEmojier.load_unicode_dict(); -+ return false; -+ }); -+ } -+ -+ -+ private void set_emoji_partial_match() { -+ IBusEmojier.set_partial_match( -+ m_settings_emoji.get_boolean("has-partial-match")); -+ IBusEmojier.set_partial_match_length( -+ m_settings_emoji.get_int("partial-match-length")); -+ IBusEmojier.set_partial_match_condition( -+ m_settings_emoji.get_int("partial-match-condition")); -+ } -+ -+ -+ public void load_settings() { -+ BindingCommon.unbind_switch_shortcut(BindingCommon.KeyEventFuncType.ANY, -+ m_keybindings); -+ bind_emoji_shortcut(); -+ BindingCommon.set_custom_font(m_settings_panel, -+ m_settings_emoji, -+ ref m_css_provider); -+ set_emoji_favorites(); -+ set_emoji_lang(); -+ set_emoji_partial_match(); -+ } -+ -+ -+ /** -+ * disconnect_signals: -+ * -+ * Call this API before m_panel = null so that the ref_count becomes 0 -+ */ -+ public void disconnect_signals() { -+ if (m_emojier_set_emoji_lang_id > 0) { -+ GLib.Source.remove(m_emojier_set_emoji_lang_id); -+ m_emojier_set_emoji_lang_id = 0; -+ } -+ } -+ -+ -+ private void show_emojier(Gdk.Event event) { -+ m_emojier = new IBusEmojier(); -+ string emoji = m_emojier.run(m_real_current_context_path, event); -+ if (emoji == null) { -+ m_emojier = null; -+ return; -+ } -+ this.emojier_focus_commit(); -+ } -+ -+ -+ private void handle_emoji_typing(Gdk.Event event) { -+ if (m_emojier != null && m_emojier.is_running()) { -+ m_emojier.present_centralize(event); -+ return; -+ } -+ show_emojier(event); -+ } -+ -+ -+ private bool emojier_focus_commit_real() { -+ if (m_emojier == null) -+ return true; -+ string selected_string = m_emojier.get_selected_string(); -+ string prev_context_path = m_emojier.get_input_context_path(); -+ if (selected_string != null && -+ prev_context_path != "" && -+ prev_context_path == m_current_context_path) { -+ IBus.Text text = new IBus.Text.from_string(selected_string); -+ commit_text(text); -+ m_emojier = null; -+ bool has_favorite = false; -+ foreach (unowned string favorite in m_emojier_favorites) { -+ if (favorite == selected_string) { -+ has_favorite = true; -+ break; -+ } -+ } -+ if (!has_favorite) { -+ m_emojier_favorites += selected_string; -+ m_settings_emoji.set_strv("favorites", m_emojier_favorites); -+ } -+ return true; -+ } -+ -+ return false; -+ } -+ -+ -+ private void emojier_focus_commit() { -+ if (m_emojier == null) -+ return; -+ string selected_string = m_emojier.get_selected_string(); -+ string prev_context_path = m_emojier.get_input_context_path(); -+ if (selected_string == null && -+ prev_context_path != "" && -+ m_emojier.is_running()) { -+ var context = GLib.MainContext.default(); -+ if (m_emojier_focus_commit_text_id > 0 && -+ context.find_source_by_id(m_emojier_focus_commit_text_id) -+ != null) { -+ GLib.Source.remove(m_emojier_focus_commit_text_id); -+ } -+ m_emojier_focus_commit_text_id = GLib.Timeout.add(100, () => { -+ // focus_in is comming before switcher returns -+ emojier_focus_commit_real(); -+ m_emojier_focus_commit_text_id = -1; -+ return false; -+ }); -+ } else { -+ if (emojier_focus_commit_real()) { -+ var context = GLib.MainContext.default(); -+ if (m_emojier_focus_commit_text_id > 0 && -+ context.find_source_by_id(m_emojier_focus_commit_text_id) -+ != null) { -+ GLib.Source.remove(m_emojier_focus_commit_text_id); -+ } -+ m_emojier_focus_commit_text_id = -1; -+ } -+ } -+ } -+ -+ -+ public override void focus_in(string input_context_path) { -+ m_current_context_path = input_context_path; -+ -+ /* 'fake' input context is named as -+ * '/org/freedesktop/IBus/InputContext_1' and always send in -+ * focus-out events by ibus-daemon for the global engine mode. -+ * Now ibus-daemon assumes to always use the global engine. -+ * But this event should not be used for modal dialogs -+ * such as Switcher. -+ */ -+ if (!input_context_path.has_suffix("InputContext_1")) { -+ m_real_current_context_path = m_current_context_path; -+ this.emojier_focus_commit(); -+ } -+ } -+ -+ -+ public override void focus_out(string input_context_path) { -+ m_current_context_path = ""; -+ } -+ -+ -+ public override void panel_extension_received(GLib.Variant data) { -+ IBus.XEvent? xevent = IBus.Serializable.deserialize_object(data) -+ as IBus.XEvent; -+ if (xevent == null) { -+ warning ("Failed to deserialize IBusXEvent"); -+ return; -+ } -+ if (xevent.get_purpose() != "emoji") { -+ string format = "The purpose %s is not implemented in PanelExtension"; -+ warning (format.printf(xevent.get_purpose())); -+ return; -+ } -+ Gdk.EventType event_type; -+ if (xevent.get_event_type() == IBus.XEventType.KEY_PRESS) { -+ event_type = Gdk.EventType.KEY_PRESS; -+ } else if (xevent.get_event_type() == IBus.XEventType.KEY_RELEASE) { -+ event_type = Gdk.EventType.KEY_RELEASE; -+ } else { -+ warning ("Not supported type %d".printf(xevent.get_event_type())); -+ return; -+ } -+ Gdk.Event event = new Gdk.Event(event_type); -+ event.key.time = xevent.get_time(); -+ Gdk.Display? display = Gdk.Display.get_default(); -+ X.Window xid = xevent.get_window(); -+ Gdk.X11.Window window; -+ window = Gdk.X11.Window.lookup_for_display( -+ display as Gdk.X11.Display, xid); -+ if (window != null) { -+ event.key.window = window; -+ } else { -+ window = new Gdk.X11.Window.foreign_for_display( -+ display as Gdk.X11.Display, xid); -+ event.key.window = window; -+ } -+ handle_emoji_typing(event); -+ } -+} --- -2.14.3 - -From 366963d57d1468914611c71929cc64c83be9affd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Piotr=20Dr=C4=85g?= -Date: Tue, 20 Feb 2018 18:57:32 +0900 -Subject: [PATCH] Fix typos in translatable strings -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -BUG=https://github.com/ibus/ibus/pull/1983 -R=Shawn.P.Huang@gmail.com - -Review URL: https://codereview.appspot.com/333670043 - -Patch from Piotr Drąg . ---- - data/ibus.schemas.in | 6 +++--- - ui/gtk3/emojierapp.vala | 2 +- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in -index 278362d7..4523ccc4 100644 ---- a/data/ibus.schemas.in -+++ b/data/ibus.schemas.in -@@ -64,7 +64,7 @@ - [ara,bg,cz,dev,gr,gur,in,jp(kana),mal,mkd,ru,ua] - - Latin layouts which have no ASCII -- US layout is appended to the latin layouts. variant can be -+ US layout is appended to the Latin layouts. variant can be - omitted. - - -@@ -299,7 +299,7 @@ - and blue, 3. a RGB color in form 'rgb(r,g,b)' or - 4. a RGBA color in form 'rgba(r,g,b,a)' where 'r', - 'g', and 'b' are either integers in the range 0 to 255 -- or precentage values in the range 0% to 100%, and -+ or percentage values in the range 0% to 100%, and - 'a' is a floating point value in the range 0 to 1 - of the alpha. - -@@ -373,7 +373,7 @@ - Monospace 16 - - Custom font -- Custom font name for emoji chracters on emoji dialog -+ Custom font name for emoji characters on emoji dialog - - - -diff --git a/ui/gtk3/emojierapp.vala b/ui/gtk3/emojierapp.vala -index d816352e..efedf344 100644 ---- a/ui/gtk3/emojierapp.vala -+++ b/ui/gtk3/emojierapp.vala -@@ -94,7 +94,7 @@ public class EmojiApplication : Application { - /* TRANSLATORS: "FONT" should be capital and translatable. - * It's used for an argument command --font=FONT - */ -- N_("\"FONT\" for emoji chracters on emoji dialog"), -+ N_("\"FONT\" for emoji characters on emoji dialog"), - N_("FONT") }, - { "lang", 0, 0, OptionArg.STRING, out annotation_lang, - /* TRANSLATORS: "LANG" should be capital and translatable. --- -2.14.3 - -From d1ebb3d77ebfe8f58188261c383d8122e2125fe6 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Wed, 21 Feb 2018 12:12:11 +0900 -Subject: [PATCH] ui/gtk3: Show code points on Unicode name list dialog - -The code points are useful since the list has many names. - -R=Shawn.P.Huang@gmail.com - -Review URL: https://codereview.appspot.com/340770043 ---- - ui/gtk3/emojier.vala | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - -diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala -index 0bf34da8..c85dfa86 100644 ---- a/ui/gtk3/emojier.vala -+++ b/ui/gtk3/emojier.vala -@@ -198,7 +198,8 @@ public class IBusEmojier : Gtk.ApplicationWindow { - private class EPaddedLabelBox : Gtk.Box { - public EPaddedLabelBox(string text, - Gtk.Align align, -- TravelDirection direction=TravelDirection.NONE) { -+ TravelDirection direction=TravelDirection.NONE, -+ string? caption=null) { - GLib.Object( - name : "IBusEmojierPaddedLabelBox", - orientation : Gtk.Orientation.HORIZONTAL, -@@ -218,6 +219,11 @@ public class IBusEmojier : Gtk.ApplicationWindow { - } - EPaddedLabel label = new EPaddedLabel(text, align); - pack_start(label, true, true, 0); -+ if (caption != null) { -+ EPaddedLabel label_r = new EPaddedLabel(caption, -+ Gtk.Align.END); -+ pack_end(label_r, true, true, 0); -+ } - } - } - private class ETitleLabelBox : Gtk.HeaderBar { -@@ -979,9 +985,13 @@ public class IBusEmojier : Gtk.ApplicationWindow { - uint n = 0; - foreach (unowned IBus.UnicodeBlock block in m_unicode_block_list) { - string name = block.get_name(); -+ string caption = "U+%08X".printf(block.get_start()); - EBoxRow row = new EBoxRow(name); - EPaddedLabelBox widget = -- new EPaddedLabelBox(_(name), Gtk.Align.CENTER); -+ new EPaddedLabelBox(_(name), -+ Gtk.Align.CENTER, -+ TravelDirection.NONE, -+ caption); - row.add(widget); - m_list_box.add(row); - if (n++ == m_category_active_index) { --- -2.14.3 - -From fc54b0c051c2eb4a2c1f836b1415def00314cfc1 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Wed, 21 Feb 2018 12:17:31 +0900 -Subject: [PATCH] ui/gtk3: Load Unicode data when open the dialog by - default - -The emoji data requires about 10MB and the Unicode data requires about 15MB. -Now the emoji data is loaded at the time of startup and the Unicode data -is loaded if users open the dialog at the beginning. -The settings can be customized with gsettings command and the keys -of 'load-emoji-at-startup' and 'load-unicode-at-startup' in -'org.freedesktop.ibus.panel.emoji' schema. - -Review URL: https://codereview.appspot.com/340780043 ---- - data/ibus.schemas.in | 32 ++++++++++++++++++++++++++++++++ - ui/gtk3/panelbinding.vala | 41 +++++++++++++++++++++++++++++++++++++++-- - 2 files changed, 71 insertions(+), 2 deletions(-) - -diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in -index 4523ccc4..3c6b6f69 100644 ---- a/data/ibus.schemas.in -+++ b/data/ibus.schemas.in -@@ -455,6 +455,38 @@ - - - -+ -+ /schemas/desktop/ibus/panel/emoji/load-emoji-at-startup -+ /desktop/ibus/panel/emoji/load-emoji-at-startup -+ ibus -+ bool -+ true -+ -+ Load the emoji data at the time of startup -+ Load the emoji data at the time of startup if true. -+ About 10MB memory is needed to load the data. -+ Load the emoji data when open the emoji dialog at the -+ beginning if false. -+ -+ -+ -+ -+ /schemas/desktop/ibus/panel/emoji/load-unicode-at-startup -+ /desktop/ibus/panel/emoji/load-unicode-at-startup -+ ibus -+ bool -+ false -+ -+ Load the Unicode data at the time of startup -+ Load the Unicode data at the time of startup if true. -+ About 15MB memory is needed to load the data. -+ Load the Unicode data when open the emoji dialog at the -+ beginning if false. -+ The Unicode data is always loaded after the emoji data -+ is loaded even if true. -+ -+ -+ - - /schemas/desktop/ibus/general/embed_preedit_text - /desktop/ibus/general/embed_preedit_text -diff --git a/ui/gtk3/panelbinding.vala b/ui/gtk3/panelbinding.vala -index 50700121..1fbf6cfc 100644 ---- a/ui/gtk3/panelbinding.vala -+++ b/ui/gtk3/panelbinding.vala -@@ -35,6 +35,10 @@ class PanelBinding : IBus.PanelService { - private const uint PRELOAD_ENGINES_DELAY_TIME = 30000; - private GLib.List m_keybindings = - new GLib.List(); -+ private bool m_load_emoji_at_startup; -+ private bool m_loaded_emoji = false; -+ private bool m_load_unicode_at_startup; -+ private bool m_loaded_unicode = false; - - public PanelBinding(IBus.Bus bus) { - GLib.assert(bus.is_connected()); -@@ -109,6 +113,14 @@ class PanelBinding : IBus.PanelService { - m_settings_emoji.changed["partial-match-condition"].connect((key) => { - set_emoji_partial_match(); - }); -+ -+ m_settings_emoji.changed["load-emoji-at-startup"].connect((key) => { -+ set_load_emoji_at_startup(); -+ }); -+ -+ m_settings_emoji.changed["load-unicode-at-startup"].connect((key) => { -+ set_load_unicode_at_startup(); -+ }); - } - - -@@ -148,7 +160,11 @@ class PanelBinding : IBus.PanelService { - IBusEmojier.set_annotation_lang( - m_settings_emoji.get_string("lang")); - m_emojier_set_emoji_lang_id = 0; -- IBusEmojier.load_unicode_dict(); -+ m_loaded_emoji = true; -+ if (m_load_unicode_at_startup && !m_loaded_unicode) { -+ IBusEmojier.load_unicode_dict(); -+ m_loaded_unicode = true; -+ } - return false; - }); - } -@@ -164,7 +180,21 @@ class PanelBinding : IBus.PanelService { - } - - -+ private void set_load_emoji_at_startup() { -+ m_load_emoji_at_startup = -+ m_settings_emoji.get_boolean("load-emoji-at-startup"); -+ } -+ -+ -+ private void set_load_unicode_at_startup() { -+ m_load_unicode_at_startup = -+ m_settings_emoji.get_boolean("load-unicode-at-startup"); -+ } -+ - public void load_settings() { -+ -+ set_load_emoji_at_startup(); -+ set_load_unicode_at_startup(); - BindingCommon.unbind_switch_shortcut(BindingCommon.KeyEventFuncType.ANY, - m_keybindings); - bind_emoji_shortcut(); -@@ -172,7 +202,8 @@ class PanelBinding : IBus.PanelService { - m_settings_emoji, - ref m_css_provider); - set_emoji_favorites(); -- set_emoji_lang(); -+ if (m_load_emoji_at_startup && !m_loaded_emoji) -+ set_emoji_lang(); - set_emoji_partial_match(); - } - -@@ -191,6 +222,12 @@ class PanelBinding : IBus.PanelService { - - - private void show_emojier(Gdk.Event event) { -+ if (!m_loaded_emoji) -+ set_emoji_lang(); -+ if (!m_loaded_unicode && m_loaded_emoji) { -+ IBusEmojier.load_unicode_dict(); -+ m_loaded_unicode = true; -+ } - m_emojier = new IBusEmojier(); - string emoji = m_emojier.run(m_real_current_context_path, event); - if (emoji == null) { --- -2.14.3 - -From 7ccbd21ca7d163cdd71dc6c0405d8a32d63d324d Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 27 Feb 2018 14:06:30 +0900 -Subject: [PATCH 1/2] Disable panel extension for gdm user - -The gdm user's process is also running while the login user's process -is running so the double panel extensions are better to be avoided for -the memory usage. - -Review URL: https://codereview.appspot.com/340330044 ---- - bus/main.c | 49 ++++++++++++++++++++++++++++++------------------- - 1 file changed, 30 insertions(+), 19 deletions(-) - -diff --git a/bus/main.c b/bus/main.c -index 5b2589b1..fe603778 100644 ---- a/bus/main.c -+++ b/bus/main.c -@@ -47,6 +47,10 @@ static gchar *panel_extension = "default"; - static gchar *config = "default"; - static gchar *desktop = "gnome"; - -+static gchar *panel_extension_disable_users[] = { -+ "gdm" -+}; -+ - static void - show_version_and_quit (void) - { -@@ -170,6 +174,9 @@ _sig_usr2_handler (int sig) - gint - main (gint argc, gchar **argv) - { -+ int i; -+ const gchar *username = ibus_get_user_name (); -+ - setlocale (LC_ALL, ""); - - GOptionContext *context = g_option_context_new ("- ibus daemon"); -@@ -194,9 +201,7 @@ main (gint argc, gchar **argv) - - /* check uid */ - { -- const gchar *username = ibus_get_user_name (); -- uid_t uid = getuid (); -- struct passwd *pwd = getpwuid (uid); -+ struct passwd *pwd = getpwuid (getuid ()); - - if (pwd == NULL || g_strcmp0 (pwd->pw_name, username) != 0) { - g_printerr ("Please run ibus-daemon with login user! Do not run ibus-daemon with sudo or su.\n"); -@@ -237,6 +242,12 @@ main (gint argc, gchar **argv) - } - - bus_server_init (); -+ for (i = 0; i < G_N_ELEMENTS(panel_extension_disable_users); i++) { -+ if (!g_strcmp0 (username, panel_extension_disable_users[i]) != 0) { -+ panel_extension = "disable"; -+ break; -+ } -+ } - if (!single) { - /* execute config component */ - if (g_strcmp0 (config, "default") == 0) { -@@ -271,25 +282,25 @@ main (gint argc, gchar **argv) - if (!execute_cmdline (panel)) - exit (-1); - } -+ } - - #ifdef EMOJI_DICT -- if (g_strcmp0 (panel_extension, "default") == 0) { -- BusComponent *component; -- component = bus_ibus_impl_lookup_component_by_name ( -- BUS_DEFAULT_IBUS, IBUS_SERVICE_PANEL_EXTENSION); -- if (component) { -- bus_component_set_restart (component, restart); -- } -- if (component == NULL || -- !bus_component_start (component, g_verbose)) { -- g_printerr ("Can not execute default panel program\n"); -- exit (-1); -- } -- } else if (g_strcmp0 (panel_extension, "disable") != 0 && -- g_strcmp0 (panel_extension, "") != 0) { -- if (!execute_cmdline (panel_extension)) -- exit (-1); -+ if (g_strcmp0 (panel_extension, "default") == 0) { -+ BusComponent *component; -+ component = bus_ibus_impl_lookup_component_by_name ( -+ BUS_DEFAULT_IBUS, IBUS_SERVICE_PANEL_EXTENSION); -+ if (component) { -+ bus_component_set_restart (component, restart); -+ } -+ if (component == NULL || -+ !bus_component_start (component, g_verbose)) { -+ g_printerr ("Can not execute default panel program\n"); -+ exit (-1); - } -+ } else if (g_strcmp0 (panel_extension, "disable") != 0 && -+ g_strcmp0 (panel_extension, "") != 0) { -+ if (!execute_cmdline (panel_extension)) -+ exit (-1); - } - #endif - --- -2.14.3 - -From c57b7c34d75871db172e023b0094b979000f62fc Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 27 Feb 2018 14:10:29 +0900 -Subject: [PATCH 2/2] Enable emoji keybinding in Wayland - -XI2 keybinding does not work for the root window in Wayland because -of a security issue maybe. Now I think to move the keybinding in -ibus-extension-gtk3 to each IBusEngine. - -FIXME: Unfortunatelly gtk_get_current_event_time() cannot get time -for the delayed DBus events and gtk_window_move() does not work for -GtkDialog without a parent window in Wayland. - -R=Shawn.P.Huang@gmail.com - -Review URL: https://codereview.appspot.com/333700043 ---- - bus/engineproxy.c | 19 +- - bus/ibusimpl.c | 47 +++- - bus/inputcontext.c | 29 ++- - src/Makefile.am | 2 + - src/ibus.h | 1 + - src/ibusaccelgroup.c | 529 ++++++++++++++++++++++++++++++++++++++++++++++ - src/ibusaccelgroup.h | 51 +++++ - src/ibusengine.c | 179 +++++++++++++++- - ui/gtk3/emojier.vala | 1 + - ui/gtk3/extension.vala | 5 +- - ui/gtk3/panelbinding.vala | 65 ++---- - 11 files changed, 863 insertions(+), 65 deletions(-) - create mode 100644 src/ibusaccelgroup.c - create mode 100644 src/ibusaccelgroup.h - -diff --git a/bus/engineproxy.c b/bus/engineproxy.c -index cd4d54fd..175aec56 100644 ---- a/bus/engineproxy.c -+++ b/bus/engineproxy.c -@@ -2,7 +2,7 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2015-2016 Takao Fujiwara -+ * Copyright (C) 2015-2018 Takao Fujiwara - * Copyright (C) 2008-2016 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or -@@ -90,6 +90,7 @@ enum { - CURSOR_DOWN_LOOKUP_TABLE, - REGISTER_PROPERTIES, - UPDATE_PROPERTY, -+ PANEL_EXTENSION, - LAST_SIGNAL, - }; - -@@ -370,6 +371,17 @@ bus_engine_proxy_class_init (BusEngineProxyClass *class) - 1, - IBUS_TYPE_PROPERTY); - -+ engine_signals[PANEL_EXTENSION] = -+ g_signal_new (I_("panel-extension"), -+ G_TYPE_FROM_CLASS (class), -+ G_SIGNAL_RUN_LAST, -+ 0, -+ NULL, NULL, -+ bus_marshal_VOID__VARIANT, -+ G_TYPE_NONE, -+ 1, -+ G_TYPE_VARIANT); -+ - text_empty = ibus_text_new_from_static_string (""); - g_object_ref_sink (text_empty); - -@@ -631,6 +643,11 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy, - return; - } - -+ if (g_strcmp0 (signal_name, "PanelExtension") == 0) { -+ g_signal_emit (engine, engine_signals[PANEL_EXTENSION], 0, parameters); -+ return; -+ } -+ - g_return_if_reached (); - } - -diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c -index 58d205cf..a4ce3d9d 100644 ---- a/bus/ibusimpl.c -+++ b/bus/ibusimpl.c -@@ -302,9 +302,8 @@ _panel_destroy_cb (BusPanelProxy *panel, - } - - static void --_panel_panel_extension_cb (BusPanelProxy *panel, -- GVariant *parameters, -- BusIBusImpl *ibus) -+bus_ibus_impl_panel_extension_received (BusIBusImpl *ibus, -+ GVariant *parameters) - { - if (!ibus->extension) { - g_warning ("Panel extension is not running."); -@@ -323,6 +322,14 @@ _panel_panel_extension_cb (BusPanelProxy *panel, - -1, NULL, NULL, NULL); - } - -+static void -+_panel_panel_extension_cb (BusPanelProxy *panel, -+ GVariant *parameters, -+ BusIBusImpl *ibus) -+{ -+ bus_ibus_impl_panel_extension_received (ibus, parameters); -+} -+ - static void - _registry_changed_cb (IBusRegistry *registry, - BusIBusImpl *ibus) -@@ -642,6 +649,21 @@ bus_ibus_impl_set_context_engine_from_desc (BusIBusImpl *ibus, - NULL); - } - -+static void -+_context_panel_extension_cb (BusInputContext *context, -+ GVariant *parameters, -+ BusIBusImpl *ibus) -+{ -+ bus_ibus_impl_panel_extension_received (ibus, parameters); -+} -+ -+const static struct { -+ const gchar *name; -+ GCallback callback; -+} context_signals [] = { -+ { "panel-extension", G_CALLBACK (_context_panel_extension_cb) } -+}; -+ - /** - * bus_ibus_impl_set_focused_context: - * -@@ -651,6 +673,11 @@ static void - bus_ibus_impl_set_focused_context (BusIBusImpl *ibus, - BusInputContext *context) - { -+ gint i; -+ BusEngineProxy *engine = NULL; -+ guint purpose = 0; -+ guint hints = 0; -+ - g_assert (BUS_IS_IBUS_IMPL (ibus)); - g_assert (context == NULL || BUS_IS_INPUT_CONTEXT (context)); - g_assert (context == NULL || bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS); -@@ -660,10 +687,6 @@ bus_ibus_impl_set_focused_context (BusIBusImpl *ibus, - return; - } - -- BusEngineProxy *engine = NULL; -- guint purpose = 0; -- guint hints = 0; -- - if (ibus->focused_context) { - if (ibus->use_global_engine) { - /* dettach engine from the focused context */ -@@ -681,6 +704,10 @@ bus_ibus_impl_set_focused_context (BusIBusImpl *ibus, - - bus_input_context_get_content_type (ibus->focused_context, - &purpose, &hints); -+ for (i = 0; i < G_N_ELEMENTS(context_signals); i++) { -+ g_signal_handlers_disconnect_by_func (ibus->focused_context, -+ context_signals[i].callback, ibus); -+ } - g_object_unref (ibus->focused_context); - ibus->focused_context = NULL; - } -@@ -698,6 +725,12 @@ bus_ibus_impl_set_focused_context (BusIBusImpl *ibus, - bus_input_context_set_engine (context, engine); - bus_input_context_enable (context); - } -+ for (i = 0; i < G_N_ELEMENTS(context_signals); i++) { -+ g_signal_connect (ibus->focused_context, -+ context_signals[i].name, -+ context_signals[i].callback, -+ ibus); -+ } - - if (ibus->panel != NULL) - bus_panel_proxy_focus_in (ibus->panel, context); -diff --git a/bus/inputcontext.c b/bus/inputcontext.c -index 4f2ecafc..a957d107 100644 ---- a/bus/inputcontext.c -+++ b/bus/inputcontext.c -@@ -127,6 +127,7 @@ enum { - ENGINE_CHANGED, - REQUEST_ENGINE, - SET_CONTENT_TYPE, -+ PANEL_EXTENSION, - LAST_SIGNAL, - }; - -@@ -598,6 +599,17 @@ bus_input_context_class_init (BusInputContextClass *class) - G_TYPE_UINT, - G_TYPE_UINT); - -+ context_signals[PANEL_EXTENSION] = -+ g_signal_new (I_("panel-extension"), -+ G_TYPE_FROM_CLASS (class), -+ G_SIGNAL_RUN_LAST, -+ 0, -+ NULL, NULL, -+ bus_marshal_VOID__VARIANT, -+ G_TYPE_NONE, -+ 1, -+ G_TYPE_VARIANT); -+ - text_empty = ibus_text_new_from_string (""); - g_object_ref_sink (text_empty); - lookup_table_empty = ibus_lookup_table_new (9 /* page size */, 0, FALSE, FALSE); -@@ -2102,6 +2114,20 @@ _engine_update_property_cb (BusEngineProxy *engine, - bus_input_context_update_property (context, prop); - } - -+/** -+ * _engine_panel_extension_cb: -+ * -+ * A function to be called when "panel-extension" glib signal is sent -+ * from the engine object. -+ */ -+static void -+_engine_panel_extension_cb (BusEngineProxy *engine, -+ GVariant *parameters, -+ BusInputContext *context) -+{ -+ g_signal_emit (context, context_signals[PANEL_EXTENSION], 0, parameters); -+} -+ - #define DEFINE_FUNCTION(name) \ - static void \ - _engine_##name##_cb (BusEngineProxy *engine, \ -@@ -2244,7 +2270,8 @@ const static struct { - { "cursor-down-lookup-table", G_CALLBACK (_engine_cursor_down_lookup_table_cb) }, - { "register-properties", G_CALLBACK (_engine_register_properties_cb) }, - { "update-property", G_CALLBACK (_engine_update_property_cb) }, -- { "destroy", G_CALLBACK (_engine_destroy_cb) }, -+ { "panel-extension", G_CALLBACK (_engine_panel_extension_cb) }, -+ { "destroy", G_CALLBACK (_engine_destroy_cb) } - }; - - static void -diff --git a/src/Makefile.am b/src/Makefile.am -index 72ec05ab..6a62e0f0 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -72,6 +72,7 @@ libibus_1_0_la_LDFLAGS = \ - $(NULL) - - ibus_sources = \ -+ ibusaccelgroup.c \ - ibusattribute.c \ - ibusattrlist.c \ - ibusbus.c \ -@@ -122,6 +123,7 @@ ibus_enumtypes_sources = \ - $(NULL) - ibus_headers = \ - ibus.h \ -+ ibusaccelgroup.h \ - ibusattribute.h \ - ibusattrlist.h \ - ibusbus.h \ -diff --git a/src/ibus.h b/src/ibus.h -index b15dded9..256d57ba 100644 ---- a/src/ibus.h -+++ b/src/ibus.h -@@ -60,6 +60,7 @@ - #include - #include - #include -+#include - - #ifndef IBUS_DISABLE_DEPRECATED - #include -diff --git a/src/ibusaccelgroup.c b/src/ibusaccelgroup.c -new file mode 100644 -index 00000000..8a81597e ---- /dev/null -+++ b/src/ibusaccelgroup.c -@@ -0,0 +1,529 @@ -+/* GTK - The GIMP Toolkit -+ * Copyright (C) 1998, 2001 Tim Janik -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ */ -+ -+/* -+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS -+ * file for a list of people on the GTK+ Team. See the ChangeLog -+ * files for a list of changes. These files are distributed with -+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. -+ */ -+ -+#include "config.h" -+#include -+#include -+ -+#include "ibusaccelgroup.h" -+#include "ibuskeys.h" -+#include "ibuskeysyms.h" -+ -+ -+/* for _gtk_get_primary_accel_mod() */ -+#define _IBUS_GET_PRIMARY_ACCEL_MOD IBUS_CONTROL_MASK -+ -+/** -+ * SECTION: ibusaccelgroup -+ * @short_description: Groups of global keyboard accelerators for an -+ * entire GtkWindow -+ * @title: Accelerator Groups -+ * @stability: Unstable -+ * -+ * Provides ibus_accelerator_parse() -+ */ -+ -+ -+/** -+ * ibus_accelerator_valid: -+ * @keyval: a GDK keyval -+ * @modifiers: modifier mask -+ * -+ * Determines whether a given keyval and modifier mask constitute -+ * a valid keyboard accelerator. For example, the #IBUS_KEY_a keyval -+ * plus #IBUS_CONTROL_MASK is valid - this is a “Ctrl+a” accelerator. -+ * But, you can't, for instance, use the #IBUS_KEY_Control_L keyval -+ * as an accelerator. -+ * -+ * Returns: %TRUE if the accelerator is valid -+ */ -+gboolean -+ibus_accelerator_valid (guint keyval, -+ IBusModifierType modifiers) -+{ -+ static const guint invalid_accelerator_vals[] = { -+ IBUS_KEY_Shift_L, IBUS_KEY_Shift_R, IBUS_KEY_Shift_Lock, -+ IBUS_KEY_Caps_Lock, IBUS_KEY_ISO_Lock, IBUS_KEY_Control_L, -+ IBUS_KEY_Control_R, IBUS_KEY_Meta_L, IBUS_KEY_Meta_R, -+ IBUS_KEY_Alt_L, IBUS_KEY_Alt_R, IBUS_KEY_Super_L, IBUS_KEY_Super_R, -+ IBUS_KEY_Hyper_L, IBUS_KEY_Hyper_R, IBUS_KEY_ISO_Level3_Shift, -+ IBUS_KEY_ISO_Next_Group, IBUS_KEY_ISO_Prev_Group, -+ IBUS_KEY_ISO_First_Group, IBUS_KEY_ISO_Last_Group, -+ IBUS_KEY_Mode_switch, IBUS_KEY_Num_Lock, IBUS_KEY_Multi_key, -+ IBUS_KEY_Scroll_Lock, IBUS_KEY_Sys_Req, -+ IBUS_KEY_Tab, IBUS_KEY_ISO_Left_Tab, IBUS_KEY_KP_Tab, -+ IBUS_KEY_First_Virtual_Screen, IBUS_KEY_Prev_Virtual_Screen, -+ IBUS_KEY_Next_Virtual_Screen, IBUS_KEY_Last_Virtual_Screen, -+ IBUS_KEY_Terminate_Server, IBUS_KEY_AudibleBell_Enable, -+ 0 -+ }; -+ static const guint invalid_unmodified_vals[] = { -+ IBUS_KEY_Up, IBUS_KEY_Down, IBUS_KEY_Left, IBUS_KEY_Right, -+ IBUS_KEY_KP_Up, IBUS_KEY_KP_Down, IBUS_KEY_KP_Left, IBUS_KEY_KP_Right, -+ 0 -+ }; -+ const guint *ac_val; -+ -+ modifiers &= IBUS_MODIFIER_MASK; -+ -+ if (keyval <= 0xFF) -+ return keyval >= 0x20; -+ -+ ac_val = invalid_accelerator_vals; -+ while (*ac_val) { -+ if (keyval == *ac_val++) -+ return FALSE; -+ } -+ -+ if (!modifiers) { -+ ac_val = invalid_unmodified_vals; -+ while (*ac_val) { -+ if (keyval == *ac_val++) -+ return FALSE; -+ } -+ } -+ -+ return TRUE; -+} -+ -+static inline gboolean -+is_alt (const gchar *string) -+{ -+ return ((string[0] == '<') && -+ (string[1] == 'a' || string[1] == 'A') && -+ (string[2] == 'l' || string[2] == 'L') && -+ (string[3] == 't' || string[3] == 'T') && -+ (string[4] == '>')); -+} -+ -+static inline gboolean -+is_ctl (const gchar *string) -+{ -+ return ((string[0] == '<') && -+ (string[1] == 'c' || string[1] == 'C') && -+ (string[2] == 't' || string[2] == 'T') && -+ (string[3] == 'l' || string[3] == 'L') && -+ (string[4] == '>')); -+} -+ -+static inline gboolean -+is_modx (const gchar *string) -+{ -+ return ((string[0] == '<') && -+ (string[1] == 'm' || string[1] == 'M') && -+ (string[2] == 'o' || string[2] == 'O') && -+ (string[3] == 'd' || string[3] == 'D') && -+ (string[4] >= '1' && string[4] <= '5') && -+ (string[5] == '>')); -+} -+ -+static inline gboolean -+is_ctrl (const gchar *string) -+{ -+ return ((string[0] == '<') && -+ (string[1] == 'c' || string[1] == 'C') && -+ (string[2] == 't' || string[2] == 'T') && -+ (string[3] == 'r' || string[3] == 'R') && -+ (string[4] == 'l' || string[4] == 'L') && -+ (string[5] == '>')); -+} -+ -+static inline gboolean -+is_shft (const gchar *string) -+{ -+ return ((string[0] == '<') && -+ (string[1] == 's' || string[1] == 'S') && -+ (string[2] == 'h' || string[2] == 'H') && -+ (string[3] == 'f' || string[3] == 'F') && -+ (string[4] == 't' || string[4] == 'T') && -+ (string[5] == '>')); -+} -+ -+static inline gboolean -+is_shift (const gchar *string) -+{ -+ return ((string[0] == '<') && -+ (string[1] == 's' || string[1] == 'S') && -+ (string[2] == 'h' || string[2] == 'H') && -+ (string[3] == 'i' || string[3] == 'I') && -+ (string[4] == 'f' || string[4] == 'F') && -+ (string[5] == 't' || string[5] == 'T') && -+ (string[6] == '>')); -+} -+ -+static inline gboolean -+is_control (const gchar *string) -+{ -+ return ((string[0] == '<') && -+ (string[1] == 'c' || string[1] == 'C') && -+ (string[2] == 'o' || string[2] == 'O') && -+ (string[3] == 'n' || string[3] == 'N') && -+ (string[4] == 't' || string[4] == 'T') && -+ (string[5] == 'r' || string[5] == 'R') && -+ (string[6] == 'o' || string[6] == 'O') && -+ (string[7] == 'l' || string[7] == 'L') && -+ (string[8] == '>')); -+} -+ -+static inline gboolean -+is_release (const gchar *string) -+{ -+ return ((string[0] == '<') && -+ (string[1] == 'r' || string[1] == 'R') && -+ (string[2] == 'e' || string[2] == 'E') && -+ (string[3] == 'l' || string[3] == 'L') && -+ (string[4] == 'e' || string[4] == 'E') && -+ (string[5] == 'a' || string[5] == 'A') && -+ (string[6] == 's' || string[6] == 'S') && -+ (string[7] == 'e' || string[7] == 'E') && -+ (string[8] == '>')); -+} -+ -+static inline gboolean -+is_meta (const gchar *string) -+{ -+ return ((string[0] == '<') && -+ (string[1] == 'm' || string[1] == 'M') && -+ (string[2] == 'e' || string[2] == 'E') && -+ (string[3] == 't' || string[3] == 'T') && -+ (string[4] == 'a' || string[4] == 'A') && -+ (string[5] == '>')); -+} -+ -+static inline gboolean -+is_super (const gchar *string) -+{ -+ return ((string[0] == '<') && -+ (string[1] == 's' || string[1] == 'S') && -+ (string[2] == 'u' || string[2] == 'U') && -+ (string[3] == 'p' || string[3] == 'P') && -+ (string[4] == 'e' || string[4] == 'E') && -+ (string[5] == 'r' || string[5] == 'R') && -+ (string[6] == '>')); -+} -+ -+static inline gboolean -+is_hyper (const gchar *string) -+{ -+ return ((string[0] == '<') && -+ (string[1] == 'h' || string[1] == 'H') && -+ (string[2] == 'y' || string[2] == 'Y') && -+ (string[3] == 'p' || string[3] == 'P') && -+ (string[4] == 'e' || string[4] == 'E') && -+ (string[5] == 'r' || string[5] == 'R') && -+ (string[6] == '>')); -+} -+ -+static inline gboolean -+is_primary (const gchar *string) -+{ -+ return ((string[0] == '<') && -+ (string[1] == 'p' || string[1] == 'P') && -+ (string[2] == 'r' || string[2] == 'R') && -+ (string[3] == 'i' || string[3] == 'I') && -+ (string[4] == 'm' || string[4] == 'M') && -+ (string[5] == 'a' || string[5] == 'A') && -+ (string[6] == 'r' || string[6] == 'R') && -+ (string[7] == 'y' || string[7] == 'Y') && -+ (string[8] == '>')); -+} -+ -+static inline gboolean -+is_keycode (const gchar *string) -+{ -+ return (string[0] == '0' && -+ string[1] == 'x' && -+ g_ascii_isxdigit (string[2]) && -+ g_ascii_isxdigit (string[3])); -+} -+ -+/** -+ * ibus_accelerator_parse: -+ * @accelerator: string representing an accelerator -+ * @accelerator_key: (out) (allow-none): return location for accelerator -+ * keyval, or %NULL -+ * @accelerator_mods: (out) (allow-none): return location for accelerator -+ * modifier mask, %NULL -+ * -+ * Parses a string representing an accelerator. The format looks like -+ * “a” or “F1” or “z” (the last one is -+ * for key release). -+ * -+ * The parser is fairly liberal and allows lower or upper case, and also -+ * abbreviations such as “” and “”. Key names are parsed using -+ * gdk_keyval_from_name(). For character keys the name is not the symbol, -+ * but the lowercase name, e.g. one would use “minus” instead of -+ * “-”. -+ * -+ * If the parse fails, @accelerator_key and @accelerator_mods will -+ * be set to 0 (zero). -+ * -+ * Since: 1.5.18 -+ */ -+void -+ibus_accelerator_parse (const gchar *accelerator, -+ guint *accelerator_key, -+ IBusModifierType *accelerator_mods) -+{ -+ guint keyval; -+ IBusModifierType mods; -+ gint len; -+ gboolean error; -+ -+ if (accelerator_key) -+ *accelerator_key = 0; -+ if (accelerator_mods) -+ *accelerator_mods = 0; -+ g_return_if_fail (accelerator != NULL); -+ -+ error = FALSE; -+ keyval = 0; -+ mods = 0; -+ len = strlen (accelerator); -+ while (len) { -+ if (*accelerator == '<') { -+ if (len >= 9 && is_release (accelerator)) { -+ accelerator += 9; -+ len -= 9; -+ mods |= IBUS_RELEASE_MASK; -+ } else if (len >= 9 && is_primary (accelerator)) { -+ accelerator += 9; -+ len -= 9; -+ mods |= _IBUS_GET_PRIMARY_ACCEL_MOD; -+ } else if (len >= 9 && is_control (accelerator)) { -+ accelerator += 9; -+ len -= 9; -+ mods |= IBUS_CONTROL_MASK; -+ } else if (len >= 7 && is_shift (accelerator)) { -+ accelerator += 7; -+ len -= 7; -+ mods |= IBUS_SHIFT_MASK; -+ } else if (len >= 6 && is_shft (accelerator)) { -+ accelerator += 6; -+ len -= 6; -+ mods |= IBUS_SHIFT_MASK; -+ } else if (len >= 6 && is_ctrl (accelerator)) { -+ accelerator += 6; -+ len -= 6; -+ mods |= IBUS_CONTROL_MASK; -+ } else if (len >= 6 && is_modx (accelerator)) { -+ static const guint mod_vals[] = { -+ IBUS_MOD1_MASK, IBUS_MOD2_MASK, IBUS_MOD3_MASK, -+ IBUS_MOD4_MASK, IBUS_MOD5_MASK -+ }; -+ -+ len -= 6; -+ accelerator += 4; -+ mods |= mod_vals[*accelerator - '1']; -+ accelerator += 2; -+ } else if (len >= 5 && is_ctl (accelerator)) { -+ accelerator += 5; -+ len -= 5; -+ mods |= IBUS_CONTROL_MASK; -+ } else if (len >= 5 && is_alt (accelerator)) { -+ accelerator += 5; -+ len -= 5; -+ mods |= IBUS_MOD1_MASK; -+ } else if (len >= 6 && is_meta (accelerator)) { -+ accelerator += 6; -+ len -= 6; -+ mods |= IBUS_META_MASK; -+ } else if (len >= 7 && is_hyper (accelerator)) { -+ accelerator += 7; -+ len -= 7; -+ mods |= IBUS_HYPER_MASK; -+ } else if (len >= 7 && is_super (accelerator)) { -+ accelerator += 7; -+ len -= 7; -+ mods |= IBUS_SUPER_MASK; -+ } else { -+ gchar last_ch; -+ -+ last_ch = *accelerator; -+ while (last_ch && last_ch != '>') { -+ last_ch = *accelerator; -+ accelerator += 1; -+ len -= 1; -+ } -+ } -+ } else { -+ if (len >= 4 && is_keycode (accelerator)) { -+ /* There was a keycode in the string, but -+ * we cannot store it, so we have an error */ -+ error = TRUE; -+ goto out; -+ } else { -+ keyval = ibus_keyval_from_name (accelerator); -+ if (keyval == IBUS_KEY_VoidSymbol) { -+ error = TRUE; -+ goto out; -+ } -+ } -+ -+ accelerator += len; -+ len -= len; -+ } -+ } -+ -+out: -+ if (error) -+ keyval = mods = 0; -+ -+ if (accelerator_key) -+ *accelerator_key = ibus_keyval_to_lower (keyval); -+ if (accelerator_mods) -+ *accelerator_mods = mods; -+} -+ -+/** -+ * ibus_accelerator_name: -+ * @accelerator_key: accelerator keyval -+ * @accelerator_mods: accelerator modifier mask -+ * -+ * Converts an accelerator keyval and modifier mask into a string -+ * parseable by gtk_accelerator_parse(). For example, if you pass in -+ * #IBUS_KEY_q and #IBUS_CONTROL_MASK, this function returns “q”. -+ * -+ * If you need to display accelerators in the user interface, -+ * see gtk_accelerator_get_label(). -+ * -+ * Returns: a newly-allocated accelerator name -+ */ -+gchar* -+ibus_accelerator_name (guint accelerator_key, -+ IBusModifierType accelerator_mods) -+{ -+ static const gchar text_release[] = ""; -+ static const gchar text_primary[] = ""; -+ static const gchar text_shift[] = ""; -+ static const gchar text_control[] = ""; -+ static const gchar text_mod1[] = ""; -+ static const gchar text_mod2[] = ""; -+ static const gchar text_mod3[] = ""; -+ static const gchar text_mod4[] = ""; -+ static const gchar text_mod5[] = ""; -+ static const gchar text_meta[] = ""; -+ static const gchar text_super[] = ""; -+ static const gchar text_hyper[] = ""; -+ IBusModifierType saved_mods; -+ guint l; -+ const gchar *keyval_name; -+ gchar *accelerator; -+ -+ accelerator_mods &= IBUS_MODIFIER_MASK; -+ -+ keyval_name = ibus_keyval_name (ibus_keyval_to_lower (accelerator_key)); -+ if (!keyval_name) -+ keyval_name = ""; -+ -+ saved_mods = accelerator_mods; -+ l = 0; -+ if (accelerator_mods & IBUS_RELEASE_MASK) -+ l += sizeof (text_release) - 1; -+ if (accelerator_mods & _IBUS_GET_PRIMARY_ACCEL_MOD) { -+ l += sizeof (text_primary) - 1; -+ /* consume the default accel */ -+ accelerator_mods &= ~_IBUS_GET_PRIMARY_ACCEL_MOD; -+ } -+ if (accelerator_mods & IBUS_SHIFT_MASK) -+ l += sizeof (text_shift) - 1; -+ if (accelerator_mods & IBUS_CONTROL_MASK) -+ l += sizeof (text_control) - 1; -+ if (accelerator_mods & IBUS_MOD1_MASK) -+ l += sizeof (text_mod1) - 1; -+ if (accelerator_mods & IBUS_MOD2_MASK) -+ l += sizeof (text_mod2) - 1; -+ if (accelerator_mods & IBUS_MOD3_MASK) -+ l += sizeof (text_mod3) - 1; -+ if (accelerator_mods & IBUS_MOD4_MASK) -+ l += sizeof (text_mod4) - 1; -+ if (accelerator_mods & IBUS_MOD5_MASK) -+ l += sizeof (text_mod5) - 1; -+ l += strlen (keyval_name); -+ if (accelerator_mods & IBUS_META_MASK) -+ l += sizeof (text_meta) - 1; -+ if (accelerator_mods & IBUS_HYPER_MASK) -+ l += sizeof (text_hyper) - 1; -+ if (accelerator_mods & IBUS_SUPER_MASK) -+ l += sizeof (text_super) - 1; -+ -+ accelerator = g_new (gchar, l + 1); -+ -+ accelerator_mods = saved_mods; -+ l = 0; -+ accelerator[l] = 0; -+ if (accelerator_mods & IBUS_RELEASE_MASK) { -+ strcpy (accelerator + l, text_release); -+ l += sizeof (text_release) - 1; -+ } -+ if (accelerator_mods & _IBUS_GET_PRIMARY_ACCEL_MOD) { -+ strcpy (accelerator + l, text_primary); -+ l += sizeof (text_primary) - 1; -+ /* consume the default accel */ -+ accelerator_mods &= ~_IBUS_GET_PRIMARY_ACCEL_MOD; -+ } -+ if (accelerator_mods & IBUS_SHIFT_MASK) { -+ strcpy (accelerator + l, text_shift); -+ l += sizeof (text_shift) - 1; -+ } -+ if (accelerator_mods & IBUS_CONTROL_MASK) { -+ strcpy (accelerator + l, text_control); -+ l += sizeof (text_control) - 1; -+ } -+ if (accelerator_mods & IBUS_MOD1_MASK) { -+ strcpy (accelerator + l, text_mod1); -+ l += sizeof (text_mod1) - 1; -+ } -+ if (accelerator_mods & IBUS_MOD2_MASK) { -+ strcpy (accelerator + l, text_mod2); -+ l += sizeof (text_mod2) - 1; -+ } -+ if (accelerator_mods & IBUS_MOD3_MASK) { -+ strcpy (accelerator + l, text_mod3); -+ l += sizeof (text_mod3) - 1; -+ } -+ if (accelerator_mods & IBUS_MOD4_MASK) { -+ strcpy (accelerator + l, text_mod4); -+ l += sizeof (text_mod4) - 1; -+ } -+ if (accelerator_mods & IBUS_MOD5_MASK) { -+ strcpy (accelerator + l, text_mod5); -+ l += sizeof (text_mod5) - 1; -+ } -+ if (accelerator_mods & IBUS_META_MASK) { -+ strcpy (accelerator + l, text_meta); -+ l += sizeof (text_meta) - 1; -+ } -+ if (accelerator_mods & IBUS_HYPER_MASK) { -+ strcpy (accelerator + l, text_hyper); -+ l += sizeof (text_hyper) - 1; -+ } -+ if (accelerator_mods & IBUS_SUPER_MASK) { -+ strcpy (accelerator + l, text_super); -+ l += sizeof (text_super) - 1; -+ } -+ strcpy (accelerator + l, keyval_name); -+ -+ return accelerator; -+} -diff --git a/src/ibusaccelgroup.h b/src/ibusaccelgroup.h -new file mode 100644 -index 00000000..cb38bee4 ---- /dev/null -+++ b/src/ibusaccelgroup.h -@@ -0,0 +1,51 @@ -+/* GTK - The GIMP Toolkit -+ * Copyright (C) 1998, 2001 Tim Janik -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ */ -+ -+/* -+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS -+ * file for a list of people on the GTK+ Team. See the ChangeLog -+ * files for a list of changes. These files are distributed with -+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. -+ */ -+ -+#ifndef __IBUS_ACCEL_GROUP_H_ -+#define __IBUS_ACCEL_GROUP_H_ -+ -+ -+#if !defined (__IBUS_H_INSIDE__) && !defined (IBUS_COMPILATION) -+#error "Only can be included directly" -+#endif -+ -+#include -+#include -+ -+G_BEGIN_DECLS -+ -+ -+/* --- Accelerators--- */ -+gboolean ibus_accelerator_valid (guint keyval, -+ IBusModifierType modifiers) -+ G_GNUC_CONST; -+void ibus_accelerator_parse (const gchar *accelerator, -+ guint *accelerator_key, -+ IBusModifierType *accelerator_mods); -+gchar* ibus_accelerator_name (guint accelerator_key, -+ IBusModifierType accelerator_mods); -+ -+G_END_DECLS -+ -+#endif /* __IBUS_ACCEL_GROUP_H_ */ -diff --git a/src/ibusengine.c b/src/ibusengine.c -index da648d11..9a0b1a8a 100644 ---- a/src/ibusengine.c -+++ b/src/ibusengine.c -@@ -20,12 +20,16 @@ - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ --#include "ibusengine.h" - #include - #include -+ -+#include "ibusaccelgroup.h" -+#include "ibusengine.h" -+#include "ibuskeysyms.h" - #include "ibusmarshalers.h" - #include "ibusinternal.h" - #include "ibusshare.h" -+#include "ibusxevent.h" - - #define IBUS_ENGINE_GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_ENGINE, IBusEnginePrivate)) -@@ -60,6 +64,8 @@ enum { - }; - - -+typedef struct _IBusEngineKeybinding IBusEngineKeybinding; -+ - /* IBusEnginePriv */ - struct _IBusEnginePrivate { - gchar *engine_name; -@@ -74,11 +80,19 @@ struct _IBusEnginePrivate { - /* cached content-type */ - guint content_purpose; - guint content_hints; -+ -+ GSettings *settings_emoji; -+ IBusEngineKeybinding **emoji_keybindings; -+}; -+ -+struct _IBusEngineKeybinding { -+ guint keyval; -+ IBusModifierType modifiers; - }; - - static guint engine_signals[LAST_SIGNAL] = { 0 }; - --static IBusText *text_empty = NULL; -+static IBusText *text_empty; - - /* functions prototype */ - static void ibus_engine_destroy (IBusEngine *engine); -@@ -176,6 +190,11 @@ static void ibus_engine_dbus_property_changed - (IBusEngine *engine, - const gchar *property_name, - GVariant *value); -+static void ibus_engine_keybinding_free (IBusEngine *engine); -+static void settings_emoji_hotkey_changed_cb -+ (GSettings *settings, -+ const gchar *key, -+ gpointer data); - - - G_DEFINE_TYPE (IBusEngine, ibus_engine, IBUS_TYPE_SERVICE) -@@ -263,11 +282,27 @@ static const gchar introspection_xml[] = - " " - " " - " " -+ " " -+ " " -+ " " - /* FIXME properties */ - " " - " " - ""; - -+static const guint IBUS_MODIFIER_FILTER = -+ IBUS_MODIFIER_MASK & ~( -+ IBUS_LOCK_MASK | /* Caps Lock */ -+ IBUS_MOD2_MASK | /* Num Lock */ -+ IBUS_BUTTON1_MASK | -+ IBUS_BUTTON2_MASK | -+ IBUS_BUTTON3_MASK | -+ IBUS_BUTTON4_MASK | -+ IBUS_BUTTON5_MASK | -+ IBUS_SUPER_MASK | -+ IBUS_HYPER_MASK | -+ IBUS_META_MASK); -+ - static void - ibus_engine_class_init (IBusEngineClass *class) - { -@@ -802,9 +837,15 @@ ibus_engine_class_init (IBusEngineClass *class) - static void - ibus_engine_init (IBusEngine *engine) - { -- engine->priv = IBUS_ENGINE_GET_PRIVATE (engine); -- -- engine->priv->surrounding_text = g_object_ref_sink (text_empty); -+ IBusEnginePrivate *priv; -+ engine->priv = priv = IBUS_ENGINE_GET_PRIVATE (engine); -+ -+ priv->surrounding_text = g_object_ref_sink (text_empty); -+ priv->settings_emoji = -+ g_settings_new ("org.freedesktop.ibus.panel.emoji"); -+ settings_emoji_hotkey_changed_cb (priv->settings_emoji, "hotkey", engine); -+ g_signal_connect (priv->settings_emoji, "changed::hotkey", -+ G_CALLBACK (settings_emoji_hotkey_changed_cb), engine); - } - - static void -@@ -817,6 +858,7 @@ ibus_engine_destroy (IBusEngine *engine) - g_object_unref (engine->priv->surrounding_text); - engine->priv->surrounding_text = NULL; - } -+ ibus_engine_keybinding_free (engine); - - IBUS_OBJECT_CLASS(ibus_engine_parent_class)->destroy (IBUS_OBJECT (engine)); - } -@@ -852,6 +894,53 @@ ibus_engine_get_property (IBusEngine *engine, - } - } - -+static void -+ibus_engine_panel_extension (IBusEngine *engine) -+{ -+ IBusXEvent *xevent = ibus_x_event_new ( -+ "event-type", IBUS_X_EVENT_KEY_PRESS, -+ "purpose", "emoji", -+ NULL); -+ GVariant *data = ibus_serializable_serialize_object ( -+ IBUS_SERIALIZABLE (xevent)); -+ -+ g_assert (data != NULL); -+ ibus_engine_emit_signal (engine, -+ "PanelExtension", -+ g_variant_new ("(v)", data)); -+} -+ -+static gboolean -+ibus_engine_filter_key_event (IBusEngine *engine, -+ guint keyval, -+ guint keycode, -+ guint state) -+{ -+ IBusEnginePrivate *priv; -+ int i; -+ guint modifiers; -+ -+ if ((state & IBUS_RELEASE_MASK) != 0) -+ return FALSE; -+ g_return_val_if_fail (IBUS_IS_ENGINE (engine), FALSE); -+ -+ priv = engine->priv; -+ modifiers = state & IBUS_MODIFIER_FILTER; -+ if (keyval >= IBUS_KEY_A && keyval <= IBUS_KEY_Z && -+ (modifiers & IBUS_SHIFT_MASK) != 0) { -+ keyval = keyval - IBUS_KEY_A + IBUS_KEY_a; -+ } -+ for (i = 0; priv->emoji_keybindings[i]; i++) { -+ IBusEngineKeybinding *binding = priv->emoji_keybindings[i]; -+ if (binding->keyval == keyval && -+ binding->modifiers == modifiers) { -+ ibus_engine_panel_extension (engine); -+ return TRUE; -+ } -+ } -+ return FALSE; -+} -+ - static gboolean - ibus_engine_service_authorized_method (IBusService *service, - GDBusConnection *connection) -@@ -892,6 +981,7 @@ ibus_engine_service_method_call (IBusService *service, - if (g_strcmp0 (method_name, "ProcessKeyEvent") == 0) { - guint keyval, keycode, state; - gboolean retval = FALSE; -+ - g_variant_get (parameters, "(uuu)", &keyval, &keycode, &state); - g_signal_emit (engine, - engine_signals[PROCESS_KEY_EVENT], -@@ -900,6 +990,12 @@ ibus_engine_service_method_call (IBusService *service, - keycode, - state, - &retval); -+ if (!retval) { -+ retval = ibus_engine_filter_key_event (engine, -+ keyval, -+ keycode, -+ state); -+ } - g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", retval)); - return; - } -@@ -1338,6 +1434,79 @@ ibus_engine_dbus_property_changed (IBusEngine *engine, - g_object_unref (message); - } - -+static void -+ibus_engine_keybinding_free (IBusEngine *engine) -+{ -+ IBusEnginePrivate *priv; -+ int i; -+ -+ g_return_if_fail (IBUS_IS_ENGINE (engine)); -+ -+ priv = engine->priv; -+ if (priv->emoji_keybindings) { -+ for (i = 0; priv->emoji_keybindings[i]; i++) -+ g_slice_free (IBusEngineKeybinding, priv->emoji_keybindings[i]); -+ g_clear_pointer (&priv->emoji_keybindings, g_free); -+ } -+} -+ -+static IBusEngineKeybinding * -+ibus_engine_keybinding_new (IBusEngine *engine, -+ const gchar *accelerator) -+{ -+ guint keyval = 0U; -+ IBusModifierType modifiers = 0; -+ IBusEngineKeybinding *binding = NULL; -+ -+ ibus_accelerator_parse (accelerator, &keyval, &modifiers); -+ if (keyval == 0U && modifiers == 0) { -+ g_warning ("Failed to parse shortcut key '%s'", accelerator); -+ return NULL; -+ } -+ if (modifiers & IBUS_SUPER_MASK) { -+ modifiers^=IBUS_SUPER_MASK; -+ modifiers|=IBUS_MOD4_MASK; -+ } -+ -+ binding = g_slice_new0 (IBusEngineKeybinding); -+ binding->keyval = keyval; -+ binding->modifiers = modifiers; -+ return binding; -+} -+ -+static void -+settings_emoji_hotkey_changed_cb (GSettings *settings, -+ const gchar *key, -+ gpointer data) -+{ -+ IBusEngine *engine; -+ IBusEnginePrivate *priv; -+ gchar **accelerators; -+ int i, j, length; -+ g_return_if_fail (IBUS_IS_ENGINE (data)); -+ engine = IBUS_ENGINE (data); -+ priv = engine->priv; -+ -+ if (g_strcmp0 (key, "hotkey") != 0) -+ return; -+ accelerators = g_settings_get_strv (settings, key); -+ length = g_strv_length (accelerators); -+ ibus_engine_keybinding_free (engine); -+ if (length == 0) { -+ g_strfreev (accelerators); -+ return; -+ } -+ priv->emoji_keybindings = g_new0 (IBusEngineKeybinding*, length + 1); -+ for (i = 0, j = 0; i < length; i++) { -+ IBusEngineKeybinding *binding = -+ ibus_engine_keybinding_new (engine, accelerators[i]); -+ if (!binding) -+ continue; -+ priv->emoji_keybindings[j++] = binding; -+ } -+ g_strfreev (accelerators); -+} -+ - IBusEngine * - ibus_engine_new (const gchar *engine_name, - const gchar *object_path, -diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala -index c85dfa86..8217a000 100644 ---- a/ui/gtk3/emojier.vala -+++ b/ui/gtk3/emojier.vala -@@ -2062,6 +2062,7 @@ public class IBusEmojier : Gtk.ApplicationWindow { - // Do not hide a bottom panel in XFCE4 - if (work_area.y < y) - y = work_area.y; -+ // FIXME: move() does not work in Wayland - move(x, y); - - uint32 timestamp = event.get_time(); -diff --git a/ui/gtk3/extension.vala b/ui/gtk3/extension.vala -index a170280b..03026d00 100644 ---- a/ui/gtk3/extension.vala -+++ b/ui/gtk3/extension.vala -@@ -115,8 +115,9 @@ class ExtensionGtk { - // and Ctrl-Shift-e when ibus-ui-gtk3 runs after the - // desktop is launched. - GLib.Environment.unset_variable("GDK_CORE_DEVICE_EVENTS"); -- // for Gdk.X11.get_default_xdisplay() -- Gdk.set_allowed_backends("x11"); -+ // Gdk.set_allowed_backends("x11") let present_with_time() failed on -+ // launching the dialog secondly in Wayland. -+ //Gdk.set_allowed_backends("x11"); - - ExtensionGtk extension = new ExtensionGtk(argv); - extension.run(); -diff --git a/ui/gtk3/panelbinding.vala b/ui/gtk3/panelbinding.vala -index 1fbf6cfc..e3f39e12 100644 ---- a/ui/gtk3/panelbinding.vala -+++ b/ui/gtk3/panelbinding.vala -@@ -33,8 +33,6 @@ class PanelBinding : IBus.PanelService { - private string[] m_emojier_favorites = {}; - private Gtk.CssProvider m_css_provider; - private const uint PRELOAD_ENGINES_DELAY_TIME = 30000; -- private GLib.List m_keybindings = -- new GLib.List(); - private bool m_load_emoji_at_startup; - private bool m_loaded_emoji = false; - private bool m_load_unicode_at_startup; -@@ -49,15 +47,6 @@ class PanelBinding : IBus.PanelService { - m_bus = bus; - - init_settings(); -- -- bind_emoji_shortcut(); -- } -- -- -- ~PanelBinding() { -- BindingCommon.unbind_switch_shortcut( -- BindingCommon.KeyEventFuncType.ANY, -- m_keybindings); - } - - -@@ -77,13 +66,6 @@ class PanelBinding : IBus.PanelService { - ref m_css_provider); - }); - -- m_settings_emoji.changed["hotkey"].connect((key) => { -- BindingCommon.unbind_switch_shortcut( -- BindingCommon.KeyEventFuncType.EMOJI_TYPING, -- m_keybindings); -- bind_emoji_shortcut(); -- }); -- - m_settings_emoji.changed["font"].connect((key) => { - BindingCommon.set_custom_font(m_settings_panel, - m_settings_emoji, -@@ -124,25 +106,6 @@ class PanelBinding : IBus.PanelService { - } - - -- private void bind_emoji_shortcut() { --#if EMOJI_DICT -- string[] accelerators = m_settings_emoji.get_strv("hotkey"); -- -- var keybinding_manager = KeybindingManager.get_instance(); -- -- foreach (var accelerator in accelerators) { -- BindingCommon.keybinding_manager_bind( -- keybinding_manager, -- ref m_keybindings, -- accelerator, -- BindingCommon.KeyEventFuncType.EMOJI_TYPING, -- handle_emoji_typing, -- null); -- } --#endif -- } -- -- - private void set_emoji_favorites() { - m_emojier_favorites = m_settings_emoji.get_strv("favorites"); - IBusEmojier.set_favorites( -@@ -195,9 +158,6 @@ class PanelBinding : IBus.PanelService { - - set_load_emoji_at_startup(); - set_load_unicode_at_startup(); -- BindingCommon.unbind_switch_shortcut(BindingCommon.KeyEventFuncType.ANY, -- m_keybindings); -- bind_emoji_shortcut(); - BindingCommon.set_custom_font(m_settings_panel, - m_settings_emoji, - ref m_css_provider); -@@ -354,19 +314,26 @@ class PanelBinding : IBus.PanelService { - return; - } - Gdk.Event event = new Gdk.Event(event_type); -- event.key.time = xevent.get_time(); -- Gdk.Display? display = Gdk.Display.get_default(); -+ uint32 time = xevent.get_time(); -+ if (time == 0) -+ time = Gtk.get_current_event_time(); -+ event.key.time = time; - X.Window xid = xevent.get_window(); -- Gdk.X11.Window window; -- window = Gdk.X11.Window.lookup_for_display( -- display as Gdk.X11.Display, xid); -- if (window != null) { -- event.key.window = window; -- } else { -+ Gdk.Display? display = Gdk.Display.get_default(); -+ Gdk.Window? window = null; -+ if (window == null && xid != 0) { -+ window = Gdk.X11.Window.lookup_for_display( -+ display as Gdk.X11.Display, xid); -+ } -+ if (window == null && xid != 0) { - window = new Gdk.X11.Window.foreign_for_display( - display as Gdk.X11.Display, xid); -- event.key.window = window; - } -+ if (window == null) { -+ window = Gdk.get_default_root_window(); -+ window.ref(); -+ } -+ event.key.window = window; - handle_emoji_typing(event); - } - } --- -2.14.3 -