public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/ibus] autotool: Removed ibus-HEAD.patch
@ 2026-05-31 2:06 Takao Fujiwara
0 siblings, 0 replies; only message in thread
From: Takao Fujiwara @ 2026-05-31 2:06 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/ibus
Branch : autotool
Commit : d6bf0e42b2c6515f33cd3f8dc621431b277a9fb1
Author : Takao Fujiwara <tfujiwar@redhat.com>
Date : 2018-03-02T17:34:59+09:00
Stats : +0/-10021 in 1 file(s)
URL : https://src.fedoraproject.org/rpms/ibus/c/d6bf0e42b2c6515f33cd3f8dc621431b277a9fb1?branch=autotool
Log:
Removed 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 <takao.fujiwara1@gmail.com>
-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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2015-2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * Copyright (C) 2015-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
- * 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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2008-2013 Red Hat, Inc.
-+ * Copyright (C) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * 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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * Copyright (C) 2017-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
- *
- * 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 <takao.fujiwara1@gmail.com>
-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 <shawn.p.huang@gmail.com>
--# Copyright (c) 2015-2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
--# Copyright (c) 2007-2017 Red Hat, Inc.
-+# Copyright (c) 2015-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+# 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 <takao.fujiwara1@gmail.com>
-+ * Copyright (C) 2016-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
- * 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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2008-2013 Red Hat, Inc.
-+ * Copyright (C) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * 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 <ibusutil.h>
- #include <ibusregistry.h>
- #include <ibusemoji.h>
-+#include <ibusunicode.h>
-
- #ifndef IBUS_DISABLE_DEPRECATED
- #include <ibuskeysyms-compat.h>
-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 <takao.fujiwara1@gmail.com>
-+ * 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 <config.h>
-+#endif
-+
-+#include <glib.h>
-+#include <glib/gstdio.h>
-+#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 <takao.fujiwara1@gmail.com>
-+ * 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 <ibus.h> 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 <gio/gio.h>
-+#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 <takao.fujiwara1@gmail.com>
-+ * 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 <glib/gi18n.h>
-+
-+#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 <takao.fujiwara1@gmail.com>
-+ * 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 <config.h>
-+#endif
-+
-+#include <glib.h>
-+#include <stdlib.h>
-+#include <string.h>
-+
-+#ifdef HAVE_LOCALE_H
-+#include <locale.h>
-+#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 <glib/gi18n.h>\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 <takao.fujiwara1@gmail.com>
-+ * Copyright (c) 2017-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
- *
- * 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<string, GLib.SList<string>>?
- m_annotation_to_emojis_dict;
- private static GLib.HashTable<string, IBus.EmojiData>?
-@@ -231,6 +299,14 @@ class IBusEmojier : Gtk.ApplicationWindow {
- m_category_to_emojis_dict;
- private static GLib.HashTable<string, GLib.SList<string>>?
- m_emoji_to_emoji_variants_dict;
-+ private static GLib.HashTable<unichar, IBus.UnicodeData>?
-+ m_unicode_to_data_dict;
-+ private static GLib.HashTable<string, GLib.SList<unichar>>?
-+ m_name_to_unicodes_dict;
-+ private static GLib.SList<IBus.UnicodeBlock> 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<string, GLib.SList<string>>(GLib.str_hash,
- GLib.str_equal);
-+ m_unicode_to_data_dict =
-+ new GLib.HashTable<unichar, IBus.UnicodeData>(
-+ GLib.direct_hash,
-+ GLib.direct_equal);
-+ m_name_to_unicodes_dict =
-+ new GLib.HashTable<string, GLib.SList<unichar>>(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<IBus.UnicodeData> 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<unowned string> 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<unichar> 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<unowned string> 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<string>? total_emojis = null;
- unowned GLib.SList<string>? sub_emojis = null;
-+ unowned GLib.SList<unichar>? 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<unowned string>? 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<unowned string>? 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<weak Gtk.Widget> 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 <takao.fujiwara1@gmail.com>
-+ * Copyright (C) 2017-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
- * 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 <shawn.p.huang@gmail.com>
-- * Copyright(c) 2015-2017 Takao Fujwiara <takao.fujiwara1@gmail.com>
-+ * Copyright(c) 2015-2018 Takao Fujwiara <takao.fujiwara1@gmail.com>
- *
- * 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 <takao.fujiwara1@gmail.com>
-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 <takao.fujiwara1@gmail.com>
-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 <shawn.p.huang@gmail.com>
--# Copyright (c) 2007-2013 Red Hat, Inc.
-+# Copyright (c) 2013-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+# 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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2008-2013 Red Hat, Inc.
-+ * Copyright (C) 2011-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * 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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2008-2013 Red Hat, Inc.
-+ * Copyright (C) 2013-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * 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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
-- * Copyright (C) 2008-2014 Red Hat, Inc.
-+ * Copyright (C) 2017-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * 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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2008-2014 Red Hat, Inc.
-+ * Copyright (C) 2017-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * 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 <shawn.p.huang@gmail.com>
--# Copyright (c) 2015-2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+# Copyright (c) 2015-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
- # 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 <ibusregistry.h>
- #include <ibusemoji.h>
- #include <ibusunicode.h>
-+#include <ibusxevent.h>
-
- #ifndef IBUS_DISABLE_DEPRECATED
- #include <ibuskeysyms-compat.h>
-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[] =
- " <arg direction='in' type='u' name='purpose' />"
- " <arg direction='in' type='u' name='hints' />"
- " </method>"
-+ " <method name='PanelExtensionReceived'>"
-+ " <arg direction='in' type='v' name='data' />"
-+ " </method>"
- /* Signals */
- " <signal name='CursorUp' />"
- " <signal name='CursorDown' />"
-@@ -235,6 +246,9 @@ static const gchar introspection_xml[] =
- " <signal name='CommitText'>"
- " <arg type='v' name='text' />"
- " </signal>"
-+ " <signal name='PanelExtension'>"
-+ " <arg type='v' name='data' />"
-+ " </signal>"
- " </interface>"
- "</node>";
-
-@@ -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.
-+ *
-+ * <note><para>Argument @user_data is ignored in this function.</para>
-+ * </note>
-+ */
-+ 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 <takao.fujiwara1@gmail.com>
-+ * Copyright (c) 2017-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
- *
- * 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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2008-2010 Red Hat, Inc.
-+ * Copyright (C) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * 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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2008-2013 Red Hat, Inc.
-+ * Copyright (C) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * 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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2008-2010 Red Hat, Inc.
-+ * Copyright (C) 2015-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * 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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2008-2013 Red Hat, Inc.
-+ * Copyright (C) 2015-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * 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 <takao.fujiwara1@gmail.com>
-+ * 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 <takao.fujiwara1@gmail.com>
-+ * 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 <ibus.h> 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 <shawn.p.huang@gmail.com>
--# Copyright (c) 2015-2017 Takao Fujwiara <takao.fujiwara1@gmail.com>
--# Copyright (c) 2007-2017 Red Hat, Inc.
-+# Copyright (c) 2015-2018 Takao Fujwiara <takao.fujiwara1@gmail.com>
-+# 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 <shawn.p.huang@gmail.com>
-+ * Copyright(c) 2018 Takao Fujwiara <takao.fujiwara1@gmail.com>
-+ *
-+ * 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<Keybinding> 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<Keybinding> 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 <shawn.p.huang@gmail.com>
-+ * Copyright(c) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ *
-+ * 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 @@
-+<?xml version="1.0" encoding="utf-8"?>
-+<!-- filename: gtkextension.xml -->
-+<component>
-+ <name>org.freedesktop.IBus.Panel.Extension</name>
-+ <description>Gtk Panel Extension Component</description>
-+ <exec>@libexecdir@/ibus-extension-gtk3</exec>
-+ <version>@VERSION@</version>
-+ <author>Takao Fujiwara <takao.fujiwara1@gmail.com></author>
-+ <license>GPL</license>
-+ <homepage>https://github.com/ibus/ibus/wiki</homepage>
-+ <textdomain>ibus</textdomain>
-+</component>
-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 <shawn.p.huang@gmail.com>
-+ * Copyright(c) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
- *
- * 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<Keybinding> m_keybindings = new GLib.List<Keybinding>();
-+ private GLib.List<BindingCommon.Keybinding> m_keybindings =
-+ new GLib.List<BindingCommon.Keybinding>();
-
- 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<Keybinding> keybindings) {
- var keybinding_manager = KeybindingManager.get_instance();
-
-- unowned GLib.List<Keybinding> 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 <shawn.p.huang@gmail.com>
-+ * Copyright(c) 2018 Takao Fujwiara <takao.fujiwara1@gmail.com>
-+ *
-+ * 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<BindingCommon.Keybinding> m_keybindings =
-+ new GLib.List<BindingCommon.Keybinding>();
-+
-+ 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?= <piotrdrag@gmail.com>
-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 <piotrdrag@gmail.com>.
----
- 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 @@
- <default>[ara,bg,cz,dev,gr,gur,in,jp(kana),mal,mkd,ru,ua]</default>
- <locale name="C">
- <short>Latin layouts which have no ASCII</short>
-- <long>US layout is appended to the latin layouts. variant can be
-+ <long>US layout is appended to the Latin layouts. variant can be
- omitted.
- </long>
- </locale>
-@@ -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.</long>
- </locale>
-@@ -373,7 +373,7 @@
- <default>Monospace 16</default>
- <locale name="C">
- <short>Custom font</short>
-- <long>Custom font name for emoji chracters on emoji dialog</long>
-+ <long>Custom font name for emoji characters on emoji dialog</long>
- </locale>
- </schema>
- <schema>
-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 <takao.fujiwara1@gmail.com>
-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 <takao.fujiwara1@gmail.com>
-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 @@
- </long>
- </locale>
- </schema>
-+ <schema>
-+ <key>/schemas/desktop/ibus/panel/emoji/load-emoji-at-startup</key>
-+ <applyto>/desktop/ibus/panel/emoji/load-emoji-at-startup</applyto>
-+ <owner>ibus</owner>
-+ <type>bool</type>
-+ <default>true</default>
-+ <locale name="C">
-+ <short>Load the emoji data at the time of startup</short>
-+ <long>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.
-+ </long>
-+ </locale>
-+ </schema>
-+ <schema>
-+ <key>/schemas/desktop/ibus/panel/emoji/load-unicode-at-startup</key>
-+ <applyto>/desktop/ibus/panel/emoji/load-unicode-at-startup</applyto>
-+ <owner>ibus</owner>
-+ <type>bool</type>
-+ <default>false</default>
-+ <locale name="C">
-+ <short>Load the Unicode data at the time of startup</short>
-+ <long>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.
-+ </long>
-+ </locale>
-+ </schema>
- <schema>
- <key>/schemas/desktop/ibus/general/embed_preedit_text</key>
- <applyto>/desktop/ibus/general/embed_preedit_text</applyto>
-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<BindingCommon.Keybinding> m_keybindings =
- new GLib.List<BindingCommon.Keybinding>();
-+ 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 <takao.fujiwara1@gmail.com>
-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 <takao.fujiwara1@gmail.com>
-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 <shawn.p.huang@gmail.com>
-- * Copyright (C) 2015-2016 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * Copyright (C) 2015-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
- * 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 <ibusemoji.h>
- #include <ibusunicode.h>
- #include <ibusxevent.h>
-+#include <ibusaccelgroup.h>
-
- #ifndef IBUS_DISABLE_DEPRECATED
- #include <ibuskeysyms-compat.h>
-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 <http://www.gnu.org/licenses/>.
-+ */
-+
-+/*
-+ * 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 <string.h>
-+#include <stdlib.h>
-+
-+#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
-+ * “<Control>a” or “<Shift><Alt>F1” or “<Release>z” (the last one is
-+ * for key release).
-+ *
-+ * The parser is fairly liberal and allows lower or upper case, and also
-+ * abbreviations such as “<Ctl>” and “<Ctrl>”. 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 “<Ctrl>minus” instead of
-+ * “<Ctrl>-”.
-+ *
-+ * 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 “<Control>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[] = "<Release>";
-+ static const gchar text_primary[] = "<Primary>";
-+ static const gchar text_shift[] = "<Shift>";
-+ static const gchar text_control[] = "<Control>";
-+ static const gchar text_mod1[] = "<Alt>";
-+ static const gchar text_mod2[] = "<Mod2>";
-+ static const gchar text_mod3[] = "<Mod3>";
-+ static const gchar text_mod4[] = "<Mod4>";
-+ static const gchar text_mod5[] = "<Mod5>";
-+ static const gchar text_meta[] = "<Meta>";
-+ static const gchar text_super[] = "<Super>";
-+ static const gchar text_hyper[] = "<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 <http://www.gnu.org/licenses/>.
-+ */
-+
-+/*
-+ * 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 <ibus.h> can be included directly"
-+#endif
-+
-+#include <glib.h>
-+#include <ibustypes.h>
-+
-+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 <stdarg.h>
- #include <string.h>
-+
-+#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[] =
- " <arg type='u' name='keycode' />"
- " <arg type='u' name='state' />"
- " </signal>"
-+ " <signal name='PanelExtension'>"
-+ " <arg type='v' name='data' />"
-+ " </signal>"
- /* FIXME properties */
- " <property name='ContentType' type='(uu)' access='write' />"
- " </interface>"
- "</node>";
-
-+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<BindingCommon.Keybinding> m_keybindings =
-- new GLib.List<BindingCommon.Keybinding>();
- 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
-
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-05-31 2:06 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-31 2:06 [rpms/ibus] autotool: Removed ibus-HEAD.patch Takao Fujiwara
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox