public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Takao Fujiwara <tfujiwar@redhat.com>
To: git-commits@fedoraproject.org
Subject: [rpms/ibus] autotool: Deleted upstreamed patches
Date: Sun, 31 May 2026 02:06:57 GMT	[thread overview]
Message-ID: <178019321700.1.14459109162438851166.rpms-ibus-3032216b57aa@fedoraproject.org> (raw)

A new commit has been pushed.

Repo   : rpms/ibus
Branch : autotool
Commit : 3032216b57aac3d11c9d6323228d7a58a8b309aa
Author : Takao Fujiwara <tfujiwar@redhat.com>
Date   : 2018-08-08T20:07:39+09:00
Stats  : +0/-11241 in 1 file(s)
URL    : https://src.fedoraproject.org/rpms/ibus/c/3032216b57aac3d11c9d6323228d7a58a8b309aa?branch=autotool

Log:
Deleted upstreamed patches

---
diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch
deleted file mode 100644
index 0f9a5c8..0000000
--- a/ibus-HEAD.patch
+++ /dev/null
@@ -1,11241 +0,0 @@
-From c6439d74d5472c95de4d5c2cdc6487bfd508e3d8 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Thu, 15 Mar 2018 16:57:02 +0900
-Subject: [PATCH] ui/gtk3: Add num pad Enter, Down, Up, Left, Right on Emojier
-
-BUG=rhbz#1554813
-R=Shawn.P.Huang@gmail.com
-
-Review URL: https://codereview.appspot.com/337690043
----
- ui/gtk3/emojier.vala | 25 +++++++++++++++++--------
- 1 file changed, 17 insertions(+), 8 deletions(-)
-
-diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala
-index 8707e432..24029703 100644
---- a/ui/gtk3/emojier.vala
-+++ b/ui/gtk3/emojier.vala
-@@ -1918,6 +1918,7 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-                 return true;
-             break;
-         case Gdk.Key.Return:
-+        case Gdk.Key.KP_Enter:
-             key_press_enter();
-             return true;
-         case Gdk.Key.BackSpace:
-@@ -1959,29 +1960,37 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             }
-             return true;
-         case Gdk.Key.Right:
--            key_press_cursor_horizontal(keyval, modifiers);
-+        case Gdk.Key.KP_Right:
-+            key_press_cursor_horizontal(Gdk.Key.Right, modifiers);
-             return true;
-         case Gdk.Key.Left:
--            key_press_cursor_horizontal(keyval, modifiers);
-+        case Gdk.Key.KP_Left:
-+            key_press_cursor_horizontal(Gdk.Key.Left, modifiers);
-             return true;
-         case Gdk.Key.Down:
--            key_press_cursor_vertical(keyval, modifiers);
-+        case Gdk.Key.KP_Down:
-+            key_press_cursor_vertical(Gdk.Key.Down, modifiers);
-             return true;
-         case Gdk.Key.Up:
--            key_press_cursor_vertical(keyval, modifiers);
-+        case Gdk.Key.KP_Up:
-+            key_press_cursor_vertical(Gdk.Key.Up, modifiers);
-             return true;
-         case Gdk.Key.Page_Down:
--            key_press_cursor_vertical(keyval, modifiers);
-+        case Gdk.Key.KP_Page_Down:
-+            key_press_cursor_vertical(Gdk.Key.Page_Down, modifiers);
-             return true;
-         case Gdk.Key.Page_Up:
--            key_press_cursor_vertical(keyval, modifiers);
-+        case Gdk.Key.KP_Page_Up:
-+            key_press_cursor_vertical(Gdk.Key.Page_Up, modifiers);
-             return true;
-         case Gdk.Key.Home:
--            if (key_press_cursor_home_end(keyval, modifiers))
-+        case Gdk.Key.KP_Home:
-+            if (key_press_cursor_home_end(Gdk.Key.Home, modifiers))
-                 return true;
-             break;
-         case Gdk.Key.End:
--            if (key_press_cursor_home_end(keyval, modifiers))
-+        case Gdk.Key.KP_End:
-+            if (key_press_cursor_home_end(Gdk.Key.End, modifiers))
-                 return true;
-             break;
-         case Gdk.Key.Insert:
--- 
-2.14.3
-
-From b184861396279d903e62bf6aad271a2205a79832 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Fri, 30 Mar 2018 12:33:59 +0900
-Subject: [PATCH] ui/gtk3: Sort Unicode candidates
-
-BUG=rhbz#1554714
-R=Shawn.P.Huang@gmail.com
-
-Review URL: https://codereview.appspot.com/339430043
----
- ui/gtk3/emojier.vala | 26 +++++++++++++++++++++++---
- 1 file changed, 23 insertions(+), 3 deletions(-)
-
-diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala
-index 24029703..0c0865f1 100644
---- a/ui/gtk3/emojier.vala
-+++ b/ui/gtk3/emojier.vala
-@@ -1144,9 +1144,11 @@ public 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_exact_unicodes = null;
-         unowned GLib.SList<unichar>? sub_unicodes = null;
-         int length = annotation.length;
-         if (m_has_partial_match && length >= m_partial_match_length) {
-+            GLib.SList<string>? sorted_emojis = null;
-             foreach (unowned string key in
-                      m_annotation_to_emojis_dict.get_keys()) {
-                 if (key.length < length)
-@@ -1173,16 +1175,29 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-                 sub_emojis = m_annotation_to_emojis_dict.lookup(key);
-                 foreach (unowned string emoji in sub_emojis) {
-                     if (total_emojis.find_custom(emoji, GLib.strcmp) == null) {
--                        total_emojis.append(emoji);
-+                        sorted_emojis.insert_sorted(emoji, GLib.strcmp);
-                     }
-                 }
-             }
-+            foreach (string emoji in sorted_emojis) {
-+                if (total_emojis.find_custom(emoji, GLib.strcmp) == null) {
-+                    total_emojis.append(emoji);
-+                }
-+            }
-         } else {
-             sub_emojis = m_annotation_to_emojis_dict.lookup(annotation);
-             foreach (unowned string emoji in sub_emojis)
-                 total_emojis.append(emoji);
-         }
-+        sub_exact_unicodes = m_name_to_unicodes_dict.lookup(annotation);
-+        foreach (unichar code in sub_exact_unicodes) {
-+            string ch = code.to_string();
-+            if (total_emojis.find_custom(ch, GLib.strcmp) == null) {
-+                total_emojis.append(ch);
-+            }
-+        }
-         if (length >= m_partial_match_length) {
-+            GLib.SList<string>? sorted_unicodes = null;
-             foreach (unowned string key in m_name_to_unicodes_dict.get_keys()) {
-                 bool matched = false;
-                 if (key.index_of(annotation) >= 0)
-@@ -1192,11 +1207,16 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-                 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);
-+                    if (sorted_unicodes.find_custom(ch, GLib.strcmp) == null) {
-+                        sorted_unicodes.insert_sorted(ch, GLib.strcmp);
-                     }
-                 }
-             }
-+            foreach (string ch in sorted_unicodes) {
-+                if (total_emojis.find_custom(ch, GLib.strcmp) == null) {
-+                    total_emojis.append(ch);
-+                }
-+            }
-         }
-         return total_emojis;
-     }
--- 
-2.14.3
-
-From 5788be80685f397c3db3bdf4e672d67cfb9b3433 Mon Sep 17 00:00:00 2001
-From: Jeremy Bicha <jbicha@ubuntu.com>
-Date: Fri, 30 Mar 2018 12:37:27 +0900
-Subject: [PATCH] Fix ucd directory override
-
-BUG=https://github.com/ibus/ibus/pull/1995
-R=Shawn.P.Huang@gmail.com
-
-Review URL: https://codereview.appspot.com/339450043
-
-Patch from Jeremy Bicha <jbicha@ubuntu.com>.
----
- configure.ac | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/configure.ac b/configure.ac
-index 6c00803f..d19aa874 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -666,7 +666,7 @@ 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=$with_ucd_dir,
-     UCD_DIR="/usr/share/unicode/ucd"
- )
- AC_SUBST(UCD_DIR)
--- 
-2.14.3
-
-From 75a6667b6ad8c8cb801cb160b7b04625334f9094 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Thu, 5 Apr 2018 16:54:41 +0900
-Subject: [PATCH] src/tests: Fix ibus-compose for the latest GTK
-
----
- src/tests/ibus-compose.c | 17 +++++++++++++++--
- 1 file changed, 15 insertions(+), 2 deletions(-)
-
-diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c
-index eb7b9f19..aabb36ac 100644
---- a/src/tests/ibus-compose.c
-+++ b/src/tests/ibus-compose.c
-@@ -2,6 +2,10 @@
- #include "ibus.h"
- #include "ibuscomposetable.h"
- 
-+#define GREEN "\033[0;32m"
-+#define RED   "\033[0;31m"
-+#define NC    "\033[0m"
-+
- IBusBus *m_bus;
- IBusComposeTable *m_compose_table;
- IBusEngine *m_engine;
-@@ -172,7 +176,12 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
-                          guint           nchars,
-                          gpointer        data)
- {
-+/* https://gitlab.gnome.org/GNOME/gtk/commit/9981f46e0b
-+ * The latest GTK does not emit "inserted-text" when the text is "".
-+ */
-+#if !GTK_CHECK_VERSION (3, 22, 16)
-     static int n_loop = 0;
-+#endif
-     static guint stride = 0;
-     guint i;
-     int seq;
-@@ -182,16 +191,18 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
- 
-     g_assert (m_compose_table != NULL);
- 
-+#if !GTK_CHECK_VERSION (3, 22, 16)
-     if (n_loop % 2 == 1) {
-         n_loop = 0;
-         return;
-     }
-+#endif
-     i = stride + (m_compose_table->max_seq_len + 2) - 1;
-     seq = (i + 1) / (m_compose_table->max_seq_len + 2);
-     if (m_compose_table->data[i] == code) {
--        test = "OK";
-+        test = GREEN "PASS" NC;
-     } else {
--        test = "NG";
-+        test = RED "FAIL" NC;
-         m_retval = -1;
-     }
-     g_print ("%05d/%05d %s expected: %04X typed: %04X\n",
-@@ -207,7 +218,9 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
-     }
- 
-     stride += m_compose_table->max_seq_len + 2;
-+#if !GTK_CHECK_VERSION (3, 22, 16)
-     n_loop++;
-+#endif
-     gtk_entry_set_text (entry, "");
- }
- 
--- 
-2.14.3
-
-From 28d0c1d4bc47beb38995d84cc4bb1d539c08a070 Mon Sep 17 00:00:00 2001
-From: Olivier Tilloy <olivier.tilloy@canonical.com>
-Date: Fri, 6 Apr 2018 16:02:11 +0900
-Subject: [PATCH] src: Make the call to chmod in ibus_bus_init conditional
-
-BUG=https://github.com/ibus/ibus/issues/1996
----
- src/ibusbus.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/src/ibusbus.c b/src/ibusbus.c
-index 11659c41..98820e8a 100644
---- a/src/ibusbus.c
-+++ b/src/ibusbus.c
-@@ -557,7 +557,6 @@ ibus_bus_init (IBusBus *bus)
-     path = g_path_get_dirname (ibus_get_socket_path ());
- 
-     g_mkdir_with_parents (path, 0700);
--    g_chmod (path, 0700);
- 
-     if (stat (path, &buf) == 0) {
-         if (buf.st_uid != getuid ()) {
-@@ -565,6 +564,9 @@ ibus_bus_init (IBusBus *bus)
-                        path, ibus_get_user_name ());
-             return;
-         }
-+        if (buf.st_mode != (S_IFDIR | S_IRWXU)) {
-+            g_chmod (path, 0700);
-+        }
-     }
- 
-     g_free (path);
--- 
-2.14.3
-
-From 32f2f2bab149ad766674e7421f7044ebe98bb0b6 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Fri, 6 Apr 2018 20:24:08 +0900
-Subject: [PATCH] tests: Added an automation testing on console
-
-test-console.sh runs /usr/bin/ibus-daemon on console after install ibus.
-
-Login as root
-  --builddir /root/ibus/src/tests --srcdir /root/ibus/src/tests
-
-Also added DISABLE_GUI_TESTS parameters for make check.
----
- bus/Makefile.am       |   1 +
- src/tests/Makefile.am |   5 +-
- src/tests/runtest     | 151 +++++++++++++++++++------------
- test/test-console.sh  | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 343 insertions(+), 56 deletions(-)
- create mode 100755 test/test-console.sh
-
-diff --git a/bus/Makefile.am b/bus/Makefile.am
-index 8bcc8e16..76166a0f 100644
---- a/bus/Makefile.am
-+++ b/bus/Makefile.am
-@@ -122,6 +122,7 @@ TESTS_ENVIRONMENT = \
-     top_builddir=$(top_builddir) \
-     top_srcdir=$(top_srcdir) \
-     builddir=$(builddir) \
-+    srcdir=$(srcdir) \
-     $(NULL)
- 
- LOG_COMPILER = $(top_srcdir)/src/tests/runtest
-diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
-index 125be3fc..8bcac8f2 100644
---- a/src/tests/Makefile.am
-+++ b/src/tests/Makefile.am
-@@ -3,7 +3,8 @@
- # ibus - The Input Bus
- #
- # Copyright (c) 2007-2015 Peng Huang <shawn.p.huang@gmail.com>
--# Copyright (c) 2007-2015 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
-@@ -66,6 +67,8 @@ TESTS_ENVIRONMENT = \
- 	top_builddir=$(top_builddir) \
- 	top_srcdir=$(top_srcdir) \
- 	builddir=$(builddir) \
-+	srcdir=$(srcdir) \
-+	DISABLE_GUI_TESTS=$(DISABLE_GUI_TESTS) \
- 	$(NULL)
- 
- LOG_COMPILER = $(srcdir)/runtest
-diff --git a/src/tests/runtest b/src/tests/runtest
-index 0e43fee5..b3b2a1ce 100755
---- a/src/tests/runtest
-+++ b/src/tests/runtest
-@@ -1,5 +1,8 @@
- #!/bin/sh
- 
-+# -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*-
-+# vim:set et sts=4:
-+
- # Run a test case given by the first argument in a separate directory.
- # This script may also launch $top_builddir/bus/ibus-daemon for testing.
- 
-@@ -17,6 +20,8 @@
- : ${top_builddir:=../..}
- : ${top_srcdir:=../..}
- : ${builddir:=.}
-+: ${srcdir:=.}
-+: ${DISABLE_GUI_TESTS:=''}
- 
- BUS_REQUIRED_TESTS="
- ibus-bus
-@@ -29,50 +34,51 @@ ibus-engine-switch
- ibus-compose
- test-stress
- "
-+retval=0
- 
- # Portable replacement of basename.
- func_basename () {
--  case "$1" in
-+    case "$1" in
-     */*)
--      expr "$1" : '.*/\(.*\)'
--      ;;
-+        expr "$1" : '.*/\(.*\)'
-+        ;;
-     *)
--      echo "$1"
--  esac
-+        echo "$1"
-+    esac
- }
- 
- # Portable replacement of dirname.
- func_dirname () {
--  case "$1" in
-+    case "$1" in
-     */*)
--      expr "$1" : '\(.*\)/.*'
--      ;;
-+        expr "$1" : '\(.*\)/.*'
-+        ;;
-     *)
--      echo .
--  esac
-+        echo .
-+    esac
- }
- 
- # Kill ibus-daemon process and remove temporary files.
- func_cleanup () {
--  tstdir=$1
--  if test -f $tstdir/ibus-daemon.pid; then
--    . $tstdir/ibus-daemon.pid
--    kill $IBUS_DAEMON_PID &> /dev/null
--  fi
--  rm -fr $tstdir
-+    tstdir=$1
-+    if test -f $tstdir/ibus-daemon.pid; then
-+        . $tstdir/ibus-daemon.pid
-+        kill $IBUS_DAEMON_PID &> /dev/null
-+    fi
-+    rm -fr $tstdir
- }
- 
- # Prepare component files necessary for testing, under components/.
- func_copy_component () {
--  file=$1
--  base=`func_basename $file`
--  libexecdir=`func_dirname $file`
--  # top_srcdir != top_builddir in make dist
--  libexecdir=`echo "$libexecdir" | sed -e "s|$top_srcdir|$top_builddir|"`
--  if test -f $file.in; then
--    mkdir -p components
--    sed "s|@libexecdir@|$libexecdir|g" < $file.in > components/$base
--  fi
-+    file=$1
-+    base=`func_basename $file`
-+    libexecdir=`func_dirname $file`
-+    # top_srcdir != top_builddir in make dist
-+    libexecdir=`echo "$libexecdir" | sed -e "s|$top_srcdir|$top_builddir|"`
-+    if test -f $file.in; then
-+        mkdir -p components
-+        sed "s|@libexecdir@|$libexecdir|g" < $file.in > components/$base
-+    fi
- }
- 
- trap 'func_cleanup $tstdir' 1 2 3 15
-@@ -80,44 +86,79 @@ trap 'func_cleanup $tstdir' 1 2 3 15
- tst=$1; shift
- tstdir=tmp-`func_basename $tst`
- 
--test -d $tstdir || mkdir $tstdir
--
--( cd $tstdir
--
--  need_bus=no
--  for t in $BUS_REQUIRED_TESTS; do
-+for t in $DISABLE_GUI_TESTS; do
-     if test $t = `func_basename $tst`; then
--      need_bus=yes
-+        exit 77
-     fi
--  done
--
--  if test $need_bus = yes; then
--    func_copy_component "../$top_srcdir/engine/simple.xml"
--    func_copy_component "../$top_srcdir/conf/memconf/memconf.xml"
-+done
- 
--    IBUS_COMPONENT_PATH=$PWD/components
--    export IBUS_COMPONENT_PATH
-+test -d $tstdir || mkdir $tstdir
- 
--    IBUS_ADDRESS_FILE=$PWD/ibus-daemon.pid
--    export IBUS_ADDRESS_FILE
-+run_test_case()
-+{
-+    pushd $tstdir
-+
-+    need_bus=no
-+    for t in $BUS_REQUIRED_TESTS; do
-+        if test $t = `func_basename $tst`; then
-+            need_bus=yes
-+        fi
-+    done
-+
-+    if test $need_bus = yes; then
-+        func_copy_component "../$top_srcdir/engine/simple.xml"
-+        func_copy_component "../$top_srcdir/conf/memconf/memconf.xml"
-+
-+        IBUS_COMPONENT_PATH=$PWD/components
-+        export IBUS_COMPONENT_PATH
-+
-+        IBUS_ADDRESS_FILE=$PWD/ibus-daemon.pid
-+        export IBUS_ADDRESS_FILE
-+
-+        # Start ibus-daemon.
-+        ../$top_builddir/bus/ibus-daemon \
-+        --daemonize \
-+        --cache=none \
-+        --panel=disable \
-+        --panel-extension=disable \
-+        --config=default \
-+        --verbose;
-+
-+        # Wait until all necessary components are up.
-+        sleep 1
-+    fi
- 
--    # Start ibus-daemon.
--    ../$top_builddir/bus/ibus-daemon \
--    --daemonize \
--    --cache=none \
--    --panel=disable \
--    --panel-extension=disable \
--    --config=default \
--    --verbose;
-+    "../$tst" ${1+"$@"}
- 
--    # Wait until all necessary components are up.
--    sleep 1
--  fi
-+    retval=`expr $retval \| $?`
- 
--  exec "../$tst" ${1+"$@"} )
-+    $popd
- 
--retval=$?
-+    func_cleanup $tstdir
-+}
- 
--func_cleanup $tstdir
-+envfile=$srcdir/`func_basename $tst`.env
-+if test -f $envfile ; then
-+    ENVS="`cat $envfile`"
-+fi;
-+if test x"$ENVS" = x ; then
-+    run_test_case
-+else
-+    LANG_backup=$LANG
-+    i=1
-+    for e in $ENVS; do
-+        first=`echo "$e" | cut -c1-1`
-+        if test x"$first" = x"#" ; then
-+            continue
-+        fi
-+        export $e
-+        echo "Run `func_basename $tst` on $e"
-+        echo "======================="
-+        run_test_case
-+        echo ""
-+        i=`expr $i + 1`
-+    done
-+    export LANG=$LANG_backup
-+fi
- 
- exit $retval
-diff --git a/test/test-console.sh b/test/test-console.sh
-new file mode 100755
-index 00000000..7199f7a7
---- /dev/null
-+++ b/test/test-console.sh
-@@ -0,0 +1,242 @@
-+#!/bin/sh
-+# -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*-
-+# vim:set noet ts=4:
-+#
-+# ibus-anthy - The Anthy engine for IBus
-+#
-+# Copyright (c) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+# Copyright (c) 2018 Red Hat, Inc.
-+#
-+# This program is free software; you can redistribute it and/or modify
-+# it under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; either version 2 of the License, or
-+# (at your option) any later version.
-+#
-+# This program 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 General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License along
-+# with this program; if not, write to the Free Software Foundation, Inc.,
-+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-+
-+# This test runs /usr/bin/ibus-daemon after install ibus
-+#
-+# # init 3
-+# Login as root
-+# # /root/ibus/tests/test-console.sh --tests ibus-compose \
-+#   --builddir /root/ibus/src/tests --srcdir /root/ibus/src/tests
-+
-+PROGNAME=`basename $0`
-+VERSION=0.1
-+DISPLAY=:99.0
-+BUILDDIR="."
-+SRCDIR="."
-+TEST_LOG=test-suite.log
-+HAVE_GRAPHICS=1
-+DESKTOP_COMMAND="gnome-session"
-+PID_XORG=0
-+PID_GNOME_SESSION=0
-+TESTS=""
-+GREEN='\033[0;32m'
-+RED='\033[0;31m'
-+NC='\033[0m'
-+
-+usage()
-+{
-+    echo -e \
-+"This test runs /usr/bin/ibus-daemon after install ibus\n"                     \
-+"$PROGNAME [OPTIONS…]\n"                                                       \
-+"\n"                                                                           \
-+"OPTIONS:\n"                                                                   \
-+"-h, --help                       This help\n"                                 \
-+"-v, --version                    Show version\n"                              \
-+"-b, --builddir=BUILDDIR          Set the BUILDDIR\n"                          \
-+"-s, --srcdir=SOURCEDIR           Set the SOURCEDIR\n"                         \
-+"-c, --no-graphics                Use Xvfb instead of Xorg\n"                  \
-+"-d, --desktop=DESKTOP            Run DESTKTOP. The default is gnome-session\n" \
-+"-t, --tests=\"TESTS...\"           Run TESTS programs which is separated by space\n" \
-+""
-+}
-+
-+parse_args()
-+{
-+    # This is GNU getopt. "sudo port getopt" in BSD?
-+    ARGS=`getopt -o hvb:s:cd:t: --long help,version,builddir:,srcdir:,no-graphics,desktop:,tests:\
-+        -- "$@"`;
-+    eval set -- "$ARGS"
-+    while [ 1 ] ; do
-+        case "$1" in
-+        -h | --help )        usage; exit 0;;
-+        -v | --version )     echo -e "$VERSION"; exit 0;;
-+        -b | --builddir )    BUILDDIR="$2"; shift 2;;
-+        -s | --srcdir )      SRCDIR="$2"; shift 2;;
-+        -c | --no-graphics ) HAVE_GRAPHICS=0; shift;;
-+        -d | --desktop )     DESKTOP_COMMAND="$2"; shift 2;;
-+        -t | --tests )       TESTS="$2"; shift 2;;
-+        -- )                 shift; break;;
-+        * )                  usage; exit 1;;
-+        esac
-+    done
-+}
-+
-+init_desktop()
-+{
-+    if test x$FORCE_TEST != x ; then
-+        RUN_ARGS="$RUN_ARGS --force"
-+    fi
-+
-+    if test ! -f $HOME/.config/gnome-initial-setup-done ; then
-+        if test ! -f /var/lib/AccountsService/users/$USER ; then
-+            mkdir -p /var/lib/AccountsService/users
-+            cat >> /var/lib/AccountsService/users/$USER << _EOF
-+[User]
-+Language=ja_JP.UTF-8
-+XSession=gnome
-+SystemAccount=false
-+_EOF
-+        fi
-+        mkdir -p $HOME/.config
-+        touch $HOME/.config/gnome-initial-setup-done
-+    fi
-+}
-+
-+run_dbus_daemon()
-+{
-+    a=`ps -ef | grep dbus-daemon | grep "\-\-system" | grep -v session | grep -v grep`
-+    if test x"$a" = x ; then
-+        eval `dbus-launch --sh-syntax`
-+    fi
-+    SUSER=`echo "$USER" | cut -c 1-7`
-+    a=`ps -ef | grep dbus-daemon | grep "$SUSER" | grep -v gdm | grep session | grep -v grep`
-+    if test x"$a" = x ; then
-+        systemctl --user start dbus
-+        export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$UID/bus
-+    fi
-+    systemctl --user status dbus | col -b
-+    ps -ef | grep dbus-daemon | grep "$SUSER" | grep -v gdm | egrep 'session|system' | grep -v grep
-+    systemctl --user show-environment | col -b
-+}
-+
-+run_desktop()
-+{
-+    if test $HAVE_GRAPHICS -eq 1 ; then
-+        /usr/libexec/Xorg.wrap -noreset +extension GLX +extension RANDR +extension RENDER -logfile ./xorg.log -config ./xorg.conf -configdir . $DISPLAY &
-+    else
-+        /usr/bin/Xvfb $DISPLAY -noreset +extension GLX +extension RANDR +extension RENDER -screen 0 1280x1024x24 &
-+    fi
-+    PID_XORG=$!
-+    sleep 1
-+    export DISPLAY=$DISPLAY
-+    $DESKTOP_COMMAND &
-+    PID_GNOME_SESSION=$!
-+    sleep 30
-+    if test "$DESKTOP_COMMAND" != "gnome-session" ; then
-+        ibus-daemon --daemonize --verbose
-+        sleep 1
-+    fi
-+}
-+
-+count_case_result()
-+{
-+    retval=$1
-+    pass=$2
-+    fail=$3
-+
-+    if test $retval -eq  0 ; then
-+        pass=`expr $pass + 1`
-+    else
-+        fail=`expr $fail + 1`
-+    fi
-+    echo $pass $fail
-+}
-+
-+echo_case_result()
-+{
-+    retval=$1
-+    tst=$2
-+    log=$3
-+    subtst=${4:-''}
-+
-+    if test $retval -eq  0 ; then
-+        echo -e "${GREEN}PASS${NC}: $tst $subtst"
-+    else
-+        echo -e "${RED}FAIL${NC}: $tst $subtst"
-+        echo "FAIL: $tst $subtst" >> $TEST_LOG
-+        echo "======================" >> $TEST_LOG
-+        echo "" >> $TEST_LOG
-+        cat "$log" >> $TEST_LOG
-+        echo "" >> $TEST_LOG
-+    fi
-+}
-+
-+run_test_suite()
-+{
-+    cd `dirname $0`
-+    pass=0
-+    fail=0
-+
-+    if test -f $TEST_LOG ; then
-+        rm $TEST_LOG
-+    fi
-+    for tst in $TESTS; do
-+        ENVS=
-+        if test -f $SRCDIR/${tst}.env ; then
-+            ENVS="`cat $SRCDIR/${tst}.env`"
-+        fi
-+        if test x"$ENVS" = x ; then
-+            $BUILDDIR/$tst >&${tst}.log
-+            retval=$?
-+            read pass fail << EOF
-+            `count_case_result $retval $pass $fail`
-+EOF
-+            echo_case_result $retval $tst ${tst}.log
-+        else
-+            LANG_backup=$LANG
-+            i=1
-+            for e in $ENVS; do
-+                first=`echo "$e" | cut -c1-1`
-+                if test x"$first" = x"#" ; then
-+                    continue
-+                fi
-+                export $e
-+                $BUILDDIR/$tst >&${tst}.${i}.log
-+                retval=$?
-+                read pass fail << EOF
-+                `count_case_result $retval $pass $fail`
-+EOF
-+                echo_case_result $retval $tst ${tst}.${i}.log $e
-+                i=`expr $i + 1`
-+            done
-+            export LANG=$LANG_backup
-+        fi
-+    done
-+    echo ""
-+    echo -e "# ${GREEN}PASS${NC}: $pass"
-+    echo -e "# ${RED}FAIL${NC}: $fail"
-+    if test -f ${TEST_LOG} ; then
-+        echo ""
-+        echo -e "${RED}See ${TEST_LOG}$NC"
-+    fi
-+}
-+
-+finit()
-+{
-+    if test "$DESKTOP_COMMAND" != "gnome-session" ; then
-+        ibus exit
-+    fi
-+    kill $PID_GNOME_SESSION $PID_XORG
-+}
-+
-+main()
-+{
-+    parse_args $@
-+    init_desktop
-+    run_dbus_daemon
-+    run_desktop
-+    run_test_suite
-+    finit
-+}
-+
-+main $@
--- 
-2.14.3
-
-From 68e162a59c7943ee6207ff7d21f9a75d1e6f2f79 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Fri, 6 Apr 2018 20:35:50 +0900
-Subject: [PATCH] src/tests: Fix a typo in runtest
-
----
- src/tests/runtest | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
-diff --git a/src/tests/runtest b/src/tests/runtest
-index b3b2a1ce..09026be0 100755
---- a/src/tests/runtest
-+++ b/src/tests/runtest
-@@ -92,10 +92,9 @@ for t in $DISABLE_GUI_TESTS; do
-     fi
- done
- 
--test -d $tstdir || mkdir $tstdir
--
- run_test_case()
- {
-+    test -d $tstdir || mkdir $tstdir
-     pushd $tstdir
- 
-     need_bus=no
-@@ -132,7 +131,7 @@ run_test_case()
- 
-     retval=`expr $retval \| $?`
- 
--    $popd
-+    popd
- 
-     func_cleanup $tstdir
- }
--- 
-2.14.3
-
-From c360cbd830943a4bfb0ece9cc07b99a426dc2121 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Mon, 9 Apr 2018 11:57:09 +0900
-Subject: [PATCH] src/tests: Add ibus-compose.env
-
----
- src/tests/ibus-compose.env | 3 +++
- 1 file changed, 3 insertions(+)
- create mode 100644 src/tests/ibus-compose.env
-
-diff --git a/src/tests/ibus-compose.env b/src/tests/ibus-compose.env
-new file mode 100644
-index 00000000..734ab8fa
---- /dev/null
-+++ b/src/tests/ibus-compose.env
-@@ -0,0 +1,3 @@
-+LANG=el_GR.UTF-8
-+LANG=fi_FI.UTF-8
-+LANG=pt_BR.UTF-8
--- 
-2.14.3
-
-From 68bd2695c4cc6a06cb8a55a55fed2054d29f0995 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Fri, 13 Apr 2018 16:31:29 +0900
-Subject: [PATCH] src/tests: Fix a typo
-
----
- src/tests/Makefile.am | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
-index 8bcac8f2..11ebb531 100644
---- a/src/tests/Makefile.am
-+++ b/src/tests/Makefile.am
-@@ -68,7 +68,7 @@ TESTS_ENVIRONMENT = \
- 	top_srcdir=$(top_srcdir) \
- 	builddir=$(builddir) \
- 	srcdir=$(srcdir) \
--	DISABLE_GUI_TESTS=$(DISABLE_GUI_TESTS) \
-+	DISABLE_GUI_TESTS="$(DISABLE_GUI_TESTS)" \
- 	$(NULL)
- 
- LOG_COMPILER = $(srcdir)/runtest
--- 
-2.14.3
-
-From 8d4c4738d07b6850e56ae74d46b7b13b7382f865 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Fri, 13 Apr 2018 17:33:50 +0900
-Subject: [PATCH] configure: Add --disable-python2 option
-
----
- bindings/pygobject/Makefile.am |  6 ++++++
- configure.ac                   | 37 ++++++++++++++++++++++++++++---------
- 2 files changed, 34 insertions(+), 9 deletions(-)
-
-diff --git a/bindings/pygobject/Makefile.am b/bindings/pygobject/Makefile.am
-index 238a537a..fb2e2a7a 100644
---- a/bindings/pygobject/Makefile.am
-+++ b/bindings/pygobject/Makefile.am
-@@ -4,6 +4,8 @@
- #
- # Copyright (c) 2012 Daiki Ueno <ueno@unixuser.org>
- # Copyright (c) 2014-2016 Peng Huang <shawn.p.huang@gmail.com>
-+# Copyright (c) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+# Copyright (c) 2012-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
-@@ -22,11 +24,13 @@
- 
- NULL =
- 
-+if ENABLE_PYTHON2
- py2_compile = PYTHON=$(PYTHON2) $(SHELL) $(py_compile)
- overrides2dir = $(py2overridesdir)
- overrides2_DATA =				\
- 	gi/overrides/IBus.py			\
- 	$(NULL)
-+endif
- 
- overridesdir = $(pyoverridesdir)
- overrides_PYTHON =				\
-@@ -56,6 +60,7 @@ EXTRA_DIST =					\
- 	$(NULL)
- 
- install-data-hook:
-+if ENABLE_PYTHON2
- 	@for data in $(overrides2_DATA); do \
- 	    file=`echo $$data | sed -e 's|^.*/||'`; \
- 	    dlist="$$dlist $$file"; \
-@@ -63,6 +68,7 @@ install-data-hook:
- 	$(py2_compile) --destdir "$(DESTDIR)" \
- 	               --basedir "$(overrides2dir)" \
- 	               $$dlist
-+endif
- 	$(NULL)
- 
- -include $(top_srcdir)/git.mk
-diff --git a/configure.ac b/configure.ac
-index d19aa874..085cecb8 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -391,6 +391,14 @@ fi
- AC_PATH_PROG(ENV_IBUS_TEST, env)
- AC_SUBST(ENV_IBUS_TEST)
- 
-+AC_ARG_ENABLE(python2,
-+    AS_HELP_STRING([--disable-python2],
-+                   [Do not install bindings/pygobject/gi and ibus for python2.
-+                    '--disable-python2' bring '--disable-python-library'.]),
-+    [enable_python2=$enableval],
-+    [enable_python2=yes]
-+)
-+
- AC_ARG_ENABLE(python-library,
-     AS_HELP_STRING([--enable-python-library],
-                    [Use ibus python library]),
-@@ -405,10 +413,6 @@ AC_ARG_ENABLE(setup,
-     [enable_setup=yes]
- )
- 
--AM_CONDITIONAL([ENABLE_PYTHON_LIBRARY], [test x"$enable_python_library" = x"yes"])
--AM_CONDITIONAL([ENABLE_SETUP], [test x"$enable_setup" = x"yes"])
--AM_CONDITIONAL([ENABLE_DAEMON], [true])
--
- # Define python version
- AC_ARG_WITH(python,
-     AS_HELP_STRING([--with-python[=PATH]],
-@@ -417,12 +421,24 @@ AC_ARG_WITH(python,
- )
- 
- AM_PATH_PYTHON([2.5])
--AC_PATH_PROG(PYTHON2, python2)
- 
--if test x"$PYTHON2" = x""; then
--    PYTHON2=$PYTHON
-+if test x"$enable_python2" != x"yes"; then
-+    enable_python_library=no
-+    PYTHON2=
-+    enable_python2="no (disabled, use --enable-python2 to enable)"
-+else
-+    AC_PATH_PROG(PYTHON2, python2)
-+
-+    if test x"$PYTHON2" = x""; then
-+        PYTHON2=$PYTHON
-+    fi
- fi
- 
-+AM_CONDITIONAL([ENABLE_PYTHON2], [test x"$enable_python2" = x"yes"])
-+AM_CONDITIONAL([ENABLE_PYTHON_LIBRARY], [test x"$enable_python_library" = x"yes"])
-+AM_CONDITIONAL([ENABLE_SETUP], [test x"$enable_setup" = x"yes"])
-+AM_CONDITIONAL([ENABLE_DAEMON], [true])
-+
- PYGOBJECT_REQUIRED=3.0.0
- 
- PKG_CHECK_EXISTS([pygobject-3.0 >= $PYGOBJECT_REQUIRED],
-@@ -434,8 +450,10 @@ if test "x$enable_pygobject" = "xyes"; then
-     pyoverridesdir=`$PYTHON -c "import gi; print(gi._overridesdir)"`
-     AC_SUBST(pyoverridesdir)
- 
--    py2overridesdir=`$PYTHON2 -c "import gi; print(gi._overridesdir)"`
--    AC_SUBST(py2overridesdir)
-+    if test x"$enable_python2" = x"yes"; then
-+        py2overridesdir=`$PYTHON2 -c "import gi; print(gi._overridesdir)"`
-+        AC_SUBST(py2overridesdir)
-+    fi
- fi
- 
- AM_CONDITIONAL(ENABLE_PYGOBJECT, test x"$enable_pygobject" = "xyes")
-@@ -752,6 +770,7 @@ Build options:
-   CFLAGS                        $CFLAGS
-   PYTHON                        $PYTHON
-   PYTHON2                       $PYTHON2
-+  Enable python2                $enable_python2
-   Gtk2 immodule dir             $GTK2_IM_MODULEDIR
-   Gtk3 immodule dir             $GTK3_IM_MODULEDIR
-   Build gtk2 immodule           $enable_gtk2
--- 
-2.14.3
-
-From 7bc160f2139799b853678264c6b01277f0721336 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Fri, 13 Apr 2018 19:39:09 +0900
-Subject: [PATCH] bus: Add DISABLE_GUI_TESTS for test-stress
-
----
- bus/Makefile.am | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/bus/Makefile.am b/bus/Makefile.am
-index 76166a0f..dda79eac 100644
---- a/bus/Makefile.am
-+++ b/bus/Makefile.am
-@@ -110,7 +110,6 @@ if ENABLE_EMOJI_DICT
- AM_CFLAGS += -DEMOJI_DICT
- endif
- 
--
- if ENABLE_TESTS
- TESTS = \
- 	test-matchrule \
-@@ -123,6 +122,7 @@ TESTS_ENVIRONMENT = \
-     top_srcdir=$(top_srcdir) \
-     builddir=$(builddir) \
-     srcdir=$(srcdir) \
-+    DISABLE_GUI_TESTS="$(DISABLE_GUI_TESTS)" \
-     $(NULL)
- 
- LOG_COMPILER = $(top_srcdir)/src/tests/runtest
--- 
-2.14.3
-
-From 10cc30eac200d10b581d9d2122d5a732f4880943 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Tue, 17 Apr 2018 14:00:20 +0900
-Subject: [PATCH] src/tests: Enable GSettings in runtest
-
----
- src/tests/runtest | 22 ++++++++++++++++++++++
- 1 file changed, 22 insertions(+)
-
-diff --git a/src/tests/runtest b/src/tests/runtest
-index 09026be0..35825b1b 100755
---- a/src/tests/runtest
-+++ b/src/tests/runtest
-@@ -34,6 +34,8 @@ ibus-engine-switch
- ibus-compose
- test-stress
- "
-+IBUS_SCHEMA_FILE='org.freedesktop.ibus.gschema.xml'
-+
- retval=0
- 
- # Portable replacement of basename.
-@@ -92,6 +94,12 @@ for t in $DISABLE_GUI_TESTS; do
-     fi
- done
- 
-+# IBusEngine has GSettings
-+if test ! -f "$top_builddir/data/dconf/$IBUS_SCHEMA_FILE" ; then
-+    echo "NOT FOUND $top_builddir/data/dconf/$IBUS_SCHEMA_FILE"
-+    exit -1
-+fi
-+
- run_test_case()
- {
-     test -d $tstdir || mkdir $tstdir
-@@ -114,6 +122,20 @@ run_test_case()
-         IBUS_ADDRESS_FILE=$PWD/ibus-daemon.pid
-         export IBUS_ADDRESS_FILE
- 
-+        cp "../$top_builddir/data/dconf/$IBUS_SCHEMA_FILE" $PWD
-+        glib-compile-schemas $PWD
-+        if test $? -ne 0 ; then
-+            echo "FAILED glib-compile-schemas"
-+            retval=1
-+            return
-+        fi
-+        if test ! -f $PWD/gschemas.compiled ; then
-+            echo "NOT FOUND $PWD/gschemas.compiled"
-+            retval=1
-+            return
-+        fi
-+        export GSETTINGS_SCHEMA_DIR=$PWD
-+
-         # Start ibus-daemon.
-         ../$top_builddir/bus/ibus-daemon \
-         --daemonize \
--- 
-2.14.3
-
-From 3280848b42b07afbac3d59066474c5f429de9182 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Tue, 17 Apr 2018 14:43:02 +0900
-Subject: [PATCH] bus: Enable sub package of gtkextension.xml and
- ibus-extension-gtk3
-
-GNOME destkop asked not to install ibus-extension-gtk3 by default
-since the UI is not called by gnome-shell.
-
-BUG=rhbz#1567689
----
- bus/main.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/bus/main.c b/bus/main.c
-index 7aa89fc4..e1cc423b 100644
---- a/bus/main.c
-+++ b/bus/main.c
-@@ -293,7 +293,7 @@ main (gint argc, gchar **argv)
-         if (component) {
-             bus_component_set_restart (component, restart);
-         }
--        if (component == NULL ||
-+        if (component != NULL &&
-             !bus_component_start (component, g_verbose)) {
-             g_printerr ("Can not execute default panel program\n");
-             exit (-1);
--- 
-2.14.3
-
-From d8f901f856ddd75baba5826038d1346c5a43d048 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Fri, 20 Apr 2018 15:58:06 +0900
-Subject: [PATCH] Replace OnlyShowIn= with NoDisplay=true
-
-BUG=rhbz#1567689
----
- ui/gtk3/ibus-extension-gtk3.desktop.in.in | 2 +-
- ui/gtk3/ibus-ui-emojier.desktop.in.in     | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/ui/gtk3/ibus-extension-gtk3.desktop.in.in b/ui/gtk3/ibus-extension-gtk3.desktop.in.in
-index 6ec5585f..a119ec8e 100644
---- a/ui/gtk3/ibus-extension-gtk3.desktop.in.in
-+++ b/ui/gtk3/ibus-extension-gtk3.desktop.in.in
-@@ -3,4 +3,4 @@ _Name=Emoji Choice
- Icon=ibus
- Exec=@libexecdir@/ibus-extension-gtk3
- Type=Application
--OnlyShowIn=
-+NoDisplay=true
-diff --git a/ui/gtk3/ibus-ui-emojier.desktop.in.in b/ui/gtk3/ibus-ui-emojier.desktop.in.in
-index f4b750a8..6d9422d5 100644
---- a/ui/gtk3/ibus-ui-emojier.desktop.in.in
-+++ b/ui/gtk3/ibus-ui-emojier.desktop.in.in
-@@ -3,4 +3,4 @@ _Name=Emoji Choice
- Icon=ibus
- Exec=ibus emoji
- Type=Application
--OnlyShowIn=
-+NoDisplay=true
--- 
-2.14.3
-
-From 886ad3651d16dd821e2526e8601c69738533a7e8 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Mon, 7 May 2018 12:35:03 +0900
-Subject: [PATCH] src: Fix SEGV in IBusEngine if no emoji shortcut keys
-
-BUG=https://github.com/ibus/ibus/issues/2005
----
- src/ibusengine.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/ibusengine.c b/src/ibusengine.c
-index 9a0b1a8a..fd61102a 100644
---- a/src/ibusengine.c
-+++ b/src/ibusengine.c
-@@ -925,6 +925,9 @@ ibus_engine_filter_key_event (IBusEngine *engine,
-     g_return_val_if_fail (IBUS_IS_ENGINE (engine), FALSE);
- 
-     priv = engine->priv;
-+    if (!priv->emoji_keybindings)
-+        return FALSE;
-+
-     modifiers = state & IBUS_MODIFIER_FILTER;
-     if (keyval >= IBUS_KEY_A && keyval <= IBUS_KEY_Z &&
-         (modifiers & IBUS_SHIFT_MASK) != 0) {
--- 
-2.14.3
-
-From 196216a89a9167425dd9b41f4f1d8a494d370249 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Fri, 11 May 2018 19:13:03 +0900
-Subject: [PATCH] src: Add ibus-keypress
-
----
- configure.ac              |   8 ++
- src/tests/Makefile.am     |   7 ++
- src/tests/ibus-keypress.c | 298 ++++++++++++++++++++++++++++++++++++++++++++++
- src/tests/runtest         |   1 +
- 4 files changed, 314 insertions(+)
- create mode 100644 src/tests/ibus-keypress.c
-
-diff --git a/configure.ac b/configure.ac
-index 085cecb8..f332a775 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -621,6 +621,14 @@ if test x"$enable_libnotify" = x"yes"; then
-     enable_libnotify="yes (enabled, use --disable-libnotify to disable)"
- fi
- 
-+PKG_CHECK_MODULES(XTEST,
-+    [x11 xtst],
-+    [enable_xtest=yes],
-+    [enable_xtest=no]
-+)
-+AM_CONDITIONAL([ENABLE_XTEST], [test x"$enable_xtest" = x"yes"])
-+
-+
- # --disable-emoji-dict option.
- AC_ARG_ENABLE(emoji-dict,
-     AS_HELP_STRING([--disable-emoji-dict],
-diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
-index 11ebb531..5f21ebcd 100644
---- a/src/tests/Makefile.am
-+++ b/src/tests/Makefile.am
-@@ -61,6 +61,9 @@ endif
- 
- if ENABLE_GTK3
- TESTS += ibus-compose
-+if ENABLE_XTEST
-+TESTS += ibus-keypress
-+endif
- endif
- 
- TESTS_ENVIRONMENT = \
-@@ -103,6 +106,10 @@ ibus_inputcontext_create_LDADD = $(prog_ldadd)
- ibus_keynames_SOURCES = ibus-keynames.c
- ibus_keynames_LDADD = $(prog_ldadd)
- 
-+ibus_keypress_SOURCES = ibus-keypress.c
-+ibus_keypress_CFLAGS = @GTK3_CFLAGS@ @XTEST_CFLAGS@
-+ibus_keypress_LDADD = $(prog_ldadd) @GTK3_LIBS@ @XTEST_LIBS@
-+
- ibus_registry_SOURCES = ibus-registry.c
- ibus_registry_LDADD = $(prog_ldadd)
- 
-diff --git a/src/tests/ibus-keypress.c b/src/tests/ibus-keypress.c
-new file mode 100644
-index 00000000..3486523b
---- /dev/null
-+++ b/src/tests/ibus-keypress.c
-@@ -0,0 +1,298 @@
-+#include <gtk/gtk.h>
-+#include <gdk/gdkx.h>
-+#include "ibus.h"
-+#include <stdlib.h>
-+#include <X11/Xlib.h>
-+#include <X11/extensions/XTest.h>
-+
-+#define GREEN "\033[0;32m"
-+#define RED   "\033[0;31m"
-+#define NC    "\033[0m"
-+
-+typedef struct _KeyData {
-+    guint keyval;
-+    guint modifiers;
-+} KeyData;
-+
-+static const KeyData test_cases[][30] = {
-+   { { IBUS_KEY_a, 0 }, { IBUS_KEY_comma, IBUS_SHIFT_MASK },
-+     { IBUS_KEY_b, 0 }, { IBUS_KEY_period, IBUS_SHIFT_MASK },
-+     { IBUS_KEY_c, 0 }, { IBUS_KEY_slash, IBUS_SHIFT_MASK },
-+     { IBUS_KEY_d, 0 }, { IBUS_KEY_semicolon, IBUS_SHIFT_MASK },
-+     { IBUS_KEY_e, 0 }, { IBUS_KEY_apostrophe, IBUS_SHIFT_MASK },
-+     { IBUS_KEY_f, 0 }, { IBUS_KEY_bracketleft, IBUS_SHIFT_MASK },
-+     { IBUS_KEY_g, 0 }, { IBUS_KEY_backslash, IBUS_SHIFT_MASK },
-+     { 0, 0 } },
-+   { { IBUS_KEY_grave, IBUS_SHIFT_MASK }, { IBUS_KEY_a, IBUS_SHIFT_MASK },
-+     { IBUS_KEY_1, IBUS_SHIFT_MASK }, { IBUS_KEY_b, IBUS_SHIFT_MASK  },
-+     { IBUS_KEY_2, IBUS_SHIFT_MASK }, { IBUS_KEY_c, IBUS_SHIFT_MASK  },
-+     { IBUS_KEY_3, IBUS_SHIFT_MASK }, { IBUS_KEY_d, IBUS_SHIFT_MASK },
-+     { IBUS_KEY_9, IBUS_SHIFT_MASK }, { IBUS_KEY_e, IBUS_SHIFT_MASK },
-+     { IBUS_KEY_0, IBUS_SHIFT_MASK }, { IBUS_KEY_f, IBUS_SHIFT_MASK },
-+     { IBUS_KEY_equal, IBUS_SHIFT_MASK }, { IBUS_KEY_g, IBUS_SHIFT_MASK },
-+     { 0, 0 } },
-+   { { 0, 0 } }
-+};
-+
-+KeyData test_end_key = { IBUS_KEY_z, IBUS_SHIFT_MASK };
-+
-+static const gunichar test_results[][60] = {
-+   { 'a', '<', 'b', '>', 'c', '?', 'd', ':', 'e', '"', 'f', '{', 'g', '|', 0 },
-+   { '~', 'A', '!', 'B', '@', 'C', '#', 'D', '(', 'E', ')', 'F', '+', 'G', 0 },
-+   { 0 }
-+};
-+
-+
-+IBusBus *m_bus;
-+IBusEngine *m_engine;
-+
-+static gboolean window_focus_in_event_cb (GtkWidget     *entry,
-+                                          GdkEventFocus *event,
-+                                          gpointer       data);
-+
-+static IBusEngine *
-+create_engine_cb (IBusFactory *factory, const gchar *name, gpointer data)
-+{
-+    static int i = 1;
-+    gchar *engine_path =
-+            g_strdup_printf ("/org/freedesktop/IBus/engine/simpletest/%d",
-+                             i++);
-+
-+    m_engine = ibus_engine_new_with_type (IBUS_TYPE_ENGINE_SIMPLE,
-+                                          name,
-+                                          engine_path,
-+                                          ibus_bus_get_connection (m_bus));
-+    g_free (engine_path);
-+    return m_engine;
-+}
-+
-+static gboolean
-+register_ibus_engine ()
-+{
-+    IBusFactory *factory;
-+    IBusComponent *component;
-+    IBusEngineDesc *desc;
-+
-+    m_bus = ibus_bus_new ();
-+    if (!ibus_bus_is_connected (m_bus)) {
-+        g_critical ("ibus-daemon is not running.");
-+        return FALSE;
-+    }
-+    factory = ibus_factory_new (ibus_bus_get_connection (m_bus));
-+    g_signal_connect (factory, "create-engine",
-+                      G_CALLBACK (create_engine_cb), NULL);
-+
-+    component = ibus_component_new (
-+            "org.freedesktop.IBus.SimpleTest",
-+            "Simple Engine Test",
-+            "0.0.1",
-+            "GPL",
-+            "Takao Fujiwara <takao.fujiwara1@gmail.com>",
-+            "https://github.com/ibus/ibus/wiki",
-+            "",
-+            "ibus");
-+    desc = ibus_engine_desc_new (
-+            "xkbtest:us::eng",
-+            "XKB Test",
-+            "XKB Test",
-+            "en",
-+            "GPL",
-+            "Takao Fujiwara <takao.fujiwara1@gmail.com>",
-+            "ibus-engine",
-+            "us");
-+    ibus_component_add_engine (component, desc);
-+    ibus_bus_register_component (m_bus, component);
-+
-+    return TRUE;
-+}
-+
-+static gboolean
-+finit (gpointer data)
-+{
-+    g_critical ("time out");
-+    gtk_main_quit ();
-+    return FALSE;
-+}
-+
-+static void
-+send_key_event (Display *xdisplay,
-+                guint    keyval,
-+                guint    modifiers)
-+{
-+    static struct {
-+        guint   state;
-+        KeySym  keysym;
-+    } state2keysym[] = {
-+        { IBUS_CONTROL_MASK, XK_Control_L } ,
-+        { IBUS_MOD1_MASK,    XK_Alt_L },
-+        { IBUS_MOD4_MASK,    XK_Super_L },
-+        { IBUS_SHIFT_MASK,   XK_Shift_L },
-+        { IBUS_LOCK_MASK,    XK_Caps_Lock },
-+        { 0,           0L }
-+    };
-+    int i;
-+    guint keycode;
-+    guint state = modifiers;
-+
-+    while (state) {
-+        for (i = 0; state2keysym[i].state; i++) {
-+            if ((state2keysym[i].state & state) != 0) {
-+                keycode = XKeysymToKeycode (xdisplay, state2keysym[i].keysym);
-+                XTestFakeKeyEvent (xdisplay, keycode, True, CurrentTime);
-+                XSync (xdisplay, False);
-+                state ^= state2keysym[i].state;
-+                break;
-+            }
-+        }
-+    }
-+    keycode = XKeysymToKeycode (xdisplay, keyval);
-+    XTestFakeKeyEvent (xdisplay, keycode, True, CurrentTime);
-+    XSync (xdisplay, False);
-+    XTestFakeKeyEvent (xdisplay, keycode, False, CurrentTime);
-+    XSync (xdisplay, False);
-+
-+    state = modifiers;
-+    while (state) {
-+        for (i = G_N_ELEMENTS (state2keysym) - 1; i >= 0; i--) {
-+            if ((state2keysym[i].state & state) != 0) {
-+                keycode = XKeysymToKeycode (xdisplay, state2keysym[i].keysym);
-+                XTestFakeKeyEvent (xdisplay, keycode, False, CurrentTime);
-+                XSync (xdisplay, False);
-+                state ^= state2keysym[i].state;
-+                break;
-+            }
-+        }
-+    }
-+}
-+
-+static void
-+set_engine_cb (GObject      *object,
-+               GAsyncResult *res,
-+               gpointer      data)
-+{
-+    IBusBus *bus = IBUS_BUS (object);
-+    GtkWidget *entry = GTK_WIDGET (data);
-+    GdkDisplay *display;
-+    Display *xdisplay;
-+    GError *error = NULL;
-+    int i, j;
-+
-+    g_assert (GTK_IS_ENTRY (entry));
-+
-+    if (!ibus_bus_set_global_engine_async_finish (bus, res, &error)) {
-+        g_critical ("set engine failed: %s", error->message);
-+        g_error_free (error);
-+        return;
-+    }
-+
-+    display = gtk_widget_get_display (entry);
-+    if (GDK_IS_X11_DISPLAY (display)) {
-+        xdisplay = gdk_x11_display_get_xdisplay (display);
-+    } else {
-+#if 0
-+        xdisplay = XOpenDisplay (NULL);
-+#else
-+        g_critical ("No idea to simulate key events in Wayland\n");
-+#endif
-+    }
-+    g_return_if_fail (xdisplay);
-+
-+    for (i = 0; test_cases[i][0].keyval; i++) {
-+        for (j = 0; test_cases[i][j].keyval; j++) {
-+            send_key_event (xdisplay,
-+                            test_cases[i][j].keyval,
-+                            test_cases[i][j].modifiers);
-+        }
-+        send_key_event (xdisplay, test_end_key.keyval, test_end_key.modifiers);
-+    }
-+
-+    g_timeout_add_seconds (10, finit, NULL);
-+}
-+
-+static gboolean
-+window_focus_in_event_cb (GtkWidget *entry, GdkEventFocus *event, gpointer data)
-+{
-+    g_assert (m_bus != NULL);
-+    ibus_bus_set_global_engine_async (m_bus,
-+                                      "xkbtest:us::eng",
-+                                      -1,
-+                                      NULL,
-+                                      set_engine_cb,
-+                                      entry);
-+    return FALSE;
-+}
-+
-+static void
-+window_inserted_text_cb (GtkEntryBuffer *buffer,
-+                         guint           position,
-+                         const gchar    *chars,
-+                         guint           nchars,
-+                         gpointer        data)
-+{
-+    GtkWidget *entry = data;
-+    static int i = 0;
-+    static int j = 0;
-+
-+    if (g_utf8_get_char (chars) == 'Z') {
-+        int k;
-+        g_print ("\n" GREEN "PASS" NC ": ");
-+        for (k = 0; k < j; k++)
-+            g_print ("%lc(%X) ", test_results[i][k], test_results[i][k]);
-+        g_print ("\n");
-+        i++;
-+        j = 0;
-+        if (test_results[i][0] == 0)
-+            gtk_main_quit ();
-+        else
-+            gtk_entry_set_text (GTK_ENTRY (entry), "");
-+        return;
-+    }
-+    g_assert (g_utf8_get_char (chars) == test_results[i][j]);
-+    j++;
-+}
-+
-+static void
-+create_window ()
-+{
-+    GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-+    GtkWidget *entry = gtk_entry_new ();
-+    GtkEntryBuffer *buffer;
-+
-+    g_signal_connect (window, "destroy",
-+                      G_CALLBACK (gtk_main_quit), NULL);
-+    g_signal_connect (entry, "focus-in-event",
-+                      G_CALLBACK (window_focus_in_event_cb), NULL);
-+    buffer = gtk_entry_get_buffer (GTK_ENTRY (entry));
-+    g_signal_connect (buffer, "inserted-text",
-+                      G_CALLBACK (window_inserted_text_cb), entry);
-+    gtk_container_add (GTK_CONTAINER (window), entry);
-+    gtk_widget_show_all (window);
-+}
-+
-+static void
-+test_keypress (void)
-+{
-+    int status = 0;
-+    GError *error = NULL;
-+
-+    g_spawn_command_line_sync ("setxkbmap -layout us",
-+                               NULL, NULL,
-+                               &status, &error);
-+    g_assert (register_ibus_engine ());
-+
-+    create_window ();
-+    gtk_main ();
-+}
-+
-+int
-+main (int argc, char *argv[])
-+{
-+    ibus_init ();
-+    g_test_init (&argc, &argv, NULL);
-+    gtk_init (&argc, &argv);
-+
-+    g_test_add_func ("/ibus/keyrepss", test_keypress);
-+
-+
-+    return g_test_run ();
-+}
-diff --git a/src/tests/runtest b/src/tests/runtest
-index 35825b1b..b6b845d6 100755
---- a/src/tests/runtest
-+++ b/src/tests/runtest
-@@ -32,6 +32,7 @@ ibus-inputcontext
- ibus-inputcontext-create
- ibus-engine-switch
- ibus-compose
-+ibus-keypress
- test-stress
- "
- IBUS_SCHEMA_FILE='org.freedesktop.ibus.gschema.xml'
--- 
-2.14.3
-
-From 8ab0b603ba1cd8701583aee46c712898d52005f1 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Wed, 23 May 2018 19:20:10 +0900
-Subject: [PATCH] bus: Fix a SEGV in bus_input_context_emit_signal
-
-IBus engines can call 'RequireSurroundingText' for a fake input context
-if there is no input focus.
----
- bus/inputcontext.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/bus/inputcontext.c b/bus/inputcontext.c
-index a957d107..dfb98c36 100644
---- a/bus/inputcontext.c
-+++ b/bus/inputcontext.c
-@@ -716,7 +716,9 @@ bus_input_context_emit_signal (BusInputContext *context,
-                                GError         **error)
- {
-     if (context->connection == NULL) {
--        g_variant_unref (parameters);
-+        /* fake context has no connections. */
-+        if (parameters)
-+            g_variant_unref (parameters);
-         return TRUE;
-     }
- 
--- 
-2.14.3
-
-From a1f91b27145b046a112bb5eba2561880dae5d6a2 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Mon, 4 Jun 2018 17:44:17 +0900
-Subject: [PATCH] ui/gtk3: Get PangoAttrList of auxiliary text from
- IBusText
-
-Since IBus auxiliary text would be one line, it's better to show the
-character attributes likes color, italic, bold, on the auxiliary text.
-
-Also deleted the cursor width from the X position of CandidatePanel
-because IBus preedit overrides the original cursor of the applications.
----
- ui/gtk3/candidatepanel.vala | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
-diff --git a/ui/gtk3/candidatepanel.vala b/ui/gtk3/candidatepanel.vala
-index ec2d3db4..d404c659 100644
---- a/ui/gtk3/candidatepanel.vala
-+++ b/ui/gtk3/candidatepanel.vala
-@@ -3,7 +3,7 @@
-  * ibus - The Input Bus
-  *
-  * Copyright(c) 2011-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>
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-@@ -153,6 +153,8 @@ public class CandidatePanel : Gtk.Box{
-     public void set_auxiliary_text(IBus.Text? text) {
-         if (text != null) {
-             m_aux_label.set_text(text.get_text());
-+            Pango.AttrList attrs = get_pango_attr_list_from_ibus_text(text);
-+            m_aux_label.set_attributes(attrs);
-             m_aux_label.show();
-         } else {
-             m_aux_label.set_text("");
-@@ -314,7 +316,7 @@ public class CandidatePanel : Gtk.Box{
- 
-     private void adjust_window_position_horizontal() {
-         Gdk.Point cursor_right_bottom = {
--                m_cursor_location.x + m_cursor_location.width,
-+                m_cursor_location.x,
-                 m_cursor_location.y + m_cursor_location.height
-         };
- 
--- 
-2.14.3
-
-From cf4e2f1d815b700b0470380e0ff428ff266cc18a Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Thu, 14 Jun 2018 17:29:06 +0900
-Subject: [PATCH] bus: Rename panel-extension to emoji-extension for CLI
-
----
- bus/main.c | 14 +++++++-------
- 1 file changed, 7 insertions(+), 7 deletions(-)
-
-diff --git a/bus/main.c b/bus/main.c
-index e1cc423b..2fb37b69 100644
---- a/bus/main.c
-+++ b/bus/main.c
-@@ -43,7 +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 *emoji_extension = "default";
- static gchar *config = "default";
- static gchar *desktop = "gnome";
- 
-@@ -67,7 +67,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" },
-+    { "emoji-extension", 'E', 0, G_OPTION_ARG_STRING, &emoji_extension, "specify the cmdline of emoji 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 },
-@@ -245,7 +245,7 @@ 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";
-+            emoji_extension = "disable";
-             break;
-         }
-     }
-@@ -286,7 +286,7 @@ main (gint argc, gchar **argv)
-     }
- 
- #ifdef EMOJI_DICT
--    if (g_strcmp0 (panel_extension, "default") == 0) {
-+    if (g_strcmp0 (emoji_extension, "default") == 0) {
-         BusComponent *component;
-         component = bus_ibus_impl_lookup_component_by_name (
-                 BUS_DEFAULT_IBUS, IBUS_SERVICE_PANEL_EXTENSION);
-@@ -298,9 +298,9 @@ main (gint argc, gchar **argv)
-             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))
-+    } else if (g_strcmp0 (emoji_extension, "disable") != 0 &&
-+               g_strcmp0 (emoji_extension, "") != 0) {
-+        if (!execute_cmdline (emoji_extension))
-             exit (-1);
-     }
- #endif
--- 
-2.14.3
-
-From ddc2284200971141947a37057356b4bbd84be7ce Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Thu, 14 Jun 2018 18:30:46 +0900
-Subject: [PATCH] tools: Add ibus read-config --engine-id option for engine
- schemas
-
-Fixed ibus read-config and reset-config options and also added --engine-id
-sub option for engine schemas.
-E.g.
-% ibus read-config --engine-id anthy
-% ibus read-config --engine-id com.github.libpinyin.ibus-libpinyin.libpinyin
----
- tools/main.vala | 99 +++++++++++++++++++++++++++++++++++++++++++++++++--------
- 1 file changed, 85 insertions(+), 14 deletions(-)
-
-diff --git a/tools/main.vala b/tools/main.vala
-index 8c0b64d3..6e201f30 100644
---- a/tools/main.vala
-+++ b/tools/main.vala
-@@ -3,7 +3,7 @@
-  * ibus - The Input Bus
-  *
-  * Copyright(c) 2013 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>
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-@@ -22,20 +22,17 @@
-  */
- 
- private const string IBUS_SCHEMAS_GENERAL = "org.freedesktop.ibus.general";
--private const string IBUS_SCHEMAS_GENERAL_PANEL =
--        "org.freedesktop.ibus.general.panel";
-+private const string IBUS_SCHEMAS_GENERAL_HOTKEY =
-+        "org.freedesktop.ibus.general.hotkey";
- private const string IBUS_SCHEMAS_PANEL = "org.freedesktop.ibus.panel";
--
--private const string[] IBUS_SCHEMAS = {
--    IBUS_SCHEMAS_GENERAL,
--    IBUS_SCHEMAS_GENERAL_PANEL,
--    IBUS_SCHEMAS_PANEL,
--};
-+private const string IBUS_SCHEMAS_PANEL_EMOJI =
-+        "org.freedesktop.ibus.panel.emoji";
- 
- bool name_only = false;
- /* system() exists as a public API. */
- bool is_system = false;
- string cache_file = null;
-+string engine_id = null;
- 
- class EngineList {
-     public IBus.EngineDesc[] data = {};
-@@ -292,15 +289,78 @@ int print_address(string[] argv) {
-     return Posix.EXIT_SUCCESS;
- }
- 
-+private int read_config_options(string[] argv) {
-+    const OptionEntry[] options = {
-+        { "engine-id", 0, 0, OptionArg.STRING, out engine_id,
-+          N_("Use engine schema paths instead of ibus core, " +
-+             "which can be comma-separated values."), "ENGINE_ID" },
-+        { null }
-+    };
-+
-+    var option = new OptionContext();
-+    option.add_main_entries(options, Config.GETTEXT_PACKAGE);
-+
-+    try {
-+        option.parse(ref argv);
-+    } catch (OptionError e) {
-+        stderr.printf("%s\n", e.message);
-+        return Posix.EXIT_FAILURE;
-+    }
-+    return Posix.EXIT_SUCCESS;
-+}
-+
-+private GLib.SList<string> get_ibus_schemas() {
-+    string[] ids = {};
-+    if (engine_id != null) {
-+        ids = engine_id.split(",");
-+    }
-+    GLib.SList<string> ibus_schemas = new GLib.SList<string>();
-+    GLib.SettingsSchemaSource schema_source =
-+            GLib.SettingsSchemaSource.get_default();
-+    string[] list_schemas = {};
-+    schema_source.list_schemas(true, out list_schemas, null);
-+    foreach (string schema in list_schemas) {
-+        if (ids.length != 0) {
-+            foreach (unowned string id in ids) {
-+                if (id == schema ||
-+                    schema.has_prefix("org.freedesktop.ibus.engine." + id)) {
-+                    ibus_schemas.prepend(schema);
-+                    break;
-+                }
-+            }
-+        } else if (schema.has_prefix("org.freedesktop.ibus") &&
-+            !schema.has_prefix("org.freedesktop.ibus.engine")) {
-+            ibus_schemas.prepend(schema);
-+        }
-+    }
-+    if (ibus_schemas.length() == 0) {
-+        printerr("Not found schemas of \"org.freedesktop.ibus\"\n");
-+        return ibus_schemas;
-+    }
-+    ibus_schemas.sort(GLib.strcmp);
-+
-+    return ibus_schemas;
-+}
-+
- int read_config(string[] argv) {
--    var output = new GLib.StringBuilder();
-+    if (read_config_options(argv) == Posix.EXIT_FAILURE)
-+        return Posix.EXIT_FAILURE;
-+
-+    GLib.SList<string> ibus_schemas = get_ibus_schemas();
-+    if (ibus_schemas.length() == 0)
-+        return Posix.EXIT_FAILURE;
- 
--    foreach (string schema in IBUS_SCHEMAS) {
-+    GLib.SettingsSchemaSource schema_source =
-+            GLib.SettingsSchemaSource.get_default();
-+    var output = new GLib.StringBuilder();
-+    foreach (string schema in ibus_schemas) {
-+        GLib.SettingsSchema settings_schema = schema_source.lookup(schema,
-+                                                                   false);
-         GLib.Settings settings = new GLib.Settings(schema);
- 
-         output.append_printf("SCHEMA: %s\n", schema);
- 
--        foreach (string key in settings.list_keys()) {
-+        foreach (string key in settings_schema.list_keys()) {
-             GLib.Variant variant = settings.get_value(key);
-             output.append_printf("  %s: %s\n", key, variant.print(true));
-         }
-@@ -311,14 +371,25 @@ int read_config(string[] argv) {
- }
- 
- int reset_config(string[] argv) {
-+    if (read_config_options(argv) == Posix.EXIT_FAILURE)
-+        return Posix.EXIT_FAILURE;
-+
-+    GLib.SList<string> ibus_schemas = get_ibus_schemas();
-+    if (ibus_schemas.length() == 0)
-+        return Posix.EXIT_FAILURE;
-+
-     print("%s\n", _("Resetting…"));
- 
--    foreach (string schema in IBUS_SCHEMAS) {
-+    GLib.SettingsSchemaSource schema_source =
-+            GLib.SettingsSchemaSource.get_default();
-+    foreach (string schema in ibus_schemas) {
-+        GLib.SettingsSchema settings_schema = schema_source.lookup(schema,
-+                                                                   false);
-         GLib.Settings settings = new GLib.Settings(schema);
- 
-         print("SCHEMA: %s\n", schema);
- 
--        foreach (string key in settings.list_keys()) {
-+        foreach (string key in settings_schema.list_keys()) {
-             print("  %s\n", key);
-             settings.reset(key);
-         }
--- 
-2.14.3
-
-From 37aa95f1adcdde82ef473936cadc0fa3fe8a4e44 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Fri, 15 Jun 2018 19:23:27 +0900
-Subject: [PATCH] setup: Replace GtkTable /w GtkGrid
-
----
- setup/setup.ui | 113 +++++++++++++++++++++------------------------------------
- 1 file changed, 41 insertions(+), 72 deletions(-)
-
-diff --git a/setup/setup.ui b/setup/setup.ui
-index 322f5146..e64b1046 100644
---- a/setup/setup.ui
-+++ b/setup/setup.ui
-@@ -99,11 +99,9 @@
-                     <property name="label_xalign">0</property>
-                     <property name="shadow_type">none</property>
-                     <child>
--                      <object class="GtkTable" id="table1">
-+                      <object class="GtkGrid" id="table1">
-                         <property name="visible">True</property>
-                         <property name="can_focus">False</property>
--                        <property name="n_rows">5</property>
--                        <property name="n_columns">2</property>
-                         <property name="column_spacing">12</property>
-                         <property name="row_spacing">6</property>
-                         <property name="margin_top">6</property>
-@@ -117,8 +115,8 @@
-                             <property name="label" translatable="yes">Next input method:</property>
-                           </object>
-                           <packing>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-+                            <property name="left_attach">0</property>
-+                            <property name="top_attach">0</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -131,10 +129,8 @@
-                             <property name="label" translatable="yes">Previous input method:</property>
-                           </object>
-                           <packing>
-+                            <property name="left_attach">0</property>
-                             <property name="top_attach">1</property>
--                            <property name="bottom_attach">2</property>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -143,6 +139,7 @@
-                             <property name="visible">True</property>
-                             <property name="can_focus">False</property>
-                             <property name="spacing">6</property>
-+                            <property name="hexpand">True</property>
-                             <child>
-                               <object class="GtkEntry" id="entry_switch_engine">
-                                 <property name="visible">True</property>
-@@ -174,8 +171,7 @@
-                           </object>
-                           <packing>
-                             <property name="left_attach">1</property>
--                            <property name="right_attach">2</property>
--                            <property name="y_options">GTK_FILL</property>
-+                            <property name="top_attach">0</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -184,6 +180,7 @@
-                             <property name="no_show_all">True</property>
-                             <property name="can_focus">False</property>
-                             <property name="spacing">6</property>
-+                            <property name="hexpand">True</property>
-                             <child>
-                               <object class="GtkEntry" id="entry_prev_engine">
-   >                                     <property name="no_show_all">True</property>
-@@ -217,10 +214,7 @@
-                           </object>
-                           <packing>
-                             <property name="left_attach">1</property>
--                            <property name="right_attach">2</property>
-                             <property name="top_attach">1</property>
--                            <property name="bottom_attach">2</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -232,10 +226,8 @@
-                             <property name="label" translatable="yes">Enable or disable:</property>
-                           </object>
-                           <packing>
-+                            <property name="left_attach">0</property>
-                             <property name="top_attach">2</property>
--                            <property name="bottom_attach">3</property>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -246,10 +238,8 @@
-                             <property name="label" translatable="yes">Enable:</property>
-                           </object>
-                           <packing>
-+                            <property name="left_attach">0</property>
-                             <property name="top_attach">3</property>
--                            <property name="bottom_attach">4</property>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -258,6 +248,7 @@
-                             <property name="no_show_all">True</property>
-                             <property name="can_focus">False</property>
-                             <property name="spacing">6</property>
-+                            <property name="hexpand">True</property>
-                             <child>
-                               <object class="GtkEntry" id="entry_enable_unconditional">
-                                 <property name="visible">True</property>
-@@ -289,10 +280,7 @@
-                           </object>
-                           <packing>
-                             <property name="left_attach">1</property>
--                            <property name="right_attach">2</property>
-                             <property name="top_attach">3</property>
--                            <property name="bottom_attach">4</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -303,10 +291,8 @@
-                             <property name="label" translatable="yes">Disable:</property>
-                           </object>
-                           <packing>
-+                            <property name="left_attach">0</property>
-                             <property name="top_attach">4</property>
--                            <property name="bottom_attach">5</property>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -315,6 +301,7 @@
-                             <property name="no_show_all">True</property>
-                             <property name="can_focus">False</property>
-                             <property name="spacing">6</property>
-+                            <property name="hexpand">True</property>
-                             <child>
-                               <object class="GtkEntry" id="entry_disable_unconditional">
-                                 <property name="visible">True</property>
-@@ -346,10 +333,7 @@
-                           </object>
-                           <packing>
-                             <property name="left_attach">1</property>
--                            <property name="right_attach">2</property>
-                             <property name="top_attach">4</property>
--                            <property name="bottom_attach">5</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                       </object>
-@@ -376,11 +360,9 @@
-                     <property name="label_xalign">0</property>
-                     <property name="shadow_type">none</property>
-                     <child>
--                      <object class="GtkTable" id="table2">
-+                      <object class="GtkGrid" id="table2">
-                         <property name="visible">True</property>
-                         <property name="can_focus">False</property>
--                        <property name="n_rows">7</property>
--                        <property name="n_columns">2</property>
-                         <property name="column_spacing">12</property>
-                         <property name="row_spacing">6</property>
-                         <property name="margin_top">6</property>
-@@ -393,10 +375,11 @@
-                             <property name="halign">start</property>
-                             <property name="label" translatable="yes">Candidates orientation:</property>
-                             <property name="justify">right</property>
-+                            <property name="hexpand">True</property>
-                           </object>
-                           <packing>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-+                            <property name="left_attach">0</property>
-+                            <property name="top_attach">0</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -404,6 +387,7 @@
-                             <property name="visible">True</property>
-                             <property name="can_focus">False</property>
-                             <property name="model">model_candidates_orientation</property>
-+                            <property name="hexpand">True</property>
-                             <child>
-                               <object class="GtkCellRendererText" id="renderer1"/>
-                               <attributes>
-@@ -413,8 +397,7 @@
-                           </object>
-                           <packing>
-                             <property name="left_attach">1</property>
--                            <property name="right_attach">2</property>
--                            <property name="y_options">GTK_FILL</property>
-+                            <property name="top_attach">0</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -425,12 +408,11 @@
-                             <property name="halign">start</property>
-                             <property name="label" translatable="yes">Show property panel:</property>
-                             <property name="justify">right</property>
-+                            <property name="hexpand">True</property>
-                           </object>
-                           <packing>
-+                            <property name="left_attach">0</property>
-                             <property name="top_attach">1</property>
--                            <property name="bottom_attach">2</property>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -440,12 +422,11 @@
-                             <property name="halign">start</property>
-                             <property name="label" translatable="yes">Language panel position:</property>
-                             <property name="justify">right</property>
-+                            <property name="hexpand">True</property>
-                           </object>
-                           <packing>
-+                            <property name="left_attach">0</property>
-                             <property name="top_attach">2</property>
--                            <property name="bottom_attach">3</property>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -453,6 +434,7 @@
-                             <property name="visible">True</property>
-                             <property name="can_focus">False</property>
-                             <property name="model">model_panel_show_mode</property>
-+                            <property name="hexpand">True</property>
-                             <child>
-                               <object class="GtkCellRendererText" id="renderer2"/>
-                               <attributes>
-@@ -462,10 +444,7 @@
-                           </object>
-                           <packing>
-                             <property name="left_attach">1</property>
--                            <property name="right_attach">2</property>
-                             <property name="top_attach">1</property>
--                            <property name="bottom_attach">2</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -473,6 +452,7 @@
-                             <property name="can_focus">False</property>
-                             <property name="no_show_all">True</property>
-                             <property name="model">model_panel_position</property>
-+                            <property name="hexpand">True</property>
-                             <child>
-                               <object class="GtkCellRendererText" id="renderer3"/>
-                               <attributes>
-@@ -482,10 +462,7 @@
-                           </object>
-                           <packing>
-                             <property name="left_attach">1</property>
--                            <property name="right_attach">2</property>
-                             <property name="top_attach">2</property>
--                            <property name="bottom_attach">3</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -499,13 +476,12 @@
-                             <property name="use_action_appearance">False</property>
-                             <property name="halign">start</property>
-                             <property name="draw_indicator">True</property>
-+                            <property name="hexpand">True</property>
-                           </object>
-                           <packing>
--                            <property name="right_attach">2</property>
-+                            <property name="left_attach">0</property>
-                             <property name="top_attach">3</property>
--                            <property name="bottom_attach">4</property>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-+                            <property name="width">2</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -519,13 +495,12 @@
-                             <property name="use_action_appearance">False</property>
-                             <property name="halign">start</property>
-                             <property name="draw_indicator">True</property>
-+                            <property name="hexpand">True</property>
-                           </object>
-                           <packing>
--                            <property name="right_attach">2</property>
-+                            <property name="left_attach">0</property>
-                             <property name="top_attach">4</property>
--                            <property name="bottom_attach">5</property>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-+                            <property name="width">2</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -539,13 +514,12 @@
-                             <property name="use_action_appearance">False</property>
-                             <property name="halign">start</property>
-                             <property name="draw_indicator">True</property>
-+                            <property name="hexpand">True</property>
-                           </object>
-                           <packing>
--                            <property name="right_attach">2</property>
-+                            <property name="left_attach">0</property>
-                             <property name="top_attach">5</property>
--                            <property name="bottom_attach">6</property>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-+                            <property name="width">2</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -559,12 +533,11 @@
-                             <property name="use_underline">True</property>
-                             <property name="halign">start</property>
-                             <property name="draw_indicator">True</property>
-+                            <property name="hexpand">True</property>
-                           </object>
-                           <packing>
-+                            <property name="left_attach">0</property>
-                             <property name="top_attach">6</property>
--                            <property name="bottom_attach">7</property>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -573,13 +546,11 @@
-                             <property name="can_focus">True</property>
-                             <property name="receives_default">True</property>
-                             <property name="use_action_appearance">False</property>
-+                            <property name="hexpand">True</property>
-                           </object>
-                           <packing>
-                             <property name="left_attach">1</property>
--                            <property name="right_attach">2</property>
-                             <property name="top_attach">6</property>
--                            <property name="bottom_attach">7</property>
--                            <property name="y_options">GTK_FILL</property>
-                           </packing>
-                         </child>
-                       </object>
-@@ -888,11 +859,9 @@
-                     <property name="label_xalign">0</property>
-                     <property name="shadow_type">none</property>
-                     <child>
--                      <object class="GtkTable" id="table_emoji1">
-+                      <object class="GtkGrid" id="table_emoji1">
-                         <property name="visible">True</property>
-                         <property name="can_focus">False</property>
--                        <property name="n_rows">5</property>
--                        <property name="n_columns">2</property>
-                         <property name="column_spacing">12</property>
-                         <property name="row_spacing">6</property>
-                         <property name="margin_top">6</property>
-@@ -906,8 +875,8 @@
-                             <property name="label" translatable="yes">Emoji choice:</property>
-                           </object>
-                           <packing>
--                            <property name="x_options">GTK_FILL</property>
--                            <property name="y_options">GTK_FILL</property>
-+                            <property name="left_attach">0</property>
-+                            <property name="top_attach">0</property>
-                           </packing>
-                         </child>
-                         <child>
-@@ -916,6 +885,7 @@
-                             <property name="visible">True</property>
-                             <property name="can_focus">False</property>
-                             <property name="spacing">6</property>
-+                            <property name="hexpand">true</property>
-                             <child>
-                               <object class="GtkEntry" id="entry_emoji_dialog">
-                                 <property name="visible">True</property>
-@@ -947,8 +917,7 @@
-                           </object>
-                           <packing>
-                             <property name="left_attach">1</property>
--                            <property name="right_attach">2</property>
--                            <property name="y_options">GTK_FILL</property>
-+                            <property name="top_attach">0</property>
-                           </packing>
-                         </child>
-                       </object>
--- 
-2.14.3
-
-From 5ee3f48049ecf128391da6448ae7e74786bd171b Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Mon, 18 Jun 2018 12:46:11 +0900
-Subject: [PATCH] Move input focus on Emojier to engines' preedit
-
----
- bindings/vala/IBus-1.0-custom.vala |   7 +
- bindings/vala/Makefile.am          |   3 +-
- bindings/vala/gdk-wayland.vapi     |   7 +
- bus/engineproxy.c                  |  53 +-
- bus/engineproxy.h                  |  25 +-
- bus/ibusimpl.c                     | 247 +++++++--
- bus/inputcontext.c                 | 399 +++++++++++----
- bus/inputcontext.h                 | 110 +++-
- bus/panelproxy.c                   | 210 +++++++-
- bus/panelproxy.h                   |  23 +-
- data/ibus.schemas.in               |  12 +
- setup/main.py                      |  10 +-
- setup/setup.ui                     |  58 ++-
- src/ibusengine.c                   | 305 ++++++++----
- src/ibuspanelservice.c             | 318 +++++++++++-
- src/ibuspanelservice.h             | 117 ++++-
- src/ibusshare.h                    |  17 +-
- src/ibusxevent.c                   | 375 +++++++++++++-
- src/ibusxevent.h                   | 143 +++++-
- ui/gtk3/Makefile.am                |   3 +
- ui/gtk3/emojier.vala               | 991 +++++++++++++++++++++++++++----------
- ui/gtk3/emojierapp.vala            |  74 ++-
- ui/gtk3/extension.vala             |   6 +-
- ui/gtk3/panel.vala                 |  23 +-
- ui/gtk3/panelbinding.vala          | 859 +++++++++++++++++++++++++++++---
- 25 files changed, 3695 insertions(+), 700 deletions(-)
- create mode 100644 bindings/vala/gdk-wayland.vapi
-
-diff --git a/bindings/vala/IBus-1.0-custom.vala b/bindings/vala/IBus-1.0-custom.vala
-index cf1fc3fa..7d34a8bd 100644
---- a/bindings/vala/IBus-1.0-custom.vala
-+++ b/bindings/vala/IBus-1.0-custom.vala
-@@ -6,8 +6,15 @@ namespace IBus {
- 		[CCode (cname = "ibus_text_new_from_static_string", has_construct_function = false)]
- 		public Text.from_static_string (string str);
- 	}
-+	public class ExtensionEvent : IBus.Serializable {
-+		[CCode (cname = "ibus_extension_event_new", has_construct_function = true)]
-+		public ExtensionEvent (string first_property_name, ...);
-+	}
- 	public class XEvent : IBus.Serializable {
- 		[CCode (cname = "ibus_x_event_new", has_construct_function = true)]
- 		public XEvent (string first_property_name, ...);
- 	}
-+	public class PanelService : IBus.Service {
-+                public void panel_extension_register_keys(string first_property_name, ...);
-+	}
- }
-diff --git a/bindings/vala/Makefile.am b/bindings/vala/Makefile.am
-index fc8e2f01..e4ecab97 100644
---- a/bindings/vala/Makefile.am
-+++ b/bindings/vala/Makefile.am
-@@ -3,7 +3,7 @@
- # ibus - The Input Bus
- #
- # Copyright (c) 2007-2016 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>
- # Copyright (c) 2007-2017 Red Hat, Inc.
- #
- # This library is free software; you can redistribute it and/or
-@@ -86,6 +86,7 @@ EXTRA_DIST =                                    \
-     ibus-1.0.deps                               \
-     ibus-emoji-dialog-1.0.deps                  \
-     config.vapi                                 \
-+    gdk-wayland.vapi                            \
-     xi.vapi                                     \
-     $(NULL)
- 
-diff --git a/bindings/vala/gdk-wayland.vapi b/bindings/vala/gdk-wayland.vapi
-new file mode 100644
-index 00000000..c65f2be4
---- /dev/null
-+++ b/bindings/vala/gdk-wayland.vapi
-@@ -0,0 +1,7 @@
-+[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "gdk/gdkwayland.h")]
-+namespace GdkWayland
-+{
-+    [CCode (type_id = "gdk_wayland_display_get_type ()")]
-+    public class Display : Gdk.Display {
-+    }
-+}
-diff --git a/bus/engineproxy.c b/bus/engineproxy.c
-index 175aec56..2d98995c 100644
---- a/bus/engineproxy.c
-+++ b/bus/engineproxy.c
-@@ -377,10 +377,10 @@ bus_engine_proxy_class_init (BusEngineProxyClass *class)
-             G_SIGNAL_RUN_LAST,
-             0,
-             NULL, NULL,
--            bus_marshal_VOID__VARIANT,
-+            bus_marshal_VOID__OBJECT,
-             G_TYPE_NONE,
-             1,
--            G_TYPE_VARIANT);
-+            IBUS_TYPE_EXTENSION_EVENT);
- 
-     text_empty = ibus_text_new_from_static_string ("");
-     g_object_ref_sink (text_empty);
-@@ -644,7 +644,16 @@ bus_engine_proxy_g_signal (GDBusProxy  *proxy,
-     }
- 
-     if (g_strcmp0 (signal_name, "PanelExtension") == 0) {
--        g_signal_emit (engine, engine_signals[PANEL_EXTENSION], 0, parameters);
-+        GVariant *arg0 = NULL;
-+        g_variant_get (parameters, "(v)", &arg0);
-+        g_return_if_fail (arg0 != NULL);
-+
-+        IBusExtensionEvent *event = IBUS_EXTENSION_EVENT (
-+                ibus_serializable_deserialize (arg0));
-+        g_variant_unref (arg0);
-+        g_return_if_fail (event != NULL);
-+        g_signal_emit (engine, engine_signals[PANEL_EXTENSION], 0, event);
-+        _g_object_unref_if_floating (event);
-         return;
-     }
- 
-@@ -1323,6 +1332,44 @@ bus_engine_proxy_is_enabled (BusEngineProxy *engine)
-     return engine->enabled;
- }
- 
-+void
-+bus_engine_proxy_panel_extension_received (BusEngineProxy     *engine,
-+                                           IBusExtensionEvent *event)
-+{
-+    GVariant *variant;
-+    g_assert (BUS_IS_ENGINE_PROXY (engine));
-+    g_assert (IBUS_IS_EXTENSION_EVENT (event));
-+
-+    variant = ibus_serializable_serialize_object (
-+            IBUS_SERIALIZABLE (event));
-+    g_return_if_fail (variant != NULL);
-+    g_dbus_proxy_call ((GDBusProxy *)engine,
-+                       "PanelExtensionReceived",
-+                       g_variant_new ("(v)", variant),
-+                       G_DBUS_CALL_FLAGS_NONE,
-+                       -1,
-+                       NULL,
-+                       NULL,
-+                       NULL);
-+}
-+
-+void
-+bus_engine_proxy_panel_extension_register_keys (BusEngineProxy *engine,
-+                                                GVariant       *parameters)
-+{
-+    g_assert (BUS_IS_ENGINE_PROXY (engine));
-+    g_assert (parameters);
-+
-+    g_dbus_proxy_call ((GDBusProxy *)engine,
-+                       "PanelExtensionRegisterKeys",
-+                       g_variant_new ("(v)", g_variant_ref (parameters)),
-+                       G_DBUS_CALL_FLAGS_NONE,
-+                       -1,
-+                       NULL,
-+                       NULL,
-+                       NULL);
-+}
-+
- static gboolean
- initable_init (GInitable     *initable,
-                GCancellable  *cancellable,
-diff --git a/bus/engineproxy.h b/bus/engineproxy.h
-index 528e61b7..a3006b47 100644
---- a/bus/engineproxy.h
-+++ b/bus/engineproxy.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.fujiwara@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
-@@ -325,5 +326,27 @@ void            bus_engine_proxy_set_content_type
- IBusPropList   *bus_engine_proxy_get_properties
-                                              (BusEngineProxy     *engine);
- 
-+/**
-+ * bus_engine_proxy_panel_extension_received:
-+ * @engine: A #BusEngineProxy.
-+ * @event: An #IBusExtensionEvent.
-+ *
-+ * Send an #IBusExtensionEvent to the engine.
-+ */
-+void            bus_engine_proxy_panel_extension_received
-+                                             (BusEngineProxy     *engine,
-+                                              IBusExtensionEvent *event);
-+
-+/**
-+ * bus_engine_proxy_panel_extension_register_keys:
-+ * @engine: A #BusEngineProxy.
-+ * @parameters: A #GVariant array which includes the name and shortcut keys.
-+ *
-+ * Send shortcut keys to the engine to enable the extension.
-+ */
-+void            bus_engine_proxy_panel_extension_register_keys
-+                                             (BusEngineProxy     *engine,
-+                                              GVariant           *parameters);
-+
- G_END_DECLS
- #endif
-diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
-index a4ce3d9d..ec1caea8 100644
---- a/bus/ibusimpl.c
-+++ b/bus/ibusimpl.c
-@@ -74,7 +74,8 @@ struct _BusIBusImpl {
- 
-     BusInputContext *focused_context;
-     BusPanelProxy   *panel;
--    BusPanelProxy   *extension;
-+    BusPanelProxy   *emoji_extension;
-+    gboolean         enable_emoji_extension;
- 
-     /* a default keymap of ibus-daemon (usually "us") which is used only
-      * when use_sys_layout is FALSE. */
-@@ -83,6 +84,7 @@ struct _BusIBusImpl {
-     gboolean use_global_engine;
-     gchar *global_engine_name;
-     gchar *global_previous_engine_name;
-+    GVariant *extension_register_keys;
- };
- 
- struct _BusIBusImplClass {
-@@ -294,40 +296,158 @@ _panel_destroy_cb (BusPanelProxy *panel,
- 
-     if (ibus->panel == panel)
-         ibus->panel = NULL;
--    else if (ibus->extension == panel)
--        ibus->extension = NULL;
-+    else if (ibus->emoji_extension == panel)
-+        ibus->emoji_extension = NULL;
-     else
-         g_return_if_reached ();
-     g_object_unref (panel);
- }
- 
- static void
--bus_ibus_impl_panel_extension_received (BusIBusImpl *ibus,
--                                        GVariant    *parameters)
-+bus_ibus_impl_set_panel_extension_mode (BusIBusImpl        *ibus,
-+                                        IBusExtensionEvent *event)
- {
--    if (!ibus->extension) {
-+    gboolean is_extension = FALSE;
-+    g_return_if_fail (BUS_IS_IBUS_IMPL (ibus));
-+    g_return_if_fail (IBUS_IS_EXTENSION_EVENT (event));
-+
-+    if (!ibus->emoji_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));
-+    g_return_if_fail (BUS_IS_PANEL_PROXY (ibus->emoji_extension));
-+
-+    ibus->enable_emoji_extension = ibus_extension_event_is_enabled (event);
-+    is_extension = ibus_extension_event_is_extension (event);
-+    if (ibus->focused_context != NULL) {
-+        if (ibus->enable_emoji_extension) {
-+            bus_input_context_set_emoji_extension (ibus->focused_context,
-+                                                   ibus->emoji_extension);
-+        } else {
-+            bus_input_context_set_emoji_extension (ibus->focused_context, NULL);
-+        }
-+        if (is_extension)
-+            bus_input_context_panel_extension_received (ibus->focused_context,
-+                                                        event);
-+    }
-+    if (is_extension)
-+        return;
- 
-     /* 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);
-+    bus_panel_proxy_panel_extension_received (ibus->emoji_extension,
-+                                              event);
-+}
-+
-+static void
-+bus_ibus_impl_set_panel_extension_keys (BusIBusImpl *ibus,
-+                                        GVariant    *parameters)
-+{
-+    BusEngineProxy *engine = NULL;
-+
-+    g_return_if_fail (BUS_IS_IBUS_IMPL (ibus));
-+    g_return_if_fail (parameters);
-+
-+    if (!ibus->emoji_extension) {
-+        g_warning ("Panel extension is not running.");
-+        return;
-+    }
-+
-+    if (ibus->extension_register_keys)
-+        g_variant_unref (ibus->extension_register_keys);
-+    ibus->extension_register_keys = g_variant_ref_sink (parameters);
-+    if (ibus->focused_context != NULL) {
-+            engine = bus_input_context_get_engine (ibus->focused_context);
-+    }
-+    if (!engine)
-+        return;
-+    bus_engine_proxy_panel_extension_register_keys (engine, parameters);
- }
- 
- static void
--_panel_panel_extension_cb (BusPanelProxy *panel,
--                           GVariant      *parameters,
--                           BusIBusImpl  *ibus)
-+_panel_panel_extension_cb (BusPanelProxy      *panel,
-+                           IBusExtensionEvent *event,
-+                           BusIBusImpl        *ibus)
- {
--    bus_ibus_impl_panel_extension_received (ibus, parameters);
-+    bus_ibus_impl_set_panel_extension_mode (ibus, event);
-+}
-+
-+static void
-+_panel_panel_extension_register_keys_cb (BusInputContext *context,
-+                                         GVariant        *parameters,
-+                                         BusIBusImpl     *ibus)
-+{
-+    bus_ibus_impl_set_panel_extension_keys (ibus, parameters);
-+}
-+
-+static void
-+_panel_update_preedit_text_received_cb (BusPanelProxy *panel,
-+                                        IBusText      *text,
-+                                        guint          cursor_pos,
-+                                        gboolean       visible,
-+                                        BusIBusImpl   *ibus)
-+{
-+    g_return_if_fail (BUS_IS_IBUS_IMPL (ibus));
-+
-+    if (!ibus->focused_context)
-+        return;
-+    bus_input_context_update_preedit_text (ibus->focused_context,
-+        text, cursor_pos, visible, IBUS_ENGINE_PREEDIT_CLEAR, FALSE);
-+}
-+
-+static void
-+_panel_update_lookup_table_received_cb (BusPanelProxy   *panel,
-+                                        IBusLookupTable *table,
-+                                        gboolean         visible,
-+                                        BusIBusImpl     *ibus)
-+{
-+    g_return_if_fail (BUS_IS_IBUS_IMPL (ibus));
-+    g_return_if_fail (IBUS_IS_LOOKUP_TABLE (table));
-+
-+    if (!ibus->focused_context)
-+        return;
-+    /* Call bus_input_context_update_lookup_table() instead of
-+     * bus_panel_proxy_update_lookup_table() for panel extensions because
-+     * bus_input_context_page_up() can call bus_panel_proxy_page_up_received().
-+     */
-+    bus_input_context_update_lookup_table (
-+            ibus->focused_context, table, visible, TRUE);
-+}
-+
-+static void
-+_panel_update_auxiliary_text_received_cb (BusPanelProxy *panel,
-+                                          IBusText      *text,
-+                                          gboolean       visible,
-+                                          BusIBusImpl   *ibus)
-+{
-+    g_return_if_fail (BUS_IS_IBUS_IMPL (ibus));
-+    g_return_if_fail (IBUS_IS_TEXT (text));
-+
-+    if (!ibus->panel)
-+        return;
-+    bus_panel_proxy_update_auxiliary_text (
-+            ibus->panel, text, visible);
-+}
-+
-+static void
-+_panel_show_lookup_table_received_cb (BusPanelProxy *panel,
-+                                      BusIBusImpl   *ibus)
-+{
-+    g_return_if_fail (BUS_IS_IBUS_IMPL (ibus));
-+
-+    if (ibus->panel)
-+        bus_panel_proxy_show_lookup_table (ibus->panel);
-+}
-+
-+static void
-+_panel_hide_lookup_table_received_cb (BusPanelProxy *panel,
-+                                      BusIBusImpl   *ibus)
-+{
-+    g_return_if_fail (BUS_IS_IBUS_IMPL (ibus));
-+
-+    if (ibus->panel)
-+        bus_panel_proxy_hide_lookup_table (ibus->panel);
- }
- 
- static void
-@@ -361,8 +481,8 @@ _dbus_name_owner_changed_cb (BusDBusImpl   *dbus,
- 
-     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;
-+    else if (!g_strcmp0 (name, IBUS_SERVICE_PANEL_EXTENSION_EMOJI))
-+        panel_type = PANEL_TYPE_EXTENSION_EMOJI;
- 
-     if (panel_type != PANEL_TYPE_NONE) {
-         if (g_strcmp0 (new_name, "") != 0) {
-@@ -370,7 +490,7 @@ _dbus_name_owner_changed_cb (BusDBusImpl   *dbus,
-             BusConnection *connection;
-             BusInputContext *context = NULL;
-             BusPanelProxy   **panel = (panel_type == PANEL_TYPE_PANEL) ?
--                                       &ibus->panel : &ibus->extension;
-+                                      &ibus->panel : &ibus->emoji_extension;
- 
-             if (*panel != NULL) {
-                 ibus_proxy_destroy ((IBusProxy *)(*panel));
-@@ -383,6 +503,8 @@ _dbus_name_owner_changed_cb (BusDBusImpl   *dbus,
-             g_return_if_fail (connection != NULL);
- 
-             *panel = bus_panel_proxy_new (connection, panel_type);
-+            if (panel_type == PANEL_TYPE_EXTENSION_EMOJI)
-+                ibus->enable_emoji_extension = FALSE;
- 
-             g_signal_connect (*panel,
-                               "destroy",
-@@ -392,6 +514,26 @@ _dbus_name_owner_changed_cb (BusDBusImpl   *dbus,
-                               "panel-extension",
-                               G_CALLBACK (_panel_panel_extension_cb),
-                               ibus);
-+            g_signal_connect (*panel,
-+                              "panel-extension-register-keys",
-+                              G_CALLBACK (
-+                                      _panel_panel_extension_register_keys_cb),
-+                              ibus);
-+            g_signal_connect (
-+                    *panel,
-+                    "update-preedit-text-received",
-+                    G_CALLBACK (_panel_update_preedit_text_received_cb),
-+                    ibus);
-+            g_signal_connect (
-+                    *panel,
-+                    "update-lookup-table-received",
-+                    G_CALLBACK (_panel_update_lookup_table_received_cb),
-+                    ibus);
-+            g_signal_connect (
-+                    *panel,
-+                    "update-auxiliary-text-received",
-+                    G_CALLBACK (_panel_update_auxiliary_text_received_cb),
-+                    ibus);
- 
-             if (ibus->focused_context != NULL) {
-                 context = ibus->focused_context;
-@@ -450,7 +592,7 @@ bus_ibus_impl_init (BusIBusImpl *ibus)
-     ibus->contexts = NULL;
-     ibus->focused_context = NULL;
-     ibus->panel = NULL;
--    ibus->extension = NULL;
-+    ibus->emoji_extension = NULL;
- 
-     ibus->keymap = ibus_keymap_get ("us");
- 
-@@ -650,11 +792,11 @@ bus_ibus_impl_set_context_engine_from_desc (BusIBusImpl     *ibus,
- }
- 
- static void
--_context_panel_extension_cb (BusInputContext *context,
--                             GVariant        *parameters,
--                             BusIBusImpl     *ibus)
-+_context_panel_extension_cb (BusInputContext    *context,
-+                             IBusExtensionEvent *event,
-+                             BusIBusImpl        *ibus)
- {
--    bus_ibus_impl_panel_extension_received (ibus, parameters);
-+    bus_ibus_impl_set_panel_extension_mode (ibus, event);
- }
- 
- const static struct {
-@@ -694,13 +836,18 @@ bus_ibus_impl_set_focused_context (BusIBusImpl     *ibus,
-             if (engine) {
-                 g_object_ref (engine);
-                 bus_input_context_set_engine (ibus->focused_context, NULL);
-+                bus_input_context_set_emoji_extension (ibus->focused_context,
-+                                                       NULL);
-             }
-         }
- 
-         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);
-+        if (ibus->emoji_extension != NULL) {
-+            bus_panel_proxy_focus_out (ibus->emoji_extension,
-+                                       ibus->focused_context);
-+        }
-+        bus_input_context_set_emoji_extension (ibus->focused_context, NULL);
- 
-         bus_input_context_get_content_type (ibus->focused_context,
-                                             &purpose, &hints);
-@@ -724,6 +871,12 @@ bus_ibus_impl_set_focused_context (BusIBusImpl     *ibus,
-         if (engine != NULL) {
-             bus_input_context_set_engine (context, engine);
-             bus_input_context_enable (context);
-+            if (ibus->enable_emoji_extension) {
-+                bus_input_context_set_emoji_extension (context,
-+                                                       ibus->emoji_extension);
-+            } else {
-+                bus_input_context_set_emoji_extension (context, NULL);
-+            }
-         }
-         for (i = 0; i < G_N_ELEMENTS(context_signals); i++) {
-             g_signal_connect (ibus->focused_context,
-@@ -734,8 +887,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 (ibus->emoji_extension != NULL)
-+            bus_panel_proxy_focus_in (ibus->emoji_extension, context);
-     }
- 
-     if (engine != NULL)
-@@ -751,6 +904,12 @@ bus_ibus_impl_set_global_engine (BusIBusImpl    *ibus,
- 
-     if (ibus->focused_context) {
-         bus_input_context_set_engine (ibus->focused_context, engine);
-+        if (ibus->enable_emoji_extension) {
-+            bus_input_context_set_emoji_extension (ibus->focused_context,
-+                                                   ibus->emoji_extension);
-+        } else {
-+            bus_input_context_set_emoji_extension (ibus->focused_context, NULL);
-+        }
-     } else if (ibus->fake_context) {
-         bus_input_context_set_engine (ibus->fake_context, engine);
-     }
-@@ -927,9 +1086,9 @@ _context_destroy_cb (BusInputContext    *context,
-         bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS) {
-         bus_panel_proxy_destroy_context (ibus->panel, context);
-     }
--    if (ibus->extension &&
-+    if (ibus->emoji_extension &&
-         bus_input_context_get_capabilities (context) & IBUS_CAP_FOCUS) {
--        bus_panel_proxy_destroy_context (ibus->extension, context);
-+        bus_panel_proxy_destroy_context (ibus->emoji_extension, context);
-     }
- 
-     ibus->contexts = g_list_remove (ibus->contexts, context);
-@@ -1489,6 +1648,7 @@ _ibus_set_global_engine_ready_cb (BusInputContext       *context,
-     else {
-         g_dbus_method_invocation_return_value (data->invocation, NULL);
- 
-+        BusEngineProxy *engine = bus_input_context_get_engine (context);
-         if (ibus->use_global_engine && (context != ibus->focused_context)) {
-             /* context and ibus->focused_context don't match. This means that
-              * the focus is moved before _ibus_set_global_engine() asynchronous
-@@ -1496,14 +1656,28 @@ _ibus_set_global_engine_ready_cb (BusInputContext       *context,
-              * being focused hasn't been updated. Update the engine here so that
-              * subsequent _ibus_get_global_engine() call could return a
-              * consistent engine name. */
--            BusEngineProxy *engine = bus_input_context_get_engine (context);
-             if (engine && ibus->focused_context != NULL) {
-                 g_object_ref (engine);
-                 bus_input_context_set_engine (context, NULL);
-+                bus_input_context_set_emoji_extension (context, NULL);
-                 bus_input_context_set_engine (ibus->focused_context, engine);
-+                if (ibus->enable_emoji_extension) {
-+                    bus_input_context_set_emoji_extension (
-+                            ibus->focused_context,
-+                            ibus->emoji_extension);
-+                } else {
-+                    bus_input_context_set_emoji_extension (
-+                            ibus->focused_context,
-+                            NULL);
-+                }
-                 g_object_unref (engine);
-             }
-         }
-+        if (engine && ibus->extension_register_keys) {
-+            bus_engine_proxy_panel_extension_register_keys (
-+                    engine,
-+                    ibus->extension_register_keys);
-+        }
-     }
- 
-     g_object_unref (ibus);
-@@ -2013,11 +2187,12 @@ bus_ibus_impl_registry_destroy (BusIBusImpl *ibus)
-     g_list_free_full (ibus->components, g_object_unref);
-     ibus->components = NULL;
- 
--    g_hash_table_destroy (ibus->engine_table);
--    ibus->engine_table = NULL;
-+    g_clear_pointer (&ibus->engine_table, g_hash_table_destroy);
- 
--    ibus_object_destroy (IBUS_OBJECT (ibus->registry));
--    ibus->registry = NULL;
-+    g_clear_pointer (&ibus->registry, ibus_object_destroy);
-+
-+    if (ibus->extension_register_keys)
-+        g_clear_pointer (&ibus->extension_register_keys, g_variant_unref);
- }
- 
- static gint
-diff --git a/bus/inputcontext.c b/bus/inputcontext.c
-index dfb98c36..bf9eafcf 100644
---- a/bus/inputcontext.c
-+++ b/bus/inputcontext.c
-@@ -94,6 +94,9 @@ struct _BusInputContext {
-     /* content-type (primary purpose and hints) */
-     guint    purpose;
-     guint    hints;
-+
-+    BusPanelProxy *emoji_extension;
-+    gboolean is_extension_lookup_table;
- };
- 
- struct _BusInputContextClass {
-@@ -162,16 +165,12 @@ static gboolean bus_input_context_service_set_property
-                                     GError               **error);
- static void     bus_input_context_unset_engine
-                                    (BusInputContext       *context);
--static void     bus_input_context_update_preedit_text
--                                   (BusInputContext       *context,
--                                    IBusText              *text,
--                                    guint                  cursor_pos,
--                                    gboolean               visible,
--                                    guint                  mode);
- static void     bus_input_context_show_preedit_text
--                                   (BusInputContext       *context);
-+                                   (BusInputContext       *context,
-+                                    gboolean               is_extension);
- static void     bus_input_context_hide_preedit_text
--                                   (BusInputContext       *context);
-+                                   (BusInputContext       *context,
-+                                    gboolean               is_extension);
- static void     bus_input_context_update_auxiliary_text
-                                    (BusInputContext       *context,
-                                     IBusText              *text,
-@@ -180,10 +179,6 @@ static void     bus_input_context_show_auxiliary_text
-                                    (BusInputContext       *context);
- static void     bus_input_context_hide_auxiliary_text
-                                    (BusInputContext       *context);
--static void     bus_input_context_update_lookup_table
--                                   (BusInputContext       *context,
--                                    IBusLookupTable       *table,
--                                    gboolean               visible);
- static void     bus_input_context_show_lookup_table
-                                    (BusInputContext       *context);
- static void     bus_input_context_hide_lookup_table
-@@ -605,10 +600,10 @@ bus_input_context_class_init (BusInputContextClass *class)
-             G_SIGNAL_RUN_LAST,
-             0,
-             NULL, NULL,
--            bus_marshal_VOID__VARIANT,
-+            bus_marshal_VOID__OBJECT,
-             G_TYPE_NONE,
-             1,
--            G_TYPE_VARIANT);
-+            IBUS_TYPE_EXTENSION_EVENT);
- 
-     text_empty = ibus_text_new_from_string ("");
-     g_object_ref_sink (text_empty);
-@@ -760,28 +755,85 @@ bus_input_context_property_changed (BusInputContext *context,
-                                           error);
- }
- 
-+
-+/**
-+ * _panel_process_key_event_cb:
-+ *
-+ * A GAsyncReadyCallback function to be called when
-+ * bus_panel_proxy_process_key_event() is finished.
-+ */
-+static void
-+_panel_process_key_event_cb (GObject               *source,
-+                             GAsyncResult          *res,
-+                             GDBusMethodInvocation *invocation)
-+{
-+    GError *error = NULL;
-+    GVariant *value = g_dbus_proxy_call_finish ((GDBusProxy *)source,
-+                                                 res,
-+                                                 &error);
-+    if (value != NULL) {
-+        g_dbus_method_invocation_return_value (invocation, value);
-+        g_variant_unref (value);
-+    }
-+    else {
-+        g_dbus_method_invocation_return_gerror (invocation, error);
-+        g_error_free (error);
-+    }
-+}
-+
-+typedef struct _ProcessKeyEventData ProcessKeyEventData;
-+struct _ProcessKeyEventData {
-+    GDBusMethodInvocation *invocation;
-+    BusInputContext       *context;
-+    guint keyval;
-+    guint keycode;
-+    guint modifiers;
-+};
-+
- /**
-  * _ic_process_key_event_reply_cb:
-  *
-- * A GAsyncReadyCallback function to be called when bus_engine_proxy_process_key_event() is finished.
-+ * A GAsyncReadyCallback function to be called when
-+ * bus_engine_proxy_process_key_event() is finished.
-  */
- static void
- _ic_process_key_event_reply_cb (GObject               *source,
-                                 GAsyncResult          *res,
--                                GDBusMethodInvocation *invocation)
-+                                ProcessKeyEventData   *data)
- {
-+    GDBusMethodInvocation *invocation = data->invocation;
-+    BusInputContext *context = data->context;
-+    guint keyval = data->keyval;
-+    guint keycode = data->keycode;
-+    guint modifiers = data->modifiers;
-     GError *error = NULL;
-     GVariant *value = g_dbus_proxy_call_finish ((GDBusProxy *)source,
-                                                  res,
-                                                  &error);
-+
-     if (value != NULL) {
--        g_dbus_method_invocation_return_value (invocation, value);
-+        gboolean retval = FALSE;
-+        g_variant_get (value, "(b)", &retval);
-+        if (context->emoji_extension && !retval) {
-+            bus_panel_proxy_process_key_event (context->emoji_extension,
-+                                               keyval,
-+                                               keycode,
-+                                               modifiers,
-+                                               (GAsyncReadyCallback)
-+                                                    _panel_process_key_event_cb,
-+                                               invocation);
-+        } else {
-+            g_dbus_method_invocation_return_value (invocation, value);
-+        }
-         g_variant_unref (value);
-     }
-     else {
-         g_dbus_method_invocation_return_gerror (invocation, error);
-         g_error_free (error);
-     }
-+
-+    g_object_unref (context);
-+    g_slice_free (ProcessKeyEventData, data);
- }
- 
- /**
-@@ -840,12 +892,19 @@ _ic_process_key_event  (BusInputContext       *context,
- 
-     /* ignore key events, if it is a fake input context */
-     if (context->has_focus && context->engine && context->fake == FALSE) {
-+        ProcessKeyEventData *data = g_slice_new0 (ProcessKeyEventData);
-+        data->invocation = invocation;
-+        data->context = g_object_ref (context);
-+        data->keyval = keyval;
-+        data->keycode = keycode;
-+        data->modifiers = modifiers;
-         bus_engine_proxy_process_key_event (context->engine,
-                                             keyval,
-                                             keycode,
-                                             modifiers,
--                                            (GAsyncReadyCallback) _ic_process_key_event_reply_cb,
--                                            invocation);
-+                                            (GAsyncReadyCallback)
-+                                                _ic_process_key_event_reply_cb,
-+                                            data);
-     }
-     else {
-         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", FALSE));
-@@ -880,6 +939,13 @@ _ic_set_cursor_location (BusInputContext       *context,
-                        context->y,
-                        context->w,
-                        context->h);
-+        if (context->emoji_extension) {
-+            bus_panel_proxy_set_cursor_location (context->emoji_extension,
-+                                                 context->x,
-+                                                 context->y,
-+                                                 context->w,
-+                                                 context->h);
-+        }
-     }
- }
- 
-@@ -912,6 +978,14 @@ _ic_set_cursor_location_relative (BusInputContext       *context,
-                        y,
-                        w,
-                        h);
-+        if (context->emoji_extension) {
-+            bus_panel_proxy_set_cursor_location_relative (
-+                    context->emoji_extension,
-+                    x,
-+                    y,
-+                    w,
-+                    h);
-+        }
-     }
- }
- 
-@@ -1394,7 +1468,7 @@ bus_input_context_clear_preedit_text (BusInputContext *context)
- 
-     /* always clear preedit text */
-     bus_input_context_update_preedit_text (context,
--        text_empty, 0, FALSE, IBUS_ENGINE_PREEDIT_CLEAR);
-+        text_empty, 0, FALSE, IBUS_ENGINE_PREEDIT_CLEAR, TRUE);
- }
- 
- void
-@@ -1407,7 +1481,10 @@ bus_input_context_focus_out (BusInputContext *context)
- 
-     bus_input_context_clear_preedit_text (context);
-     bus_input_context_update_auxiliary_text (context, text_empty, FALSE);
--    bus_input_context_update_lookup_table (context, lookup_table_empty, FALSE);
-+    bus_input_context_update_lookup_table (context,
-+                                           lookup_table_empty,
-+                                           FALSE,
-+                                           FALSE);
-     bus_input_context_register_properties (context, props_empty);
- 
-     if (context->engine) {
-@@ -1427,7 +1504,12 @@ bus_input_context_focus_out (BusInputContext *context)
-     {                                                                       \
-         g_assert (BUS_IS_INPUT_CONTEXT (context));                          \
-                                                                             \
--        if (context->has_focus && context->engine) {    \
-+        if (context->is_extension_lookup_table &&                           \
-+            context->emoji_extension) {                                     \
-+            bus_panel_proxy_##name##_lookup_table (context->emoji_extension); \
-+            return;                                                         \
-+        }                                                                   \
-+        if (context->has_focus && context->engine) {                        \
-             bus_engine_proxy_##name (context->engine);                      \
-         }                                                                   \
-     }
-@@ -1447,6 +1529,14 @@ bus_input_context_candidate_clicked (BusInputContext *context,
- {
-     g_assert (BUS_IS_INPUT_CONTEXT (context));
- 
-+    if (context->is_extension_lookup_table && context->emoji_extension) {
-+        bus_panel_proxy_candidate_clicked_lookup_table (
-+                context->emoji_extension,
-+                index,
-+                button,
-+                state);
-+            return;
-+    }
-     if (context->engine) {
-         bus_engine_proxy_candidate_clicked (context->engine,
-                                             index,
-@@ -1467,61 +1557,33 @@ bus_input_context_property_activate (BusInputContext *context,
-     }
- }
- 
--/**
-- * bus_input_context_update_preedit_text:
-- *
-- * Update a preedit text. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
-- */
--static void
--bus_input_context_update_preedit_text (BusInputContext *context,
--                                       IBusText        *text,
--                                       guint            cursor_pos,
--                                       gboolean         visible,
--                                       guint            mode)
--{
--    g_assert (BUS_IS_INPUT_CONTEXT (context));
--
--    if (context->preedit_text) {
--        g_object_unref (context->preedit_text);
--    }
--
--    context->preedit_text = (IBusText *) g_object_ref_sink (text ? text : text_empty);
--    context->preedit_cursor_pos = cursor_pos;
--    context->preedit_visible = visible;
--    context->preedit_mode = mode;
--
--    if (PREEDIT_CONDITION) {
--        GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)context->preedit_text);
--        bus_input_context_emit_signal (context,
--                                       "UpdatePreeditText",
--                                       g_variant_new ("(vub)", variant, context->preedit_cursor_pos, context->preedit_visible),
--                                       NULL);
--    }
--    else {
--        g_signal_emit (context,
--                       context_signals[UPDATE_PREEDIT_TEXT],
--                       0,
--                       context->preedit_text,
--                       context->preedit_cursor_pos,
--                       context->preedit_visible);
--    }
--}
--
- /**
-  * bus_input_context_show_preedit_text:
-  *
-  * Show a preedit text. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
-  */
- static void
--bus_input_context_show_preedit_text (BusInputContext *context)
-+bus_input_context_show_preedit_text (BusInputContext *context,
-+                                     gboolean         is_extension)
- {
-     g_assert (BUS_IS_INPUT_CONTEXT (context));
- 
--    if (context->preedit_visible) {
-+    if (context->preedit_visible)
-         return;
--    }
-+    if (!is_extension && context->emoji_extension)
-+        return;
-+
-+    if (!is_extension)
-+        context->preedit_visible = TRUE;
- 
--    context->preedit_visible = TRUE;
-+    if (context->emoji_extension && !is_extension) {
-+        /* Do not use HIDE_PREEDIT_TEXT signal below but call
-+         * bus_panel_proxy_hide_preedit_text() directly for the extension only
-+         * but not for the normal panel.
-+         */
-+        bus_panel_proxy_show_preedit_text (context->emoji_extension);
-+        return;
-+    }
- 
-     if (PREEDIT_CONDITION) {
-         bus_input_context_emit_signal (context,
-@@ -1542,15 +1604,25 @@ bus_input_context_show_preedit_text (BusInputContext *context)
-  * Hide a preedit text. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
-  */
- static void
--bus_input_context_hide_preedit_text (BusInputContext *context)
-+bus_input_context_hide_preedit_text (BusInputContext *context,
-+                                     gboolean         is_extension)
- {
-     g_assert (BUS_IS_INPUT_CONTEXT (context));
- 
--    if (!context->preedit_visible) {
-+    if (!is_extension && !context->preedit_visible)
-         return;
--    }
- 
--    context->preedit_visible = FALSE;
-+    if (!is_extension)
-+        context->preedit_visible = FALSE;
-+
-+    if (context->emoji_extension && !is_extension) {
-+        /* Do not use HIDE_PREEDIT_TEXT signal below but call
-+         * bus_panel_proxy_hide_preedit_text() directly for the extension only
-+         * but not for the normal panel.
-+         */
-+        bus_panel_proxy_hide_preedit_text (context->emoji_extension);
-+        return;
-+    }
- 
-     if (PREEDIT_CONDITION) {
-         bus_input_context_emit_signal (context,
-@@ -1658,19 +1730,15 @@ bus_input_context_hide_auxiliary_text (BusInputContext *context)
-     }
- }
- 
--/**
-- * bus_input_context_update_lookup_table:
-- *
-- * Update contents in the lookup table.
-- * Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
-- */
--static void
-+void
- bus_input_context_update_lookup_table (BusInputContext *context,
-                                        IBusLookupTable *table,
--                                       gboolean         visible)
-+                                       gboolean         visible,
-+                                       gboolean         is_extension)
- {
-     g_assert (BUS_IS_INPUT_CONTEXT (context));
- 
-+    context->is_extension_lookup_table = is_extension;
-     if (context->lookup_table) {
-         g_object_unref (context->lookup_table);
-     }
-@@ -2035,7 +2103,9 @@ _engine_update_preedit_text_cb (BusEngineProxy  *engine,
- 
-     g_assert (context->engine == engine);
- 
--    bus_input_context_update_preedit_text (context, text, cursor_pos, visible, mode);
-+    bus_input_context_update_preedit_text (context, text,
-+                                           cursor_pos, visible, mode,
-+                                           TRUE);
- }
- 
- /**
-@@ -2075,7 +2145,7 @@ _engine_update_lookup_table_cb (BusEngineProxy   *engine,
- 
-     g_assert (context->engine == engine);
- 
--    bus_input_context_update_lookup_table (context, table, visible);
-+    bus_input_context_update_lookup_table (context, table, visible, FALSE);
- }
- 
- /**
-@@ -2123,11 +2193,35 @@ _engine_update_property_cb (BusEngineProxy  *engine,
-  * from the engine object.
-  */
- static void
--_engine_panel_extension_cb (BusEngineProxy  *engine,
--                            GVariant        *parameters,
--                            BusInputContext *context)
-+_engine_panel_extension_cb (BusEngineProxy     *engine,
-+                            IBusExtensionEvent *event,
-+                            BusInputContext    *context)
- {
--    g_signal_emit (context, context_signals[PANEL_EXTENSION], 0, parameters);
-+    g_signal_emit (context, context_signals[PANEL_EXTENSION], 0, event);
-+}
-+
-+static void
-+_engine_show_preedit_text_cb (BusEngineProxy  *engine,
-+                              BusInputContext *context)
-+{
-+    g_assert (BUS_IS_ENGINE_PROXY (engine));
-+    g_assert (BUS_IS_INPUT_CONTEXT (context));
-+
-+    g_assert (context->engine == engine);
-+
-+    bus_input_context_show_preedit_text (context, FALSE);
-+}
-+
-+static void
-+_engine_hide_preedit_text_cb (BusEngineProxy  *engine,
-+                              BusInputContext *context)
-+{
-+    g_assert (BUS_IS_ENGINE_PROXY (engine));
-+    g_assert (BUS_IS_INPUT_CONTEXT (context));
-+
-+    g_assert (context->engine == engine);
-+
-+    bus_input_context_hide_preedit_text (context, FALSE);
- }
- 
- #define DEFINE_FUNCTION(name)                                   \
-@@ -2143,8 +2237,6 @@ _engine_panel_extension_cb (BusEngineProxy  *engine,
-         bus_input_context_##name (context);                     \
-     }
- 
--DEFINE_FUNCTION (show_preedit_text)
--DEFINE_FUNCTION (hide_preedit_text)
- DEFINE_FUNCTION (show_auxiliary_text)
- DEFINE_FUNCTION (hide_auxiliary_text)
- DEFINE_FUNCTION (show_lookup_table)
-@@ -2239,7 +2331,10 @@ bus_input_context_disable (BusInputContext *context)
- 
-     bus_input_context_clear_preedit_text (context);
-     bus_input_context_update_auxiliary_text (context, text_empty, FALSE);
--    bus_input_context_update_lookup_table (context, lookup_table_empty, FALSE);
-+    bus_input_context_update_lookup_table (context,
-+                                           lookup_table_empty,
-+                                           FALSE,
-+                                           FALSE);
-     bus_input_context_register_properties (context, props_empty);
- 
-     if (context->engine) {
-@@ -2283,7 +2378,10 @@ bus_input_context_unset_engine (BusInputContext *context)
- 
-     bus_input_context_clear_preedit_text (context);
-     bus_input_context_update_auxiliary_text (context, text_empty, FALSE);
--    bus_input_context_update_lookup_table (context, lookup_table_empty, FALSE);
-+    bus_input_context_update_lookup_table (context,
-+                                           lookup_table_empty,
-+                                           FALSE,
-+                                           FALSE);
-     bus_input_context_register_properties (context, props_empty);
- 
-     if (context->engine) {
-@@ -2639,17 +2737,128 @@ bus_input_context_set_content_type (BusInputContext *context,
- }
- 
- void
--bus_input_context_commit_text (BusInputContext *context,
--                               IBusText        *text)
-+bus_input_context_commit_text_use_extension (BusInputContext *context,
-+                                             IBusText        *text,
-+                                             gboolean         use_extension)
- {
-     g_assert (BUS_IS_INPUT_CONTEXT (context));
- 
-     if (text == text_empty || text == NULL)
-         return;
- 
--    GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
--    bus_input_context_emit_signal (context,
--                                   "CommitText",
--                                   g_variant_new ("(v)", variant),
--                                   NULL);
-+    if (use_extension && context->emoji_extension) {
-+        bus_panel_proxy_commit_text_received (context->emoji_extension, text);
-+    } else {
-+        GVariant *variant = ibus_serializable_serialize (
-+                (IBusSerializable *)text);
-+        bus_input_context_emit_signal (context,
-+                                       "CommitText",
-+                                       g_variant_new ("(v)", variant),
-+                                       NULL);
-+    }
-+}
-+
-+void
-+bus_input_context_commit_text (BusInputContext *context,
-+                               IBusText        *text)
-+{
-+    bus_input_context_commit_text_use_extension (context, text, TRUE);
-+}
-+
-+void
-+bus_input_context_update_preedit_text (BusInputContext *context,
-+                                       IBusText        *text,
-+                                       guint            cursor_pos,
-+                                       gboolean         visible,
-+                                       guint            mode,
-+                                       gboolean         use_extension)
-+{
-+    gboolean extension_visible = FALSE;
-+    g_assert (BUS_IS_INPUT_CONTEXT (context));
-+
-+    if (context->preedit_text) {
-+        g_object_unref (context->preedit_text);
-+    }
-+
-+    context->preedit_text = (IBusText *) g_object_ref_sink (text ? text :
-+                                                            text_empty);
-+    context->preedit_cursor_pos = cursor_pos;
-+    if (use_extension)
-+        context->preedit_visible = visible;
-+    if (use_extension)
-+        context->preedit_mode = mode;
-+    extension_visible = context->preedit_visible |
-+                        (context->emoji_extension != NULL);
-+
-+    if (use_extension && context->emoji_extension) {
-+        bus_panel_proxy_update_preedit_text (context->emoji_extension,
-+                                             context->preedit_text,
-+                                             context->preedit_cursor_pos,
-+                                             context->preedit_visible);
-+    } else if (PREEDIT_CONDITION) {
-+        GVariant *variant = ibus_serializable_serialize (
-+                (IBusSerializable *)context->preedit_text);
-+        bus_input_context_emit_signal (context,
-+                                       "UpdatePreeditText",
-+                                       g_variant_new (
-+                                               "(vub)",
-+                                               variant,
-+                                               context->preedit_cursor_pos,
-+                                               extension_visible),
-+                                       NULL);
-+    } else {
-+        g_signal_emit (context,
-+                       context_signals[UPDATE_PREEDIT_TEXT],
-+                       0,
-+                       context->preedit_text,
-+                       context->preedit_cursor_pos,
-+                       extension_visible);
-+    }
-+}
-+
-+void
-+bus_input_context_set_emoji_extension (BusInputContext *context,
-+                                       BusPanelProxy   *emoji_extension)
-+{
-+    g_assert (BUS_IS_INPUT_CONTEXT (context));
-+
-+    if (context->emoji_extension)
-+        g_object_unref (context->emoji_extension);
-+    context->emoji_extension = emoji_extension;
-+    if (emoji_extension) {
-+        g_object_ref (context->emoji_extension);
-+        if (!context->connection)
-+            return;
-+        bus_input_context_show_preedit_text (context, TRUE);
-+        bus_panel_proxy_set_cursor_location (context->emoji_extension,
-+                                             context->x,
-+                                             context->y,
-+                                             context->w,
-+                                             context->h);
-+    } else {
-+        if (!context->connection)
-+            return;
-+        /* https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/113
-+         * Cannot use bus_input_context_hide_preedit_text () yet.
-+         */
-+        if (!context->preedit_visible) {
-+            bus_input_context_update_preedit_text (context,
-+                                                   text_empty,
-+                                                   0,
-+                                                   FALSE,
-+                                                   IBUS_ENGINE_PREEDIT_CLEAR,
-+                                                   FALSE);
-+        }
-+    }
-+}
-+
-+void
-+bus_input_context_panel_extension_received (BusInputContext    *context,
-+                                            IBusExtensionEvent *event)
-+{
-+    g_assert (BUS_IS_INPUT_CONTEXT (context));
-+
-+    if (!context->engine)
-+        return;
-+    bus_engine_proxy_panel_extension_received (context->engine, event);
- }
-diff --git a/bus/inputcontext.h b/bus/inputcontext.h
-index 7674abd8..a46d5c06 100644
---- a/bus/inputcontext.h
-+++ b/bus/inputcontext.h
-@@ -28,6 +28,11 @@
- #include "connection.h"
- #include "factoryproxy.h"
- 
-+#ifndef __BUS_PANEL_PROXY_DEFINED
-+#define __BUS_PANEL_PROXY_DEFINED
-+typedef struct _BusPanelProxy BusPanelProxy;
-+#endif
-+
- /*
-  * Type macros.
-  */
-@@ -63,6 +68,7 @@ BusInputContext     *bus_input_context_new      (BusConnection      *connection,
- 
- /**
-  * bus_input_context_focus_in:
-+ * @context: A #BusInputContext.
-  *
-  * Give a focus to the context. Call FocusIn, Enable, SetCapabilities,
-  * and SetCursorLocation methods of the engine for the context,
-@@ -73,6 +79,7 @@ void                 bus_input_context_focus_in (BusInputContext    *context);
- 
- /**
-  * bus_input_context_focus_out:
-+ * @context: A #BusInputContext.
-  *
-  * Remove a focus from the context. Call FocusOut method of the engine for
-  * the context.
-@@ -83,6 +90,7 @@ void                 bus_input_context_focus_out
- 
- /**
-  * bus_input_context_has_focus:
-+ * @context: A #BusInputContext.
-  * @returns: context->has_focus.
-  */
- gboolean             bus_input_context_has_focus
-@@ -90,6 +98,7 @@ gboolean             bus_input_context_has_focus
- 
- /**
-  * bus_input_context_enable:
-+ * @context: A #BusInputContext.
-  *
-  * Enable the current engine for the context. Request an engine (if needed),
-  * call FocusIn, Enable, SetCapabilities, and SetCursorLocation methods
-@@ -100,6 +109,7 @@ void                 bus_input_context_enable   (BusInputContext    *context);
- 
- /**
-  * bus_input_context_disable:
-+ * @context: A #BusInputContext.
-  *
-  * Disable the current engine for the context. Request an engine (if needed),
-  * call FocusIn, Enable, SetCapabilities, and SetCursorLocation methods
-@@ -110,6 +120,7 @@ void                 bus_input_context_disable  (BusInputContext    *context);
- 
- /**
-  * bus_input_context_page_up:
-+ * @context: A #BusInputContext.
-  *
-  * Call page_up method of the current engine proxy.
-  */
-@@ -117,6 +128,7 @@ void                 bus_input_context_page_up  (BusInputContext    *context);
- 
- /**
-  * bus_input_context_page_down:
-+ * @context: A #BusInputContext.
-  *
-  * Call page_down method of the current engine proxy.
-  */
-@@ -125,6 +137,7 @@ void                 bus_input_context_page_down
- 
- /**
-  * bus_input_context_cursor_up:
-+ * @context: A #BusInputContext.
-  *
-  * Call cursor_up method of the current engine proxy.
-  */
-@@ -133,6 +146,7 @@ void                 bus_input_context_cursor_up
- 
- /**
-  * bus_input_context_cursor_down:
-+ * @context: A #BusInputContext.
-  *
-  * Call cursor_down method of the current engine proxy.
-  */
-@@ -141,6 +155,10 @@ void                 bus_input_context_cursor_down
- 
- /**
-  * bus_input_context_candidate_clicked:
-+ * @context: A #BusInputContext.
-+ * @index: An index.
-+ * @button: A button number.
-+ * @state: A button state.
-  *
-  * Call candidate_clicked method of the current engine proxy.
-  */
-@@ -152,6 +170,8 @@ void                 bus_input_context_candidate_clicked
- 
- /**
-  * bus_input_context_set_engine:
-+ * @context: A #BusInputContext.
-+ * @engine: A #BusEngineProxy.
-  *
-  * Use the engine on the context.
-  */
-@@ -161,12 +181,14 @@ void                 bus_input_context_set_engine
- 
- /**
-  * bus_input_context_set_engine_by_desc:
-+ * @context: A #BusInputContext.
-  * @desc: the engine to use on the context.
-  * @timeout: timeout (in ms) for D-Bus calls.
-  * @callback: a function to be called when bus_input_context_set_engine_by_desc
-  *            is finished. if NULL, the default callback
-  *            function, which just calls
-  *            bus_input_context_set_engine_by_desc_finish, is used.
-+ * @user_data: an argument of @callback.
-  *
-  * Create a new BusEngineProxy object and use it on the context.
-  */
-@@ -181,6 +203,9 @@ void                 bus_input_context_set_engine_by_desc
- 
- /**
-  * bus_input_context_set_engine_by_desc_finish:
-+ * @context: A #BusInputContext.
-+ * @res: A #GAsyncResult.
-+ * @error: A #GError.
-  *
-  * A function to be called by the GAsyncReadyCallback function for
-  * bus_input_context_set_engine_by_desc.
-@@ -192,6 +217,7 @@ gboolean             bus_input_context_set_engine_by_desc_finish
- 
- /**
-  * bus_input_context_get_engine:
-+ * @context: A #BusInputContext.
-  *
-  * Get a BusEngineProxy object of the current engine.
-  */
-@@ -200,6 +226,7 @@ BusEngineProxy      *bus_input_context_get_engine
- 
- /**
-  * bus_input_context_get_engine_desc:
-+ * @context: A #BusInputContext.
-  *
-  * Get an IBusEngineDesc object of the current engine.
-  */
-@@ -208,6 +235,9 @@ IBusEngineDesc      *bus_input_context_get_engine_desc
- 
- /**
-  * bus_input_context_property_activate:
-+ * @context: A #BusInputContext.
-+ * @prop_name: A property name.
-+ * @prop_state: A property state.
-  *
-  * Call property_activate method of the current engine proxy.
-  */
-@@ -219,6 +249,7 @@ void                 bus_input_context_property_activate
- 
- /**
-  * bus_input_context_get_capabilities:
-+ * @context: A #BusInputContext.
-  * @returns: context->capabilities.
-  */
- guint                bus_input_context_get_capabilities
-@@ -226,6 +257,8 @@ guint                bus_input_context_get_capabilities
- 
- /**
-  * bus_input_context_set_capabilities:
-+ * @context: A #BusInputContext.
-+ * @capabilities: capabilities.
-  *
-  * Call set_capabilities method of the current engine proxy.
-  */
-@@ -236,6 +269,7 @@ void                 bus_input_context_set_capabilities
- 
- /**
-  * bus_input_context_get_client:
-+ * @context: A #BusInputContext.
-  * @returns: context->client.
-  */
- const gchar         *bus_input_context_get_client
-@@ -243,6 +277,7 @@ const gchar         *bus_input_context_get_client
- 
- /**
-  * bus_input_context_get_content_type:
-+ * @context: A #BusInputContext.
-  * @purpose: Input purpose.
-  * @hints: Input hints.
-  */
-@@ -253,6 +288,7 @@ void                 bus_input_context_get_content_type
- 
- /**
-  * bus_input_context_set_content_type:
-+ * @context: A #BusInputContext.
-  * @purpose: Input purpose.
-  * @hints: Input hints.
-  */
-@@ -263,11 +299,83 @@ void                 bus_input_context_set_content_type
- 
- /**
-  * bus_input_context_commit_text:
-- * @text: a commited text.
-+ * @context: A #BusInputContext.
-+ * @text: A committed text.
-  */
- void                 bus_input_context_commit_text
-                                                 (BusInputContext *context,
-                                                  IBusText        *text);
- 
-+/**
-+ * bus_input_context_commit_text:
-+ * @context: A #BusInputContext.
-+ * @text: A committed text.
-+ * @use_extension: Use an extension if it's %TRUE and the extension is
-+ *                 available.
-+ */
-+void                 bus_input_context_commit_text_use_extension
-+                                               (BusInputContext *context,
-+                                                IBusText        *text,
-+                                                gboolean         use_extension);
-+
-+/**
-+ * bus_input_context_set_emoji_extension:
-+ * @context: A #BusInputContext.
-+ * @extension: A #BusPanelProxy.
-+ */
-+void                 bus_input_context_set_emoji_extension
-+                                                (BusInputContext *context,
-+                                                 BusPanelProxy   *extension);
-+
-+/**
-+ * bus_input_context_update_preedit_text:
-+ * @context: A #BusInputContext.
-+ * @text: An #IBusText.
-+ * @cursor_pos: The cursor position.
-+ * @visible: %TRUE if the preedit is visible. Otherwise %FALSE.
-+ * @mode: The preedit commit mode.
-+ * @use_extension: %TRUE if preedit text is sent to the extesion at first.
-+ *
-+ * Update a preedit text. Send D-Bus signal to update status of client or
-+ * send glib signal to the panel, depending on capabilities of the client.
-+ */
-+void                 bus_input_context_update_preedit_text
-+                                                (BusInputContext    *context,
-+                                                 IBusText           *text,
-+                                                 guint               cursor_pos,
-+                                                 gboolean            visible,
-+                                                 guint               mode,
-+                                                 gboolean
-+                                                                 use_extension);
-+
-+/**
-+ * bus_input_context_update_lookup_table:
-+ * @context: A #BusInputContext.
-+ * @table: An #IBusTable.
-+ * @visible: %TRUE if the lookup table is visible. Otherwise %FALSE.
-+ * @is_extension: %TRUE if the lookup table is created by panel extensions.
-+ *
-+ * Update contents in the lookup table.
-+ * Send D-Bus signal to update status of client or send glib signal to the
-+ * panel, depending on capabilities of the client.
-+ */
-+void                 bus_input_context_update_lookup_table
-+                                                (BusInputContext    *context,
-+                                                 IBusLookupTable    *table,
-+                                                 gboolean            visible,
-+                                                 gboolean
-+                                                                  is_extension);
-+
-+
-+/**
-+ * bus_input_context_panel_extension_received:
-+ * @context: A #BusInputContext.
-+ * @event: An #IBusExtensionEvent.
-+ *
-+ * Send An #IBusExtensionEvent callback from an extension.
-+ */
-+void                 bus_input_context_panel_extension_received
-+                                                (BusInputContext    *context,
-+                                                 IBusExtensionEvent *event);
- G_END_DECLS
- #endif
-diff --git a/bus/panelproxy.c b/bus/panelproxy.c
-index c3908fcf..1c0fcca2 100644
---- a/bus/panelproxy.c
-+++ b/bus/panelproxy.c
-@@ -52,6 +52,10 @@ enum {
-     PROPERTY_HIDE,
-     COMMIT_TEXT,
-     PANEL_EXTENSION,
-+    PANEL_EXTENSION_REGISTER_KEYS,
-+    UPDATE_PREEDIT_TEXT_RECEIVED,
-+    UPDATE_LOOKUP_TABLE_RECEIVED,
-+    UPDATE_AUXILIARY_TEXT_RECEIVED,
-     LAST_SIGNAL,
- };
- 
-@@ -125,8 +129,8 @@ bus_panel_proxy_new (BusConnection *connection,
-     case PANEL_TYPE_PANEL:
-         path = IBUS_PATH_PANEL;
-         break;
--    case PANEL_TYPE_EXTENSION:
--        path = IBUS_PATH_PANEL_EXTENSION;
-+    case PANEL_TYPE_EXTENSION_EMOJI:
-+        path = IBUS_PATH_PANEL_EXTENSION_EMOJI;
-         break;
-     default:
-         g_return_val_if_reached (NULL);
-@@ -253,6 +257,16 @@ bus_panel_proxy_class_init (BusPanelProxyClass *class)
- 
-     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__OBJECT,
-+            G_TYPE_NONE, 1,
-+            IBUS_TYPE_EXTENSION_EVENT);
-+
-+    panel_signals[PANEL_EXTENSION_REGISTER_KEYS] =
-+        g_signal_new (I_("panel-extension-register-keys"),
-             G_TYPE_FROM_CLASS (class),
-             G_SIGNAL_RUN_LAST,
-             0,
-@@ -260,6 +274,40 @@ bus_panel_proxy_class_init (BusPanelProxyClass *class)
-             bus_marshal_VOID__VARIANT,
-             G_TYPE_NONE, 1,
-             G_TYPE_VARIANT);
-+
-+    panel_signals[UPDATE_PREEDIT_TEXT_RECEIVED] =
-+        g_signal_new (I_("update-preedit-text-received"),
-+            G_TYPE_FROM_CLASS (class),
-+            G_SIGNAL_RUN_LAST,
-+            0,
-+            NULL, NULL,
-+            bus_marshal_VOID__OBJECT_UINT_BOOLEAN,
-+            G_TYPE_NONE, 3,
-+            IBUS_TYPE_TEXT,
-+            G_TYPE_UINT,
-+            G_TYPE_BOOLEAN);
-+
-+    panel_signals[UPDATE_LOOKUP_TABLE_RECEIVED] =
-+        g_signal_new (I_("update-lookup-table-received"),
-+            G_TYPE_FROM_CLASS (class),
-+            G_SIGNAL_RUN_LAST,
-+            0,
-+            NULL, NULL,
-+            bus_marshal_VOID__OBJECT_BOOLEAN,
-+            G_TYPE_NONE, 2,
-+            IBUS_TYPE_LOOKUP_TABLE,
-+            G_TYPE_BOOLEAN);
-+
-+    panel_signals[UPDATE_AUXILIARY_TEXT_RECEIVED] =
-+        g_signal_new (I_("update-auxiliary-text-received"),
-+            G_TYPE_FROM_CLASS (class),
-+            G_SIGNAL_RUN_LAST,
-+            0,
-+            NULL, NULL,
-+            bus_marshal_VOID__OBJECT_BOOLEAN,
-+            G_TYPE_NONE, 2,
-+            IBUS_TYPE_TEXT,
-+            G_TYPE_BOOLEAN);
- }
- 
- static void
-@@ -355,23 +403,83 @@ bus_panel_proxy_g_signal (GDBusProxy  *proxy,
- 
-     if (g_strcmp0 ("CommitText", signal_name) == 0) {
-         GVariant *arg0 = NULL;
--        g_variant_get (parameters, "(v)", &arg0);
--        g_return_if_fail (arg0 != NULL);
- 
-+        g_variant_get (parameters, "(v)", &arg0);
-+        g_return_if_fail (arg0);
-         IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (arg0));
-         g_variant_unref (arg0);
--        g_return_if_fail (text != NULL);
-+        g_return_if_fail (text);
-         g_signal_emit (panel, panel_signals[COMMIT_TEXT], 0, text);
-         _g_object_unref_if_floating (text);
-         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);
-+        GVariant *arg0 = NULL;
-+
-+        g_variant_get (parameters, "(v)", &arg0);
-+        g_return_if_fail (arg0);
-+        IBusExtensionEvent *event = IBUS_EXTENSION_EVENT (
-+                ibus_serializable_deserialize (arg0));
-+        g_variant_unref (arg0);
-+        g_return_if_fail (event);
-+        g_signal_emit (panel, panel_signals[PANEL_EXTENSION], 0, event);
-+        _g_object_unref_if_floating (event);
-+        return;
-+    }
-+
-+    if (g_strcmp0 ("PanelExtensionRegisterKeys", signal_name) == 0) {
-+        g_signal_emit (panel, panel_signals[PANEL_EXTENSION_REGISTER_KEYS], 0,
-+                       parameters);
-+        return;
-+    }
-+
-+    if (g_strcmp0 ("UpdatePreeditTextReceived", signal_name) == 0) {
-+        GVariant *variant = NULL;
-+        guint cursor_pos = 0;
-+        gboolean visible = FALSE;
-+        IBusText *text = NULL;
-+
-+        g_variant_get (parameters, "(vub)", &variant, &cursor_pos, &visible);
-+        g_return_if_fail (variant);
-+        text = (IBusText *) ibus_serializable_deserialize (variant);
-+        g_variant_unref (variant);
-+        g_return_if_fail (text);
-+        g_signal_emit (panel, panel_signals[UPDATE_PREEDIT_TEXT_RECEIVED], 0,
-+                       text, cursor_pos, visible);
-+        _g_object_unref_if_floating (text);
-+        return;
-+    }
-+
-+    if (g_strcmp0 ("UpdateLookupTableReceived", signal_name) == 0) {
-+        GVariant *variant = NULL;
-+        gboolean visible = FALSE;
-+        IBusLookupTable *table = NULL;
-+
-+        g_variant_get (parameters, "(vb)", &variant, &visible);
-+        g_return_if_fail (variant);
-+        table = (IBusLookupTable *) ibus_serializable_deserialize (variant);
-+        g_variant_unref (variant);
-+        g_return_if_fail (table);
-+        g_signal_emit (panel, panel_signals[UPDATE_LOOKUP_TABLE_RECEIVED], 0,
-+                       table, visible);
-+        _g_object_unref_if_floating (table);
-+        return;
-+    }
-+
-+    if (g_strcmp0 ("UpdateAuxiliaryTextReceived", signal_name) == 0) {
-+        GVariant *variant = NULL;
-+        gboolean visible = FALSE;
-+        IBusText *text = NULL;
-+
-+        g_variant_get (parameters, "(vb)", &variant, &visible);
-+        g_return_if_fail (variant);
-+        text = (IBusText *) ibus_serializable_deserialize (variant);
-+        g_variant_unref (variant);
-+        g_return_if_fail (text);
-+        g_signal_emit (panel, panel_signals[UPDATE_AUXILIARY_TEXT_RECEIVED], 0,
-+                       text, visible);
-+        _g_object_unref_if_floating (text);
-         return;
-     }
- 
-@@ -552,12 +660,17 @@ static void
- bus_panel_proxy_commit_text (BusPanelProxy *panel,
-                              IBusText      *text)
- {
-+    gboolean use_extension = TRUE;
-     g_assert (BUS_IS_PANEL_PROXY (panel));
-     g_assert (text != NULL);
- 
--    if (panel->focused_context) {
--        bus_input_context_commit_text (panel->focused_context, text);
--    }
-+    if (!panel->focused_context)
-+        return;
-+    if (panel->panel_type != PANEL_TYPE_PANEL)
-+        use_extension = FALSE;
-+    bus_input_context_commit_text_use_extension (panel->focused_context,
-+                                                 text,
-+                                                 use_extension);
- }
- 
- #define DEFINE_FUNCTION(Name, name)                     \
-@@ -877,3 +990,74 @@ bus_panel_proxy_get_panel_type (BusPanelProxy    *panel)
-     g_assert (BUS_IS_PANEL_PROXY (panel));
-     return panel->panel_type;
- }
-+
-+void
-+bus_panel_proxy_panel_extension_received (BusPanelProxy      *panel,
-+                                          IBusExtensionEvent *event)
-+{
-+    GVariant *data;
-+
-+    g_assert (BUS_IS_PANEL_PROXY (panel));
-+    g_assert (event);
-+
-+    data = ibus_serializable_serialize (IBUS_SERIALIZABLE (event));
-+    g_return_if_fail (data);
-+    g_dbus_proxy_call ((GDBusProxy *)panel,
-+                       "PanelExtensionReceived",
-+                       g_variant_new ("(v)", data),
-+                       G_DBUS_CALL_FLAGS_NONE,
-+                       -1, NULL, NULL, NULL);
-+}
-+
-+void
-+bus_panel_proxy_process_key_event (BusPanelProxy       *panel,
-+                                   guint                keyval,
-+                                   guint                keycode,
-+                                   guint                state,
-+                                   GAsyncReadyCallback  callback,
-+                                   gpointer             user_data)
-+{
-+    g_assert (BUS_IS_PANEL_PROXY (panel));
-+
-+    g_dbus_proxy_call ((GDBusProxy *)panel,
-+                       "ProcessKeyEvent",
-+                       g_variant_new ("(uuu)", keyval, keycode, state),
-+                       G_DBUS_CALL_FLAGS_NONE,
-+                       -1,
-+                       NULL,
-+                       callback,
-+                       user_data);
-+}
-+
-+void
-+bus_panel_proxy_commit_text_received (BusPanelProxy *panel,
-+                                      IBusText      *text)
-+{
-+    GVariant *variant;
-+
-+    g_assert (BUS_IS_PANEL_PROXY (panel));
-+    g_assert (IBUS_IS_TEXT (text));
-+
-+    variant = ibus_serializable_serialize (IBUS_SERIALIZABLE (text));
-+    g_dbus_proxy_call ((GDBusProxy *)panel,
-+                       "CommitTextReceived",
-+                       g_variant_new ("(v)", variant),
-+                       G_DBUS_CALL_FLAGS_NONE,
-+                       -1, NULL, NULL, NULL);
-+}
-+
-+void
-+bus_panel_proxy_candidate_clicked_lookup_table (BusPanelProxy *panel,
-+                                                guint          index,
-+                                                guint          button,
-+                                                guint          state)
-+{
-+    gboolean use_extension = TRUE;
-+    g_assert (BUS_IS_PANEL_PROXY (panel));
-+
-+    g_dbus_proxy_call ((GDBusProxy *)panel,
-+                       "CandidateClickedLookupTable",
-+                       g_variant_new ("(uuu)", index, button, state),
-+                       G_DBUS_CALL_FLAGS_NONE,
-+                       -1, NULL, NULL, NULL);
-+}
-diff --git a/bus/panelproxy.h b/bus/panelproxy.h
-index b5a7af17..4d8afb98 100644
---- a/bus/panelproxy.h
-+++ b/bus/panelproxy.h
-@@ -55,7 +55,7 @@ typedef enum
- {
-     PANEL_TYPE_NONE,
-     PANEL_TYPE_PANEL,
--    PANEL_TYPE_EXTENSION
-+    PANEL_TYPE_EXTENSION_EMOJI
- } PanelType;
- 
- typedef struct _BusPanelProxy BusPanelProxy;
-@@ -135,6 +135,27 @@ void             bus_panel_proxy_set_content_type
-                                                 guint              hints);
- PanelType        bus_panel_proxy_get_panel_type
-                                                (BusPanelProxy     *panel);
-+void             bus_panel_proxy_panel_extension_received
-+                                               (BusPanelProxy     *panel,
-+                                                IBusExtensionEvent
-+                                                                  *event);
-+void             bus_panel_proxy_process_key_event
-+                                               (BusPanelProxy     *panel,
-+                                                guint              keyval,
-+                                                guint              keycode,
-+                                                guint              state,
-+                                                GAsyncReadyCallback
-+                                                                   callback,
-+                                                gpointer           user_data);
-+void             bus_panel_proxy_commit_text_received
-+                                               (BusPanelProxy     *panel,
-+                                                IBusText          *text);
-+void             bus_panel_proxy_candidate_clicked_lookup_table
-+                                               (BusPanelProxy     *panel,
-+                                                guint              index,
-+                                                guint              button,
-+                                                guint              state);
-+
- G_END_DECLS
- #endif
- 
-diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in
-index 3c6b6f69..f4a019d0 100644
---- a/data/ibus.schemas.in
-+++ b/data/ibus.schemas.in
-@@ -353,6 +353,18 @@
- 	    <long>Custom font name for language panel</long>
-       </locale>
-     </schema>
-+    <schema>
-+      <key>/schemas/desktop/ibus/panel/emoji/unicode-hotkey</key>
-+      <applyto>/desktop/ibus/panel/emoji/unicode-hotkey</applyto>
-+      <owner>ibus</owner>
-+      <type>list</type>
-+      <list_type>string</list_type>
-+      <default>[&lt;Control&gt;&lt;Shift&gt;u]</default>
-+      <locale name="C">
-+        <short>Unicode shortcut keys for gtk_accelerator_parse</short>
-+          <long>The shortcut keys for turning Unicode typing on or off</long>
-+      </locale>
-+    </schema>
-     <schema>
-       <key>/schemas/desktop/ibus/panel/emoji/hotkey</key>
-       <applyto>/desktop/ibus/panel/emoji/hotkey</applyto>
-diff --git a/setup/main.py b/setup/main.py
-index f0eee996..f6adb098 100644
---- a/setup/main.py
-+++ b/setup/main.py
-@@ -4,7 +4,7 @@
- # ibus - The Input Bus
- #
- # Copyright (c) 2007-2016 Peng Huang <shawn.p.huang@gmail.com>
--# Copyright (c) 2010-2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+# Copyright (c) 2010-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
- # Copyright (c) 2007-2016 Red Hat, Inc.
- #
- # This library is free software; you can redistribute it and/or
-@@ -123,10 +123,15 @@ class Setup(object):
-         name = 'emoji'
-         label = 'emoji_dialog'
-         self.__init_hotkey(name, label)
-+        name = 'unicode'
-+        label = 'unicode_dialog'
-+        self.__init_hotkey(name, label)
- 
-     def __init_hotkey(self, name, label, comment=None):
-         if name == 'emoji':
-             shortcuts = self.__settings_emoji.get_strv('hotkey')
-+        elif name == 'unicode':
-+            shortcuts = self.__settings_emoji.get_strv('unicode-hotkey')
-         else:
-             shortcuts = self.__settings_hotkey.get_strv(name)
-         button = self.__builder.get_object("button_%s" % label)
-@@ -139,6 +144,9 @@ class Setup(object):
-         if name == 'emoji':
-             button.connect("clicked", self.__shortcut_button_clicked_cb,
-                     'hotkey', 'panel/' + name, label, entry)
-+        elif name == 'unicode':
-+            button.connect("clicked", self.__shortcut_button_clicked_cb,
-+                    'unicode-hotkey', 'panel/emoji', label, entry)
-         else:
-             button.connect("clicked", self.__shortcut_button_clicked_cb,
-                     name, "general/hotkey", label, entry)
-diff --git a/setup/setup.ui b/setup/setup.ui
-index e64b1046..f1beb1de 100644
---- a/setup/setup.ui
-+++ b/setup/setup.ui
-@@ -870,9 +870,9 @@
-                           <object class="GtkLabel" id="label_emoji1">
-                             <property name="visible">True</property>
-                             <property name="can_focus">False</property>
--                            <property name="tooltip_text" translatable="yes">The shortcut keys for showing emoji dialog</property>
-+                            <property name="tooltip_text" translatable="yes">The shortcut keys to enable conversions of emoji annotations or Unicode names</property>
-                             <property name="halign">start</property>
--                            <property name="label" translatable="yes">Emoji choice:</property>
-+                            <property name="label" translatable="yes">Emoji annotation:</property>
-                           </object>
-                           <packing>
-                             <property name="left_attach">0</property>
-@@ -920,6 +920,60 @@
-                             <property name="top_attach">0</property>
-                           </packing>
-                         </child>
-+                        <child>
-+                          <object class="GtkLabel" id="label_unicode1">
-+                            <property name="visible">True</property>
-+                            <property name="can_focus">False</property>
-+                            <property name="tooltip_text" translatable="yes">The shortcut keys to enable Unicode code point conversions</property>
-+                            <property name="halign">start</property>
-+                            <property name="label" translatable="yes">Unicode code point:</property>
-+                          </object>
-+                          <packing>
-+                            <property name="left_attach">0</property>
-+                            <property name="top_attach">1</property>
-+                          </packing>
-+                        </child>
-+                        <child>
-+                          <object class="GtkBox" id="hbox_unicode1">
-+                            <property name="orientation">horizontal</property>
-+                            <property name="visible">True</property>
-+                            <property name="can_focus">False</property>
-+                            <property name="spacing">6</property>
-+                            <property name="hexpand">true</property>
-+                            <child>
-+                              <object class="GtkEntry" id="entry_unicode_dialog">
-+                                <property name="visible">True</property>
-+                                <property name="can_focus">True</property>
-+                                <property name="editable">False</property>
-+                              </object>
-+                              <packing>
-+                                <property name="expand">True</property>
-+                                <property name="fill">True</property>
-+                                <property name="position">0</property>
-+                              </packing>
-+                            </child>
-+                            <child>
-+                              <object class="GtkButton" id="button_unicode_dialog">
-+                                <property name="label" translatable="yes">...</property>
-+                                <property name="use_action_appearance">False</property>
-+                                <property name="visible">True</property>
-+                                <property name="can_focus">True</property>
-+                                <property name="receives_default">False</property>
-+                                <property name="use_action_appearance">False</property>
-+                                <property name="use_underline">True</property>
-+                              </object>
-+                              <packing>
-+                                <property name="expand">False</property>
-+                                <property name="fill">True</property>
-+                                <property name="position">1</property>
-+                              </packing>
-+                            </child>
-+                          </object>
-+                          <packing>
-+                            <property name="left_attach">1</property>
-+                            <property name="top_attach">1</property>
-+                          </packing>
-+                        </child>
-                       </object>
-                     </child>
-                     <child type="label">
-diff --git a/src/ibusengine.c b/src/ibusengine.c
-index fd61102a..a3ccd7dd 100644
---- a/src/ibusengine.c
-+++ b/src/ibusengine.c
-@@ -64,8 +64,6 @@ enum {
- };
- 
- 
--typedef struct _IBusEngineKeybinding IBusEngineKeybinding;
--
- /* IBusEnginePriv */
- struct _IBusEnginePrivate {
-     gchar *engine_name;
-@@ -81,14 +79,11 @@ struct _IBusEnginePrivate {
-     guint content_purpose;
-     guint content_hints;
- 
--    GSettings             *settings_emoji;
--    IBusEngineKeybinding **emoji_keybindings;
-+    GHashTable            *extension_keybindings;
-+    gboolean               enable_extension;
-+    gchar                 *current_extension_name;
- };
- 
--struct _IBusEngineKeybinding {
--    guint            keyval;
--    IBusModifierType modifiers;
--};
- 
- static guint            engine_signals[LAST_SIGNAL] = { 0 };
- 
-@@ -191,10 +186,6 @@ static void      ibus_engine_dbus_property_changed
-                                               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)
-@@ -253,6 +244,12 @@ static const gchar introspection_xml[] =
-     "      <arg direction='in'  type='u' name='cursor_pos' />"
-     "      <arg direction='in'  type='u' name='anchor_pos' />"
-     "    </method>"
-+    "    <method name='PanelExtensionReceived'>"
-+    "      <arg direction='in'  type='v' name='event' />"
-+    "    </method>"
-+    "    <method name='PanelExtensionRegisterKeys'>"
-+    "      <arg direction='in'  type='v' name='data' />"
-+    "    </method>"
-     /* FIXME signals */
-     "    <signal name='CommitText'>"
-     "      <arg type='v' name='text' />"
-@@ -309,16 +306,22 @@ ibus_engine_class_init (IBusEngineClass *class)
-     GObjectClass *gobject_class = G_OBJECT_CLASS (class);
-     IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (class);
- 
--    gobject_class->set_property = (GObjectSetPropertyFunc) ibus_engine_set_property;
--    gobject_class->get_property = (GObjectGetPropertyFunc) ibus_engine_get_property;
-+    gobject_class->set_property =
-+            (GObjectSetPropertyFunc) ibus_engine_set_property;
-+    gobject_class->get_property =
-+            (GObjectGetPropertyFunc) ibus_engine_get_property;
- 
-     ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_engine_destroy;
- 
--    IBUS_SERVICE_CLASS (class)->service_method_call  = ibus_engine_service_method_call;
--    IBUS_SERVICE_CLASS (class)->service_get_property = ibus_engine_service_get_property;
--    IBUS_SERVICE_CLASS (class)->service_set_property = ibus_engine_service_set_property;
-+    IBUS_SERVICE_CLASS (class)->service_method_call  =
-+            ibus_engine_service_method_call;
-+    IBUS_SERVICE_CLASS (class)->service_get_property =
-+            ibus_engine_service_get_property;
-+    IBUS_SERVICE_CLASS (class)->service_set_property =
-+            ibus_engine_service_set_property;
- 
--    ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
-+    ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class),
-+                                       introspection_xml);
- 
-     class->process_key_event = ibus_engine_process_key_event;
-     class->focus_in     = ibus_engine_focus_in;
-@@ -839,26 +842,25 @@ ibus_engine_init (IBusEngine *engine)
- {
-     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);
-+    priv->extension_keybindings = g_hash_table_new_full (
-+            g_str_hash,
-+            g_str_equal,
-+            g_free,
-+            g_free);
- }
- 
- static void
- ibus_engine_destroy (IBusEngine *engine)
- {
--    g_free (engine->priv->engine_name);
--    engine->priv->engine_name = NULL;
-+    IBusEnginePrivate *priv = engine->priv;
- 
--    if (engine->priv->surrounding_text) {
--        g_object_unref (engine->priv->surrounding_text);
--        engine->priv->surrounding_text = NULL;
--    }
--    ibus_engine_keybinding_free (engine);
-+    g_clear_pointer (&priv->engine_name, g_free);
-+    g_clear_pointer (&priv->current_extension_name, g_free);
-+    if (priv->surrounding_text)
-+        g_clear_object (&priv->surrounding_text);
-+    if (priv->extension_keybindings)
-+        g_clear_pointer (&priv->extension_keybindings, g_hash_table_destroy);
- 
-     IBUS_OBJECT_CLASS(ibus_engine_parent_class)->destroy (IBUS_OBJECT (engine));
- }
-@@ -895,19 +897,38 @@ ibus_engine_get_property (IBusEngine *engine,
- }
- 
- static void
--ibus_engine_panel_extension (IBusEngine *engine)
-+ibus_engine_panel_extension (IBusEngine  *engine,
-+                             const gchar *name)
- {
--    IBusXEvent *xevent = ibus_x_event_new (
--            "event-type", IBUS_X_EVENT_KEY_PRESS,
--            "purpose", "emoji",
-+    IBusEnginePrivate *priv;
-+    IBusExtensionEvent *event;
-+    GVariant *data;
-+
-+    g_assert (IBUS_IS_ENGINE (engine));
-+    g_assert (name);
-+
-+    priv = engine->priv;
-+    if (!g_strcmp0 (name, priv->current_extension_name))
-+        priv->enable_extension = !priv->enable_extension;
-+    else
-+        priv->enable_extension = TRUE;
-+    if (priv->enable_extension) {
-+        g_free (priv->current_extension_name);
-+        priv->current_extension_name = g_strdup (name);
-+    }
-+    event = ibus_extension_event_new (
-+            "name", name,
-+            "is-enabled", priv->enable_extension,
-             NULL);
--    GVariant *data = ibus_serializable_serialize_object (
--            IBUS_SERIALIZABLE (xevent));
-+    g_assert (IBUS_IS_EXTENSION_EVENT (event));
-+    data = ibus_serializable_serialize_object (
-+            IBUS_SERIALIZABLE (event));
- 
-     g_assert (data != NULL);
-     ibus_engine_emit_signal (engine,
-                              "PanelExtension",
-                              g_variant_new ("(v)", data));
-+    g_object_unref (event);
- }
- 
- static gboolean
-@@ -917,7 +938,8 @@ ibus_engine_filter_key_event (IBusEngine *engine,
-                               guint       state)
- {
-     IBusEnginePrivate *priv;
--    int i;
-+    GList *names, *n;
-+    IBusProcessKeyEventData *keys;
-     guint modifiers;
- 
-     if ((state & IBUS_RELEASE_MASK) != 0)
-@@ -925,22 +947,29 @@ ibus_engine_filter_key_event (IBusEngine *engine,
-     g_return_val_if_fail (IBUS_IS_ENGINE (engine), FALSE);
- 
-     priv = engine->priv;
--    if (!priv->emoji_keybindings)
--        return FALSE;
--
-     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;
-+    names = g_hash_table_get_keys (priv->extension_keybindings);
-+    if (!names)
-+        return FALSE;
-+    for (n = names; n; n = n->next) {
-+        const gchar *name = (const gchar *)n->data;
-+        keys = g_hash_table_lookup (priv->extension_keybindings, name);
-+        for (; keys; keys++) {
-+            if (keys->keyval == 0 && keys->keycode == 0 && keys->state == 0)
-+                break;
-+            if (keys->keyval == keyval &&
-+                keys->state == modifiers &&
-+                (keys->keycode == 0 || keys->keycode == keycode)) {
-+                ibus_engine_panel_extension (engine, name);
-+                return TRUE;
-+            }
-         }
-     }
-+    g_list_free (names);
-     return FALSE;
- }
- 
-@@ -953,6 +982,97 @@ ibus_engine_service_authorized_method (IBusService     *service,
-     return FALSE;
- }
- 
-+static void
-+ibus_engine_service_panel_extension_register_keys (IBusEngine      *engine,
-+                                                   GVariant        *parameters,
-+                                                   GDBusMethodInvocation
-+                                                                   *invocation)
-+{
-+    IBusEnginePrivate *priv = engine->priv;
-+    GVariant *v1 = NULL;
-+    GVariant *v2 = NULL;
-+    GVariant *v3 = NULL;
-+    GVariant *vkeys = NULL;
-+    GVariantIter *iter1 = NULL;
-+    GVariantIter *iter2 = NULL;
-+    const gchar *name = NULL;
-+    guint failure_id = 0;
-+
-+    g_variant_get (parameters, "(v)", &v1);
-+    if (v1)
-+        g_variant_get (v1, "(v)", &v2);
-+    else
-+        failure_id = 1;
-+    if (v2)
-+        g_variant_get (v2, "a{sv}", &iter1);
-+    else
-+        failure_id = 2;
-+    if (iter1) {
-+        while (g_variant_iter_loop (iter1, "{&sv}", &name, &vkeys)) {
-+            if (vkeys)
-+                g_variant_get (vkeys, "av", &iter2);
-+            if (name && iter2) {
-+                IBusProcessKeyEventData *keys = NULL;
-+                gint num = 0;
-+                while (g_variant_iter_loop (iter2, "v", &v3)) {
-+                    if (v3) {
-+                        guint keyval = 0;
-+                        guint keycode = 0;
-+                        guint state = 0;
-+                        g_variant_get (v3, "(iii)",
-+                                       &keyval, &keycode, &state);
-+                        if (!keys)
-+                            keys = g_new0 (IBusProcessKeyEventData, 2);
-+                        else
-+                            keys = g_renew (IBusProcessKeyEventData,
-+                                            keys,
-+                                            num + 2);
-+                        keys[num].keyval = keyval;
-+                        keys[num].keycode = keycode;
-+                        keys[num].state = state;
-+                        keys[num + 1].keyval = 0;
-+                        keys[num + 1].keycode = 0;
-+                        keys[num + 1].state = 0;
-+                        g_clear_pointer (&v3, g_variant_unref);
-+                        num++;
-+                    } else {
-+                        failure_id = 5;
-+                    }
-+                }
-+                if (num > 0) {
-+                    g_hash_table_replace (priv->extension_keybindings,
-+                                          g_strdup (name),
-+                                          keys);
-+                } else {
-+                    g_hash_table_remove (priv->extension_keybindings, name);
-+                }
-+                g_clear_pointer (&iter2, g_variant_iter_free);
-+            } else {
-+                failure_id = 4;
-+            }
-+            g_clear_pointer (&vkeys, g_variant_unref);
-+            name = NULL;
-+        }
-+        g_variant_iter_free (iter1);
-+    } else {
-+        failure_id = 3;
-+    }
-+    if (failure_id == 0) {
-+        g_dbus_method_invocation_return_value (invocation, NULL);
-+    } else {
-+        g_dbus_method_invocation_return_error (
-+                invocation,
-+                G_DBUS_ERROR,
-+                G_DBUS_ERROR_FAILED,
-+                "PanelExtensionRegisterKeys method gives NULL: %d",
-+                failure_id);
-+    }
-+    if (v2)
-+        g_variant_unref (v2);
-+    if (v1)
-+        g_variant_unref (v1);
-+}
-+
- static void
- ibus_engine_service_method_call (IBusService           *service,
-                                  GDBusConnection       *connection,
-@@ -964,6 +1084,7 @@ ibus_engine_service_method_call (IBusService           *service,
-                                  GDBusMethodInvocation *invocation)
- {
-     IBusEngine *engine = IBUS_ENGINE (service);
-+    IBusEnginePrivate *priv = engine->priv;
- 
-     if (g_strcmp0 (interface_name, IBUS_INTERFACE_ENGINE) != 0) {
-         IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
-@@ -1002,6 +1123,33 @@ ibus_engine_service_method_call (IBusService           *service,
-         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", retval));
-         return;
-     }
-+    if (g_strcmp0 (method_name, "PanelExtensionReceived") == 0) {
-+        GVariant *arg0 = NULL;
-+        IBusExtensionEvent *event = NULL;
-+
-+        g_variant_get (parameters, "(v)", &arg0);
-+        if (arg0) {
-+            event = (IBusExtensionEvent *)ibus_serializable_deserialize_object (
-+                    arg0);
-+        }
-+        if (!event) {
-+            g_dbus_method_invocation_return_error (
-+                    invocation,
-+                    G_DBUS_ERROR,
-+                    G_DBUS_ERROR_FAILED,
-+                    "PanelExtensionReceived method gives NULL");
-+            return;
-+        }
-+        priv->enable_extension = ibus_extension_event_is_enabled (event);
-+        g_dbus_method_invocation_return_value (invocation, NULL);
-+        return;
-+    }
-+    if (g_strcmp0 (method_name, "PanelExtensionRegisterKeys") == 0) {
-+        ibus_engine_service_panel_extension_register_keys (engine,
-+                                                           parameters,
-+                                                           invocation);
-+        return;
-+    }
- 
-     static const struct {
-         gchar *member;
-@@ -1441,73 +1589,10 @@ 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 *
-diff --git a/src/ibuspanelservice.c b/src/ibuspanelservice.c
-index f37b91c3..71028ebf 100644
---- a/src/ibuspanelservice.c
-+++ b/src/ibuspanelservice.c
-@@ -57,6 +57,9 @@ enum {
-     DESTROY_CONTEXT,
-     SET_CONTENT_TYPE,
-     PANEL_EXTENSION_RECEIVED,
-+    PROCESS_KEY_EVENT,
-+    COMMIT_TEXT_RECEIVED,
-+    CANDIDATE_CLICKED_LOOKUP_TABLE,
-     LAST_SIGNAL,
- };
- 
-@@ -153,7 +156,7 @@ static void      ibus_panel_service_set_content_type
-                                     guint                   hints);
- static void      ibus_panel_service_panel_extension_received
-                                    (IBusPanelService       *panel,
--                                    GVariant               *data);
-+                                    IBusExtensionEvent     *event);
- 
- G_DEFINE_TYPE (IBusPanelService, ibus_panel_service, IBUS_TYPE_SERVICE)
- 
-@@ -184,6 +187,11 @@ static const gchar introspection_xml[] =
-     "    <method name='CursorDownLookupTable' />"
-     "    <method name='PageUpLookupTable' />"
-     "    <method name='PageDownLookupTable' />"
-+    "    <method name='CandidateClickedLookupTable'>"
-+    "      <arg direction='in' type='u' name='index' />"
-+    "      <arg direction='in' type='u' name='button' />"
-+    "      <arg direction='in' type='u' name='state' />"
-+    "    </method>"
-     "    <method name='RegisterProperties'>"
-     "      <arg direction='in'  type='v' name='props' />"
-     "    </method>"
-@@ -221,7 +229,16 @@ static const gchar introspection_xml[] =
-     "      <arg direction='in'  type='u' name='hints' />"
-     "    </method>"
-     "    <method name='PanelExtensionReceived'>"
--    "      <arg direction='in' type='v' name='data' />"
-+    "      <arg direction='in' type='v' name='event' />"
-+    "    </method>"
-+    "    <method name='ProcessKeyEvent'>"
-+    "      <arg direction='in'  type='u' name='keyval' />"
-+    "      <arg direction='in'  type='u' name='keycode' />"
-+    "      <arg direction='in'  type='u' name='state' />"
-+    "      <arg direction='out' type='b' />"
-+    "    </method>"
-+    "    <method name='CommitTextReceived'>"
-+    "      <arg direction='in' type='v' name='text' />"
-     "    </method>"
-     /* Signals */
-     "    <signal name='CursorUp' />"
-@@ -247,7 +264,23 @@ static const gchar introspection_xml[] =
-     "      <arg type='v' name='text' />"
-     "    </signal>"
-     "    <signal name='PanelExtension'>"
-+    "      <arg type='v' name='event' />"
-+    "    </signal>"
-+    "    <method name='PanelExtensionRegisterKeys'>"
-     "      <arg type='v' name='data' />"
-+    "    </method>"
-+    "    <signal name='UpdatePreeditTextReceived'>"
-+    "      <arg type='v' name='text' />"
-+    "      <arg type='u' name='cursor_pos' />"
-+    "      <arg type='b' name='visible' />"
-+    "    </signal>"
-+    "    <signal name='UpdateAuxiliaryTextReceived'>"
-+    "      <arg type='v' name='text' />"
-+    "      <arg type='b' name='visible' />"
-+    "    </signal>"
-+    "    <signal name='UpdateLookupTableReceived'>"
-+    "      <arg type='v' name='table' />"
-+    "      <arg type='b' name='visible' />"
-     "    </signal>"
-     "  </interface>"
-     "</node>";
-@@ -927,10 +960,81 @@ ibus_panel_service_class_init (IBusPanelServiceClass *class)
-             G_SIGNAL_RUN_LAST,
-             G_STRUCT_OFFSET (IBusPanelServiceClass, panel_extension_received),
-             NULL, NULL,
--            _ibus_marshal_VOID__VARIANT,
-+            _ibus_marshal_VOID__OBJECT,
-+            G_TYPE_NONE,
-+            1,
-+            IBUS_TYPE_EXTENSION_EVENT);
-+
-+    /**
-+     * IBusPanelService::process-key-event:
-+     * @panel: An #IBusPanelService
-+     * @keyval: Key symbol of the key press.
-+     * @keycode: KeyCode of the key press.
-+     * @state: Key modifier flags.
-+     *
-+     * Emitted when a key event is received.
-+     * Implement the member function IBusPanelServiceClass::process_key_event
-+     * in extended class to receive this signal.
-+     * Both the key symbol and keycode are passed to the member function.
-+     * See ibus_input_context_process_key_event() for further explanation of
-+     * key symbol, keycode and which to use.
-+     *
-+     * Returns: %TRUE for successfully process the key; %FALSE otherwise.
-+     * See also:  ibus_input_context_process_key_event().
-+     *
-+     * <note><para>Argument @user_data is ignored in this function.</para>
-+     * </note>
-+     */
-+    panel_signals[PROCESS_KEY_EVENT] =
-+        g_signal_new (I_("process-key-event"),
-+            G_TYPE_FROM_CLASS (gobject_class),
-+            G_SIGNAL_RUN_LAST,
-+            G_STRUCT_OFFSET (IBusPanelServiceClass, process_key_event),
-+            g_signal_accumulator_true_handled, NULL,
-+            _ibus_marshal_BOOL__UINT_UINT_UINT,
-+            G_TYPE_BOOLEAN,
-+            3,
-+            G_TYPE_UINT,
-+            G_TYPE_UINT,
-+            G_TYPE_UINT);
-+
-+    /**
-+     * IBusPanelService::commit-text-received:
-+     * @panel: An #IBusPanelService
-+     * @text: A #IBusText
-+     *
-+     * Emitted when the client application get the ::commit-text-received.
-+     * Implement the member function
-+     * IBusPanelServiceClass::commit_text_received in extended class to
-+     * receive this signal.
-+     *
-+     * <note><para>Argument @user_data is ignored in this function.</para>
-+     * </note>
-+     */
-+    panel_signals[COMMIT_TEXT_RECEIVED] =
-+        g_signal_new (I_("commit-text-received"),
-+            G_TYPE_FROM_CLASS (gobject_class),
-+            G_SIGNAL_RUN_LAST,
-+            G_STRUCT_OFFSET (IBusPanelServiceClass, commit_text_received),
-+            NULL, NULL,
-+            _ibus_marshal_VOID__OBJECT,
-             G_TYPE_NONE,
-             1,
--            G_TYPE_VARIANT);
-+            IBUS_TYPE_TEXT);
-+
-+    panel_signals[CANDIDATE_CLICKED_LOOKUP_TABLE] =
-+        g_signal_new (I_("candidate-clicked-lookup-table"),
-+            G_TYPE_FROM_CLASS (gobject_class),
-+            G_SIGNAL_RUN_LAST,
-+            G_STRUCT_OFFSET (IBusPanelServiceClass,
-+                             candidate_clicked_lookup_table),
-+            NULL, NULL,
-+            _ibus_marshal_VOID__UINT_UINT_UINT,
-+            G_TYPE_NONE,
-+            3,
-+            G_TYPE_UINT,
-+            G_TYPE_UINT,
-+            G_TYPE_UINT);
- }
- 
- static void
-@@ -1129,9 +1233,14 @@ ibus_panel_service_service_method_call (IBusService           *service,
-     }
- 
-     if (g_strcmp0 (method_name, "PanelExtensionReceived") == 0) {
--        GVariant *variant = NULL;
--        g_variant_get (parameters, "(v)", &variant);
--        if (variant == NULL) {
-+        GVariant *arg0 = NULL;
-+        IBusExtensionEvent *event = NULL;
-+        g_variant_get (parameters, "(v)", &arg0);
-+        if (arg0) {
-+            event = IBUS_EXTENSION_EVENT (ibus_serializable_deserialize (arg0));
-+            g_variant_unref (arg0);
-+        }
-+        if (!event) {
-             g_dbus_method_invocation_return_error (
-                     invocation,
-                     G_DBUS_ERROR,
-@@ -1140,11 +1249,63 @@ ibus_panel_service_service_method_call (IBusService           *service,
-             return;
-         }
-         g_signal_emit (panel, panel_signals[PANEL_EXTENSION_RECEIVED], 0,
--                       variant);
--        g_variant_unref (variant);
-+                       event);
-+        _g_object_unref_if_floating (event);
-         g_dbus_method_invocation_return_value (invocation, NULL);
-         return;
-     }
-+    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 (panel,
-+                       panel_signals[PROCESS_KEY_EVENT],
-+                       0,
-+                       keyval,
-+                       keycode,
-+                       state,
-+                       &retval);
-+        g_dbus_method_invocation_return_value (invocation,
-+                                               g_variant_new ("(b)", retval));
-+        return;
-+    }
-+    if (g_strcmp0 (method_name, "CommitTextReceived") == 0) {
-+        GVariant *arg0 = NULL;
-+        IBusText *text = NULL;
-+
-+        g_variant_get (parameters, "(v)", &arg0);
-+        if (arg0) {
-+            text = (IBusText *) ibus_serializable_deserialize (arg0);
-+            g_variant_unref (arg0);
-+        }
-+        if (!text) {
-+            g_dbus_method_invocation_return_error (
-+                    invocation,
-+                    G_DBUS_ERROR,
-+                    G_DBUS_ERROR_FAILED,
-+                    "CommitTextReceived method gives NULL");
-+            return;
-+        }
-+        g_signal_emit (panel,
-+                       panel_signals[COMMIT_TEXT_RECEIVED],
-+                       0,
-+                       text);
-+        _g_object_unref_if_floating (text);
-+        return;
-+    }
-+    if (g_strcmp0 (method_name, "CandidateClickedLookupTable") == 0) {
-+        guint index = 0;
-+        guint button = 0;
-+        guint state = 0;
-+        g_variant_get (parameters, "(uuu)", &index, &button, &state);
-+        g_signal_emit (panel,
-+                       panel_signals[CANDIDATE_CLICKED_LOOKUP_TABLE],
-+                       0,
-+                       index, button, state);
-+        return;
-+    }
-+
- 
-     const static struct {
-         const gchar *name;
-@@ -1318,8 +1479,8 @@ ibus_panel_service_set_content_type (IBusPanelService *panel,
- }
- 
- static void
--ibus_panel_service_panel_extension_received (IBusPanelService *panel,
--                                             GVariant         *data)
-+ibus_panel_service_panel_extension_received (IBusPanelService   *panel,
-+                                             IBusExtensionEvent *event)
- {
-     ibus_panel_service_not_implemented(panel);
- }
-@@ -1396,10 +1557,11 @@ void
- ibus_panel_service_commit_text (IBusPanelService *panel,
-                                 IBusText         *text)
- {
-+    GVariant *variant;
-     g_return_if_fail (IBUS_IS_PANEL_SERVICE (panel));
-     g_return_if_fail (IBUS_IS_TEXT (text));
- 
--    GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
-+    variant = ibus_serializable_serialize ((IBusSerializable *)text);
-     ibus_service_emit_signal ((IBusService *) panel,
-                               NULL,
-                               IBUS_INTERFACE_PANEL,
-@@ -1413,18 +1575,144 @@ ibus_panel_service_commit_text (IBusPanelService *panel,
- }
- 
- void
--ibus_panel_service_panel_extension (IBusPanelService *panel,
--                                    GVariant         *variant)
-+ibus_panel_service_panel_extension (IBusPanelService   *panel,
-+                                    IBusExtensionEvent *event)
- {
-+    GVariant *variant;
-     g_return_if_fail (IBUS_IS_PANEL_SERVICE (panel));
--    g_return_if_fail (variant);
-+    g_return_if_fail (IBUS_IS_EXTENSION_EVENT (event));
- 
-+    variant = ibus_serializable_serialize ((IBusSerializable *)event);
-     ibus_service_emit_signal ((IBusService *) panel,
-                               NULL,
-                               IBUS_INTERFACE_PANEL,
-                               "PanelExtension",
-                               g_variant_new ("(v)", variant),
-                               NULL);
-+
-+    if (g_object_is_floating (event)) {
-+        g_object_unref (event);
-+    }
-+}
-+
-+void
-+ibus_panel_service_panel_extension_register_keys (IBusPanelService   *panel,
-+                                                  const gchar
-+                                                           *first_property_name,
-+                                                  ...)
-+{
-+    GVariantBuilder builder;
-+    GVariantBuilder child;
-+    const gchar *name;
-+    va_list var_args;
-+    IBusProcessKeyEventData *keys;
-+
-+    g_return_if_fail (first_property_name);
-+
-+    g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
-+    name = first_property_name;
-+
-+    va_start (var_args, first_property_name);
-+    do {
-+        keys = va_arg (var_args, IBusProcessKeyEventData *);
-+        g_return_if_fail (keys != NULL);
-+        g_variant_builder_init (&child, G_VARIANT_TYPE ("av"));
-+        for (; keys; keys++) {
-+            if (keys->keyval == 0 && keys->keycode == 0 && keys->state == 0)
-+                break;
-+            g_variant_builder_add (&child, "v",
-+                                   g_variant_new ("(iii)",
-+                                                  keys->keyval,
-+                                                  keys->keycode, 
-+                                                  keys->state));
-+        }
-+        g_variant_builder_add (&builder, "{sv}",
-+                               g_strdup (name), g_variant_builder_end (&child));
-+    } while ((name = va_arg (var_args, const gchar *)));
-+    va_end (var_args);
-+
-+    ibus_service_emit_signal ((IBusService *) panel,
-+                              NULL,
-+                              IBUS_INTERFACE_PANEL,
-+                              "PanelExtensionRegisterKeys",
-+                              g_variant_new ("(v)",
-+                                             g_variant_builder_end (&builder)),
-+                              NULL);
-+}
-+
-+void
-+ibus_panel_service_update_preedit_text_received (IBusPanelService *panel,
-+                                                 IBusText         *text,
-+                                                 guint             cursor_pos,
-+                                                 gboolean          visible)
-+{
-+    GVariant *variant;
-+
-+    g_return_if_fail (IBUS_IS_PANEL_SERVICE (panel));
-+    g_return_if_fail (IBUS_IS_TEXT (text));
-+
-+    variant = ibus_serializable_serialize ((IBusSerializable *)text);
-+    g_return_if_fail (variant);
-+    ibus_service_emit_signal ((IBusService *) panel,
-+                              NULL,
-+                              IBUS_INTERFACE_PANEL,
-+                              "UpdatePreeditTextReceived",
-+                              g_variant_new ("(vub)",
-+                                             variant, cursor_pos, visible),
-+                              NULL);
-+
-+    if (g_object_is_floating (text)) {
-+        g_object_unref (text);
-+    }
-+}
-+
-+void
-+ibus_panel_service_update_auxiliary_text_received (IBusPanelService *panel,
-+                                                   IBusText         *text,
-+                                                   gboolean          visible)
-+{
-+    GVariant *variant;
-+    g_return_if_fail (IBUS_IS_PANEL_SERVICE (panel));
-+    g_return_if_fail (IBUS_IS_TEXT (text));
-+
-+    variant = ibus_serializable_serialize ((IBusSerializable *)text);
-+    g_return_if_fail (variant);
-+    ibus_service_emit_signal ((IBusService *) panel,
-+                              NULL,
-+                              IBUS_INTERFACE_PANEL,
-+                              "UpdateAuxiliaryTextReceived",
-+                              g_variant_new ("(vb)",
-+                                             variant, visible),
-+                              NULL);
-+
-+    if (g_object_is_floating (text)) {
-+        g_object_unref (text);
-+    }
-+}
-+
-+void
-+ibus_panel_service_update_lookup_table_received (IBusPanelService *panel,
-+                                                 IBusLookupTable  *table,
-+                                                 gboolean          visible)
-+{
-+    GVariant *variant;
-+
-+    g_return_if_fail (IBUS_IS_PANEL_SERVICE (panel));
-+    g_return_if_fail (IBUS_IS_LOOKUP_TABLE (table));
-+
-+    variant = ibus_serializable_serialize ((IBusSerializable *)table);
-+    g_return_if_fail (variant);
-+    ibus_service_emit_signal ((IBusService *) panel,
-+                              NULL,
-+                              IBUS_INTERFACE_PANEL,
-+                              "UpdateLookupTableReceived",
-+                              g_variant_new ("(vb)",
-+                                             variant, visible),
-+                              NULL);
-+
-+    if (g_object_is_floating (table)) {
-+        g_object_unref (table);
-+    }
- }
- 
- #define DEFINE_FUNC(name, Name)                             \
-diff --git a/src/ibuspanelservice.h b/src/ibuspanelservice.h
-index 60ef842b..d91f2309 100644
---- a/src/ibuspanelservice.h
-+++ b/src/ibuspanelservice.h
-@@ -38,6 +38,7 @@
- #include "ibuslookuptable.h"
- #include "ibusservice.h"
- #include "ibusproplist.h"
-+#include "ibusxevent.h"
- 
- /*
-  * Type macros.
-@@ -130,11 +131,24 @@ struct _IBusPanelServiceClass {
-                                             gint                    h);
-     void     (* panel_extension_received)
-                                            (IBusPanelService       *panel,
--                                            GVariant               *data);
-+                                            IBusExtensionEvent     *event);
-+    gboolean (* process_key_event)
-+                                           (IBusPanelService       *panel,
-+                                            guint                   keyval,
-+                                            guint                   keycode,
-+                                            guint                   state);
-+    void     (* commit_text_received)
-+                                           (IBusPanelService       *panel,
-+                                            IBusText               *text);
-+    void     (* candidate_clicked_lookup_table)
-+                                           (IBusPanelService       *panel,
-+                                            guint                   index,
-+                                            guint                   button,
-+                                            guint                   state);
- 
-     /*< private >*/
-     /* padding */
--    gpointer pdummy[5];  // We can add 8 pointers without breaking the ABI.
-+    gpointer pdummy[2];  // We can add 8 pointers without breaking the ABI.
- };
- 
- GType            ibus_panel_service_get_type  (void);
-@@ -248,12 +262,105 @@ void ibus_panel_service_commit_text       (IBusPanelService *panel,
- /**
-  * ibus_panel_service_panel_extension:
-  * @panel: An #IBusPanelService
-- * @data: (transfer full): A #GVariant data which is sent to a panel extension. 
-+ * @event: (transfer full): A #PanelExtensionEvent which is sent to a
-+ *                          panel extension. 
-  *
-+ * Enable or disable a panel extension with #IBusExtensionEvent.
-  * 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);
-+void ibus_panel_service_panel_extension   (IBusPanelService   *panel,
-+                                           IBusExtensionEvent *event);
-+
-+/**
-+ * ibus_panel_service_panel_extension_register_keys:
-+ * @panel: An #IBusPanelService
-+ * @first_property_name: the first name of the shortcut keys. This is %NULL
-+ " terminated.
-+ *
-+ * Register shortcut keys to enable panel extensions with #IBusExtensionEvent.
-+ * Notify that a data is sent
-+ * by sending a "PanelExtensionRegisterKeys" message to IBus panel extension
-+ * service. Seems Vala does not support uint[][3] and use
-+ * IBusProcessKeyEventData[]. E.g.
-+ * IBusProcessKeyEventData[] keys = {{
-+ *         IBUS_KEY_e, 0, IBUS_SHIFT_MASK | IBUS_SUPER_MASK }};
-+ * ibus_panel_service_panel_extension_register_keys(panel, "emoji", keys, NULL);
-+ */
-+void ibus_panel_service_panel_extension_register_keys
-+                                           (IBusPanelService  *panel,
-+                                            const gchar       *first_property_name,
-+                                            ...);
-+
-+/**
-+ * ibus_panel_service_update_preedit_text_received:
-+ * @panel: An #IBusPanelService
-+ * @text: Update content.
-+ * @cursor_pos: Current position of cursor
-+ * @visible: Whether the pre-edit buffer is visible.
-+ *
-+ * Notify that the preedit is updated by the panel extension
-+ *
-+ * (Note: The table object will be released, if it is floating.
-+ *  If caller want to keep the object, caller should make the object
-+ *  sink by g_object_ref_sink.)
-+ */
-+void ibus_panel_service_update_preedit_text_received
-+                                          (IBusPanelService *panel,
-+                                           IBusText         *text,
-+                                           guint             cursor_pos,
-+                                           gboolean          visible);
-+
-+/**
-+ * ibus_panel_service_show_preedit_text_received:
-+ * @panel: An IBusPanelService
-+ *
-+ * Notify that the preedit is shown by the panel extension
-+ */
-+void ibus_panel_service_show_preedit_text_received
-+                                          (IBusPanelService *panel);
-+
-+/**
-+ * ibus_panel_service_hide_preedit_text_received:
-+ * @panel: An IBusPanelService
-+ *
-+ * Notify that the preedit is hidden by the panel extension
-+ */
-+void ibus_panel_service_hide_preedit_text_received
-+                                          (IBusPanelService *panel);
-+
-+/**
-+ * ibus_panel_service_update_auxiliary_text_received:
-+ * @panel: An #IBusPanelService
-+ * @text: An #IBusText
-+ * @visible: Whether the auxilirary text is visible.
-+ *
-+ * Notify that the auxilirary is updated by the panel extension.
-+ *
-+ * (Note: The table object will be released, if it is floating.
-+ *  If caller want to keep the object, caller should make the object
-+ *  sink by g_object_ref_sink.)
-+ */
-+void ibus_panel_service_update_auxiliary_text_received
-+                                          (IBusPanelService *panel,
-+                                           IBusText         *text,
-+                                           gboolean          visible);
-+
-+/**
-+ * ibus_panel_service_update_lookup_table_received:
-+ * @panel: An #IBusPanelService
-+ * @table: An #IBusLookupTable
-+ * @visible: Whether the lookup table is visible.
-+ *
-+ * Notify that the lookup table is updated by the panel extension.
-+ *
-+ * (Note: The table object will be released, if it is floating.
-+ *  If caller want to keep the object, caller should make the object
-+ *  sink by g_object_ref_sink.)
-+ */
-+void ibus_panel_service_update_lookup_table_received
-+                                          (IBusPanelService *panel,
-+                                           IBusLookupTable  *table,
-+                                           gboolean          visible);
- G_END_DECLS
- #endif
-diff --git a/src/ibusshare.h b/src/ibusshare.h
-index 757d915b..4f5a306b 100644
---- a/src/ibusshare.h
-+++ b/src/ibusshare.h
-@@ -73,6 +73,15 @@
-  */
- #define IBUS_SERVICE_PANEL_EXTENSION "org.freedesktop.IBus.Panel.Extension"
- 
-+/**
-+ * IBUS_SERVICE_PANEL_EXTENSION_EMOJI:
-+ *
-+ * Address of IBus panel extension service for emoji.
-+ * This service provides emoji, Unicode code point, Unicode name features.
-+ */
-+#define IBUS_SERVICE_PANEL_EXTENSION_EMOJI \
-+        "org.freedesktop.IBus.Panel.Extension.Emoji"
-+
- /**
-  * IBUS_SERVICE_CONFIG:
-  *
-@@ -109,11 +118,13 @@
- #define IBUS_PATH_PANEL         "/org/freedesktop/IBus/Panel"
- 
- /**
-- * IBUS_PATH_PANEL_EXTENSION:
-+ * IBUS_PATH_PANEL_EXTENSION_EMOJI:
-  *
-- * D-Bus path for IBus panel.
-+ * D-Bus path for IBus extension panel for emoji.
-+ * This service provides emoji, Unicode code point, Unicode name features.
-  */
--#define IBUS_PATH_PANEL_EXTENSION "/org/freedesktop/IBus/Panel/Extension"
-+#define IBUS_PATH_PANEL_EXTENSION_EMOJI \
-+        "/org/freedesktop/IBus/Panel/Extension/Emoji"
- 
- /**
-  * IBUS_PATH_CONFIG:
-diff --git a/src/ibusxevent.c b/src/ibusxevent.c
-index dea80272..287bb99b 100644
---- a/src/ibusxevent.c
-+++ b/src/ibusxevent.c
-@@ -22,13 +22,23 @@
- #include "ibusinternal.h"
- #include "ibusxevent.h"
- 
-+#define IBUS_EXTENSION_EVENT_VERSION 1
-+#define IBUS_EXTENSION_EVENT_GET_PRIVATE(o)                             \
-+   (G_TYPE_INSTANCE_GET_PRIVATE ((o),                                   \
-+                                 IBUS_TYPE_EXTENSION_EVENT,             \
-+                                 IBusExtensionEventPrivate))
-+
- #define IBUS_X_EVENT_VERSION 1
--#define IBUS_X_EVENT_GET_PRIVATE(o)  \
-+#define IBUS_X_EVENT_GET_PRIVATE(o)                                     \
-    (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_X_EVENT, IBusXEventPrivate))
- 
- enum {
-     PROP_0,
-     PROP_VERSION,
-+    PROP_NAME,
-+    PROP_IS_ENABLED,
-+    PROP_IS_EXTENSION,
-+    PROP_PARAMS,
-     PROP_EVENT_TYPE,
-     PROP_WINDOW,
-     PROP_SEND_EVENT,
-@@ -52,6 +62,14 @@ enum {
- };
- 
- 
-+struct _IBusExtensionEventPrivate {
-+    guint     version;
-+    gchar    *name;
-+    gboolean  is_enabled;
-+    gboolean  is_extension;
-+    gchar    *params;
-+};
-+
- struct _IBusXEventPrivate {
-     guint    version;
-     guint32  time;
-@@ -73,24 +91,346 @@ struct _IBusXEventPrivate {
- };
- 
- /* 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);
--
-+static void      ibus_extension_event_destroy      (IBusExtensionEvent *event);
-+static void      ibus_extension_event_set_property (IBusExtensionEvent *event,
-+                                                    guint               prop_id,
-+                                                    const GValue       *value,
-+                                                    GParamSpec         *pspec);
-+static void      ibus_extension_event_get_property (IBusExtensionEvent *event,
-+                                                    guint               prop_id,
-+                                                    GValue             *value,
-+                                                    GParamSpec         *pspec);
-+static gboolean  ibus_extension_event_serialize    (IBusExtensionEvent *event,
-+                                                    GVariantBuilder
-+                                                                      *builder);
-+static gint      ibus_extension_event_deserialize  (IBusExtensionEvent *event,
-+                                                    GVariant
-+                                                                      *variant);
-+static gboolean  ibus_extension_event_copy         (IBusExtensionEvent
-+                                                                          *dest,
-+                                                    const IBusExtensionEvent
-+                                                                          *src);
-+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 (IBusExtensionEvent, ibus_extension_event, IBUS_TYPE_SERIALIZABLE)
- G_DEFINE_TYPE (IBusXEvent, ibus_x_event, IBUS_TYPE_SERIALIZABLE)
- 
-+static void
-+ibus_extension_event_class_init (IBusExtensionEventClass *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_extension_event_set_property;
-+    gobject_class->get_property =
-+            (GObjectGetPropertyFunc) ibus_extension_event_get_property;
-+
-+    object_class->destroy =
-+            (IBusObjectDestroyFunc) ibus_extension_event_destroy;
-+
-+    serializable_class->serialize   =
-+            (IBusSerializableSerializeFunc) ibus_extension_event_serialize;
-+    serializable_class->deserialize =
-+            (IBusSerializableDeserializeFunc) ibus_extension_event_deserialize;
-+    serializable_class->copy        =
-+            (IBusSerializableCopyFunc) ibus_extension_event_copy;
-+
-+    /* install properties */
-+    /**
-+     * IBusExtensionEvent:version:
-+     *
-+     * Version of the #IBusExtensionEvent.
-+     */
-+    g_object_class_install_property (gobject_class,
-+                    PROP_VERSION,
-+                    g_param_spec_uint ("version",
-+                        "version",
-+                        "version",
-+                        0,
-+                        G_MAXUINT32,
-+                        IBUS_EXTENSION_EVENT_VERSION,
-+                        G_PARAM_READABLE));
-+
-+    /**
-+     * IBusExtensionEvent:name:
-+     *
-+     * Name of the extension in the #IBusExtensionEvent.
-+     */
-+    g_object_class_install_property (gobject_class,
-+                    PROP_NAME,
-+                    g_param_spec_string ("name",
-+                        "name",
-+                        "name of the extension",
-+                        "",
-+                        G_PARAM_READWRITE |
-+                        G_PARAM_CONSTRUCT_ONLY));
-+
-+    /**
-+     * IBusExtensionEvent:is-enabled:
-+     *
-+     * %TRUE if the extension is enabled in the #IBusExtensionEvent.
-+     */
-+    g_object_class_install_property (gobject_class,
-+                    PROP_IS_ENABLED,
-+                    g_param_spec_boolean ("is-enabled",
-+                        "is enabled",
-+                        "if the extension is enabled",
-+                        FALSE,
-+                        G_PARAM_READWRITE |
-+                        G_PARAM_CONSTRUCT_ONLY));
-+
-+    /**
-+     * IBusExtensionEvent:is-extension:
-+     *
-+     * %TRUE if the #IBusExtensionEvent is called by an extension.
-+     * %FALSE if the #IBusExtensionEvent is called by an active engine or
-+     * panel.
-+     * If this value is %TRUE, the event is send to ibus-daemon, an active
-+     * engine. If it's %FALSE, the event is sned to ibus-daemon, panels.
-+     */
-+    g_object_class_install_property (gobject_class,
-+                    PROP_IS_EXTENSION,
-+                    g_param_spec_boolean ("is-extension",
-+                        "is extension",
-+                        "if the event is called by an extension",
-+                        FALSE,
-+                        G_PARAM_READWRITE |
-+                        G_PARAM_CONSTRUCT_ONLY));
-+
-+    /**
-+     * IBusExtensionEvent:params:
-+     *
-+     * Parameters to enable the extension in the #IBusExtensionEvent.
-+     */
-+    g_object_class_install_property (gobject_class,
-+                    PROP_PARAMS,
-+                    g_param_spec_string ("params",
-+                        "params",
-+                        "Parameters to enable the extension",
-+                        "",
-+                        G_PARAM_READWRITE |
-+                        G_PARAM_CONSTRUCT_ONLY));
-+
-+    g_type_class_add_private (class, sizeof (IBusExtensionEventPrivate));
-+}
-+
-+static void
-+ibus_extension_event_init (IBusExtensionEvent *event)
-+{
-+    event->priv = IBUS_EXTENSION_EVENT_GET_PRIVATE (event);
-+    event->priv->version = IBUS_EXTENSION_EVENT_VERSION;
-+}
-+
-+static void
-+ibus_extension_event_destroy (IBusExtensionEvent *event)
-+{
-+    g_clear_pointer (&event->priv->name, g_free);
-+
-+    IBUS_OBJECT_CLASS(ibus_extension_event_parent_class)->
-+            destroy (IBUS_OBJECT (event));
-+}
-+
-+static void
-+ibus_extension_event_set_property (IBusExtensionEvent   *event,
-+                                   guint         prop_id,
-+                                   const GValue *value,
-+                                   GParamSpec   *pspec)
-+{
-+    IBusExtensionEventPrivate *priv = event->priv;
-+
-+    switch (prop_id) {
-+    case PROP_NAME:
-+        g_free (priv->name);
-+        priv->name = g_value_dup_string (value);
-+        break;
-+    case PROP_IS_ENABLED:
-+        priv->is_enabled = g_value_get_boolean (value);
-+        break;
-+    case PROP_IS_EXTENSION:
-+        priv->is_extension = g_value_get_boolean (value);
-+        break;
-+    case PROP_PARAMS:
-+        priv->params = g_value_dup_string (value);
-+        break;
-+    default:
-+        G_OBJECT_WARN_INVALID_PROPERTY_ID (event, prop_id, pspec);
-+    }
-+}
-+
-+static void
-+ibus_extension_event_get_property (IBusExtensionEvent *event,
-+                                   guint               prop_id,
-+                                   GValue             *value,
-+                                   GParamSpec         *pspec)
-+{
-+    IBusExtensionEventPrivate *priv = event->priv;
-+    switch (prop_id) {
-+    case PROP_VERSION:
-+        g_value_set_uint (value, priv->version);
-+        break;
-+    case PROP_NAME:
-+        g_value_set_string (value, priv->name);
-+        break;
-+    case PROP_IS_ENABLED:
-+        g_value_set_boolean (value, priv->is_enabled);
-+        break;
-+    case PROP_IS_EXTENSION:
-+        g_value_set_boolean (value, priv->is_extension);
-+        break;
-+    case PROP_PARAMS:
-+        g_value_set_string (value, priv->params);
-+        break;
-+    default:
-+        G_OBJECT_WARN_INVALID_PROPERTY_ID (event, prop_id, pspec);
-+    }
-+}
-+
-+static gboolean
-+ibus_extension_event_serialize (IBusExtensionEvent *event,
-+                                GVariantBuilder    *builder)
-+{
-+    gboolean retval;
-+    IBusExtensionEventPrivate *priv;
-+
-+    retval = IBUS_SERIALIZABLE_CLASS (ibus_extension_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, "s", NOTNULL (priv->name));
-+    g_variant_builder_add (builder, "b", priv->is_enabled);
-+    g_variant_builder_add (builder, "b", priv->is_extension);
-+    g_variant_builder_add (builder, "s", NOTNULL (priv->params));
-+#undef NOTNULL
-+
-+    return TRUE;
-+}
-+
-+static gint
-+ibus_extension_event_deserialize (IBusExtensionEvent *event,
-+                                  GVariant           *variant)
-+{
-+    gint retval;
-+    IBusExtensionEventPrivate *priv;
-+
-+    retval = IBUS_SERIALIZABLE_CLASS (ibus_extension_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);
-+    ibus_g_variant_get_child_string (variant, retval++,
-+                                     &priv->name);
-+    g_variant_get_child (variant, retval++, "b", &priv->is_enabled);
-+    g_variant_get_child (variant, retval++, "b", &priv->is_extension);
-+    ibus_g_variant_get_child_string (variant, retval++,
-+                                     &priv->params);
-+
-+    return retval;
-+}
-+
-+static gboolean
-+ibus_extension_event_copy (IBusExtensionEvent       *dest,
-+                           const IBusExtensionEvent *src)
-+{
-+    gboolean retval;
-+    IBusExtensionEventPrivate *dest_priv = dest->priv;
-+    IBusExtensionEventPrivate *src_priv = src->priv;
-+
-+    retval = IBUS_SERIALIZABLE_CLASS (ibus_extension_event_parent_class)->
-+            copy ((IBusSerializable *)dest, (IBusSerializable *)src);
-+    g_return_val_if_fail (retval, FALSE);
-+
-+    dest_priv->version           = src_priv->version;
-+    dest_priv->name              = g_strdup (src_priv->name);
-+    dest_priv->is_enabled        = src_priv->is_enabled;
-+    dest_priv->is_extension      = src_priv->is_extension;
-+    dest_priv->params            = g_strdup (src_priv->params);
-+    return TRUE;
-+}
-+
-+IBusExtensionEvent *
-+ibus_extension_event_new (const gchar   *first_property_name,
-+                          ...)
-+{
-+    va_list var_args;
-+    IBusExtensionEvent *event;
-+
-+    va_start (var_args, first_property_name);
-+    event = (IBusExtensionEvent *) g_object_new_valist (
-+            IBUS_TYPE_EXTENSION_EVENT,
-+            first_property_name,
-+            var_args);
-+    va_end (var_args);
-+    g_assert (event->priv->version != 0);
-+    return event;
-+}
-+
-+guint
-+ibus_extension_event_get_version (IBusExtensionEvent *event)
-+{
-+    g_return_val_if_fail (IBUS_IS_EXTENSION_EVENT (event), 0);
-+    return event->priv->version;
-+}
-+
-+const gchar *
-+ibus_extension_event_get_name (IBusExtensionEvent *event)
-+{
-+    g_return_val_if_fail (IBUS_IS_EXTENSION_EVENT (event), "");
-+    return event->priv->name;
-+}
-+
-+gboolean
-+ibus_extension_event_is_enabled (IBusExtensionEvent *event)
-+{
-+    g_return_val_if_fail (IBUS_IS_EXTENSION_EVENT (event), FALSE);
-+    return event->priv->is_enabled;
-+}
-+
-+gboolean
-+ibus_extension_event_is_extension (IBusExtensionEvent *event)
-+{
-+    g_return_val_if_fail (IBUS_IS_EXTENSION_EVENT (event), FALSE);
-+    return event->priv->is_extension;
-+}
-+
-+const gchar *
-+ibus_extension_event_get_params (IBusExtensionEvent *event)
-+{
-+    g_return_val_if_fail (IBUS_IS_EXTENSION_EVENT (event), "");
-+    return event->priv->params;
-+}
-+
-+
- static void
- ibus_x_event_class_init (IBusXEventClass *class)
- {
-@@ -454,6 +794,7 @@ static void
- ibus_x_event_destroy (IBusXEvent *event)
- {
-     g_clear_pointer (&event->priv->string, g_free);
-+    g_clear_pointer (&event->priv->purpose, g_free);
- 
-     IBUS_OBJECT_CLASS(ibus_x_event_parent_class)->destroy (IBUS_OBJECT (event));
- }
-diff --git a/src/ibusxevent.h b/src/ibusxevent.h
-index f35f14e4..d44cc8f4 100644
---- a/src/ibusxevent.h
-+++ b/src/ibusxevent.h
-@@ -29,8 +29,8 @@
- 
- /**
-  * SECTION: ibusxevent
-- * @short_description: XEvent wrapper object
-- * @title: IBusXEvent
-+ * @short_description: Extension Event wrapper object
-+ * @title: IBusExtensionEvent
-  * @stability: Unstable
-  *
-  * An IBusXEvent provides a wrapper of XEvent.
-@@ -45,25 +45,150 @@
-  */
- 
- /* define GOBJECT macros */
--#define IBUS_TYPE_X_EVENT            \
-+#define IBUS_TYPE_EXTENSION_EVENT                                       \
-+    (ibus_extension_event_get_type ())
-+#define IBUS_EXTENSION_EVENT(obj)                                       \
-+    (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                 \
-+                                 IBUS_TYPE_EXTENSION_EVENT,             \
-+                                 IBusExtensionEvent))
-+#define IBUS_EXTENSION_EVENT_CLASS(klass)                               \
-+    (G_TYPE_CHECK_CLASS_CAST ((klass),                                  \
-+                              IBUS_TYPE_EXTENSION_EVENT,                \
-+                              IBusExtensionEventClass))
-+#define IBUS_IS_EXTENSION_EVENT(obj)                                    \
-+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IBUS_TYPE_EXTENSION_EVENT))
-+#define IBUS_IS_EXTENSION_EVENT_CLASS(klass)                            \
-+    (G_TYPE_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_EXTENSION_EVENT))
-+#define IBUS_EXTENSION_EVENT_GET_CLASS(obj)                             \
-+    (G_TYPE_INSTANCE_GET_CLASS ((obj),                                  \
-+                                IBUS_TYPE_EXTENSION_EVENT,              \
-+                                IBusExtensionEventClass))
-+
-+#define IBUS_TYPE_X_EVENT                                               \
-     (ibus_x_event_get_type ())
--#define IBUS_X_EVENT(obj)            \
-+#define IBUS_X_EVENT(obj)                                               \
-     (G_TYPE_CHECK_INSTANCE_CAST ((obj), IBUS_TYPE_X_EVENT, IBusXEvent))
--#define IBUS_X_EVENT_CLASS(klass)    \
-+#define IBUS_X_EVENT_CLASS(klass)                                       \
-     (G_TYPE_CHECK_CLASS_CAST ((klass), IBUS_TYPE_X_EVENT, IBusXEventClass))
--#define IBUS_IS_X_EVENT(obj)         \
-+#define IBUS_IS_X_EVENT(obj)                                            \
-     (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IBUS_TYPE_X_EVENT))
--#define IBUS_IS_X_EVENT_CLASS(klass) \
-+#define IBUS_IS_X_EVENT_CLASS(klass)                                    \
-     (G_TYPE_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_X_EVENT))
--#define IBUS_X_EVENT_GET_CLASS(obj)  \
-+#define IBUS_X_EVENT_GET_CLASS(obj)                                     \
-     (G_TYPE_INSTANCE_GET_CLASS ((obj), IBUS_TYPE_X_EVENT, IBusXEventClass))
- 
- G_BEGIN_DECLS
- 
-+typedef struct _IBusProcessKeyEventData IBusProcessKeyEventData;
-+typedef struct _IBusExtensionEvent IBusExtensionEvent;
-+typedef struct _IBusExtensionEventClass IBusExtensionEventClass;
-+typedef struct _IBusExtensionEventPrivate IBusExtensionEventPrivate;
- typedef struct _IBusXEvent IBusXEvent;
- typedef struct _IBusXEventClass IBusXEventClass;
- typedef struct _IBusXEventPrivate IBusXEventPrivate;
- 
-+/**
-+ * IBusProcessKeyEventData:
-+ *
-+ * IBuProcessKeyEventData properties.
-+ */
-+struct _IBusProcessKeyEventData {
-+    /*< public >*/
-+    guint keyval;
-+    guint keycode;
-+    guint state;
-+};
-+
-+/**
-+ * IBusExtensionEvent:
-+ *
-+ * IBusExtensionEvent properties.
-+ */
-+struct _IBusExtensionEvent {
-+    /*< private >*/
-+    IBusSerializable parent;
-+    IBusExtensionEventPrivate *priv;
-+
-+    /* instance members */
-+    /*< public >*/
-+};
-+
-+struct _IBusExtensionEventClass {
-+    /*< private >*/
-+    IBusSerializableClass parent;
-+
-+    /* class members */
-+    /*< public >*/
-+
-+    /*< private >*/
-+    /* padding */
-+    gpointer pdummy[10];
-+};
-+
-+
-+GType              ibus_extension_event_get_type    (void);
-+
-+/**
-+ * ibus_extension_event_new:
-+ * @first_property_name: Name of the first property.
-+ * @...: the NULL-terminated arguments of the properties and values.
-+ *
-+ * Create a new #IBusExtensionEvent.
-+ *
-+ * Returns: A newly allocated #IBusExtensionEvent. E.g.
-+ * ibus_extension_event_new ("name", "emoji", "is-enabled", TRUE, NULL);
-+ */
-+IBusExtensionEvent *ibus_extension_event_new        (const gchar
-+                                                           *first_property_name,
-+                                                     ...);
-+
-+/**
-+ * ibus_extension_event_get_version:
-+ * @event: An #IBusExtensionEvent.
-+ *
-+ * Returns: Version of #IBusExtensionEvent
-+ */
-+guint              ibus_extension_event_get_version (IBusExtensionEvent *event);
-+
-+/**
-+ * ibus_extension_event_get_purpose:
-+ * @event: An #IBusExtensionEvent.
-+ *
-+ * Returns: name of the extension for #IBusXEvent
-+ */
-+const gchar *      ibus_extension_event_get_name    (IBusExtensionEvent *event);
-+
-+/**
-+ * ibus_extension_event_is_enabled:
-+ * @event: An #IBusExtensionEvent.
-+ *
-+ * Returns: %TRUE if the extension is enabled for #IBusExtensionEvent
-+ */
-+gboolean           ibus_extension_event_is_enabled  (IBusExtensionEvent *event);
-+
-+/**
-+ * ibus_extension_event_is_extension:
-+ * @event: An #IBusExtensionEvent.
-+ *
-+ * Returns: %TRUE if the #IBusExtensionEvent is called by an extension.
-+ * %FALSE if the #IBusExtensionEvent is called by an active engine or
-+ * panel.
-+ * If this value is %TRUE, the event is send to ibus-daemon, an active
-+ * engine. If it's %FALSE, the event is sned to ibus-daemon, panels.
-+ */
-+gboolean           ibus_extension_event_is_extension
-+                                                    (IBusExtensionEvent *event);
-+
-+/**
-+ * ibus_extension_event_get_params:
-+ * @event: An #IBusExtensionEvent.
-+ *
-+ * Returns: Parameters to enable the extension for #IBusXEvent
-+ */
-+const gchar *      ibus_extension_event_get_params  (IBusExtensionEvent *event);
-+
-+
-+
- typedef enum {
-     IBUS_X_EVENT_NOTHING           = -1,
-     IBUS_X_EVENT_KEY_PRESS         = 0,
-@@ -76,7 +201,7 @@ typedef enum {
-  * IBusXEvent:
-  * @type: event type
-  *
-- * IBusEngine properties.
-+ * IBusXEvent properties.
-  */
- struct _IBusXEvent {
-     /*< private >*/
-diff --git a/ui/gtk3/Makefile.am b/ui/gtk3/Makefile.am
-index bf9f98d7..aaba7a4d 100644
---- a/ui/gtk3/Makefile.am
-+++ b/ui/gtk3/Makefile.am
-@@ -78,6 +78,7 @@ AM_VALAFLAGS = \
- 	--pkg=ibus-1.0 \
- 	--pkg=config \
- 	--pkg=xi \
-+	--pkg=gdk-wayland \
- 	--target-glib="$(VALA_TARGET_GLIB_VERSION)" \
- 	$(NULL)
- 
-@@ -176,6 +177,7 @@ ibus_ui_emojier_VALASOURCES =                   \
-     emojier.vala                                \
-     iconwidget.vala                             \
-     separator.vala                              \
-+    pango.vala                                  \
-     $(NULL)
- ibus_ui_emojier_SOURCES =                       \
-     $(ibus_ui_emojier_VALASOURCES:.vala=.c)     \
-@@ -213,6 +215,7 @@ ibus_extension_gtk3_VALASOURCES =               \
-     iconwidget.vala                             \
-     keybindingmanager.vala                      \
-     panelbinding.vala                           \
-+    pango.vala                                  \
-     $(NULL)
- ibus_extension_gtk3_SOURCES =                   \
-     $(ibus_extension_gtk3_VALASOURCES:.vala=.c) \
-diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala
-index 0c0865f1..cd98c9d7 100644
---- a/ui/gtk3/emojier.vala
-+++ b/ui/gtk3/emojier.vala
-@@ -226,43 +226,6 @@ public 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(
--                name : "IBusEmojierTitleLabelBox",
--                show_close_button: true,
--                decoration_layout: ":close",
--                title: title
--            );
--            var vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
--            set_custom_title(vbox);
--            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);
--            vbox.pack_start(m_lang_label, true, false, 0);
--
--            var menu = new GLib.Menu();
--            menu.append(_("Show emoji variants"), "win.variant");
--            var menu_button = new Gtk.MenuButton();
--            menu_button.set_direction(Gtk.ArrowType.NONE);
--            menu_button.set_valign(Gtk.Align.CENTER);
--            menu_button.set_menu_model(menu);
--            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() {
-         }
-@@ -275,6 +238,8 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         BACKWARD,
-     }
- 
-+    public const uint BUTTON_CLOSE_BUTTON = 1000;
-+
-     private const uint EMOJI_GRID_PAGE = 10;
-     private const string EMOJI_CATEGORY_FAVORITES = N_("Favorites");
-     private const string EMOJI_CATEGORY_OTHERS = N_("Others");
-@@ -313,11 +278,19 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     private static bool m_show_unicode = false;
-     private static LoadProgressObject m_unicode_progress_object;
-     private static bool m_loaded_unicode = false;
-+    private static string m_warning_message = "";
- 
-     private ThemedRGBA m_rgba;
-     private Gtk.Box m_vbox;
--    private ETitleLabelBox m_title;
-     private EEntry m_entry;
-+    /* If emojier is emoji category list or Unicode category list,
-+     * m_annotation is "" and preedit is also "".
-+     * If emojier is candidate mode, m_annotation is an annotation and
-+     * get_current_candidate() returns the current emoji.
-+     * But the current preedit can be "" in candidate mode in case that
-+     * Unicode candidate window has U+0000.
-+     */
-+    private string m_annotation = "";
-     private string? m_backward;
-     private int m_backward_index = -1;
-     private EScrolledWindow? m_scrolled_window = null;
-@@ -326,8 +299,20 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     private string m_input_context_path = "";
-     private GLib.MainLoop? m_loop;
-     private string? m_result;
--    private string? m_unicode_point = null;
-+    /* If m_candidate_panel_is_visible is true, emojier is candidate mode and
-+     * the emoji lookup window is visible.
-+     * If m_candidate_panel_is_visible is false, the emoji lookup window is
-+     * not visible but the mode is not clear.
-+     */
-     private bool m_candidate_panel_is_visible;
-+    /* If m_candidate_panel_mode is true, emojier is candidate mode and
-+     * it does not depend on whether the window is visible or not.
-+     * I.E. the first candidate does not show the lookup window and the
-+     * second one shows the window.
-+     * If m_candidate_panel_mode is false, emojier is emoji category list or
-+     * Unicode category list.
-+     */
-+    private bool m_candidate_panel_mode;
-     private int m_category_active_index = -1;
-     private IBus.LookupTable m_lookup_table;
-     private Gtk.Label[] m_candidates;
-@@ -337,23 +322,18 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     protected static double m_mouse_x;
-     protected static double m_mouse_y;
-     private Gtk.ProgressBar m_unicode_progress_bar;
-+    private uint m_unicode_progress_id;
-     private Gtk.Label m_unicode_percent_label;
-     private double m_unicode_percent;
-+    private Gdk.Rectangle m_cursor_location;
-+    private bool m_is_up_side_down = false;
-+    private uint m_redraw_window_id;
- 
-     public signal void candidate_clicked(uint index, uint button, uint state);
- 
-     public IBusEmojier() {
-         GLib.Object(
--            type : Gtk.WindowType.TOPLEVEL,
--            events : Gdk.EventMask.KEY_PRESS_MASK |
--                     Gdk.EventMask.KEY_RELEASE_MASK |
--                     Gdk.EventMask.BUTTON_PRESS_MASK |
--                     Gdk.EventMask.BUTTON_RELEASE_MASK,
--            window_position : Gtk.WindowPosition.CENTER,
--            icon_name: "ibus-setup",
--            accept_focus : true,
--            resizable : true,
--            focus_visible : true
-+            type : Gtk.WindowType.POPUP
-         );
- 
-         // GLib.ActionEntry accepts const variables only.
-@@ -363,6 +343,9 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-                 new GLib.Variant.boolean(m_show_emoji_variant));
-         action.activate.connect(check_action_variant_cb);
-         add_action(action);
-+        action = new GLib.SimpleAction("close", null);
-+        action.activate.connect(action_close_cb);
-+        add_action(action);
-         if (m_current_lang_id == null)
-             m_current_lang_id = "en";
-         if (m_emoji_font_family == null)
-@@ -448,14 +431,12 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-                 css_provider,
-                 Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
- 
--        m_title = new ETitleLabelBox(_("Emoji Choice"));
--        set_titlebar(m_title);
-         m_vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
-         add(m_vbox);
- 
-         m_entry = new EEntry();
-         m_entry.set_placeholder_text(_("Type annotation or choose emoji"));
--        m_vbox.add(m_entry);
-+        //m_vbox.add(m_entry);
-         m_entry.changed.connect(() => {
-             update_candidate_window();
-         });
-@@ -480,10 +461,16 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-                 m_loop.quit();
-         });
- 
-+        size_allocate.connect((w, a) => {
-+            adjust_window_position();
-+        });
-+
-         candidate_clicked.connect((i, b, s) => {
--            candidate_panel_select_index(i);
-+            if (m_input_context_path != "")
-+                candidate_panel_select_index(i, b);
-         });
- 
-+
-         if (m_annotation_to_emojis_dict == null) {
-             reload_emoji_dict();
-         }
-@@ -814,6 +801,12 @@ public class IBusEmojier : Gtk.ApplicationWindow {
- 
- 
-     private void remove_all_children() {
-+        if (m_list_box != null) {
-+            foreach (Gtk.Widget w in m_list_box.get_children()) {
-+                w.destroy();
-+            }
-+            m_list_box = null;
-+        }
-         foreach (Gtk.Widget w in m_vbox.get_children()) {
-             if (w.name == "IBusEmojierEntry" ||
-                 w.name == "IBusEmojierTitleLabelBox") {
-@@ -824,15 +817,40 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     }
- 
- 
-+    private void clamp_page() {
-+        Gtk.ListBoxRow 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_val_if_fail(m_category_active_index >= 0, false);
-+        m_lookup_table.set_cursor_pos((uint)m_category_active_index);
-+    }
-+
-+
-     private void show_category_list() {
-+        // Do not call remove_all_children() to work adjustment.clamp_page()
-+        // with PageUp/Down.
-+        // After show_candidate_panel() is called, m_category_active_index
-+        // is saved for Escape key but m_list_box is null by
-+        // remove_all_children().
-+        if (m_category_active_index >= 0 && m_list_box != null) {
-+            var row = m_list_box.get_row_at_index(m_category_active_index);
-+            m_list_box.select_row(row);
-+            return;
-+        }
-+        if (m_category_active_index < 0)
-+            m_category_active_index = 0;
-         remove_all_children();
-         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);
-         m_vbox.add(m_scrolled_window);
-         Gtk.Viewport viewport = new Gtk.Viewport(null, null);
-         m_scrolled_window.add(viewport);
-@@ -842,53 +860,21 @@ public 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 = -1;
-+            m_category_active_index = gtkrow.get_index();
-             EBoxRow row = gtkrow as EBoxRow;
-             show_emoji_for_category(row.text);
-+            show_all();
-         });
- 
--        uint n = 0;
--        if (m_favorites.length > 0) {
--            EBoxRow row = new EBoxRow(EMOJI_CATEGORY_FAVORITES);
--            EPaddedLabelBox widget =
--                    new EPaddedLabelBox(_(EMOJI_CATEGORY_FAVORITES),
--                                        Gtk.Align.CENTER);
--            row.add(widget);
--            m_list_box.add(row);
--            if (n++ == m_category_active_index)
--                m_list_box.select_row(row);
--        }
--        GLib.List<unowned string> categories =
--                m_category_to_emojis_dict.get_keys();
--        // FIXME: How to cast GLib.CompareFunc<string> to strcmp?
--        categories.sort((a, b) => {
--            if (a == EMOJI_CATEGORY_OTHERS && b != EMOJI_CATEGORY_OTHERS)
--                return 1;
--            else if (a != EMOJI_CATEGORY_OTHERS && b == EMOJI_CATEGORY_OTHERS)
--                return -1;
--            return GLib.strcmp(_(a), _(b));
--        });
--        foreach (unowned string category in categories) {
--            // "Others" category includes next unicode chars and fonts do not support
--            // the base and varints yet.
--            if (category == EMOJI_CATEGORY_OTHERS)
--               continue;
-+        uint ncandidates = m_lookup_table.get_number_of_candidates();
-+        for (uint i = 0; i < ncandidates; i++) {
-+            string category = m_lookup_table.get_candidate(i).text;
-             EBoxRow row = new EBoxRow(category);
-             EPaddedLabelBox widget =
-                     new EPaddedLabelBox(_(category), Gtk.Align.CENTER);
-             row.add(widget);
-             m_list_box.add(row);
--            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)
-+            if (i == m_category_active_index)
-                 m_list_box.select_row(row);
-         }
- 
-@@ -903,6 +889,7 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     private void show_emoji_for_category(string category) {
-         if (category == EMOJI_CATEGORY_FAVORITES) {
-             m_lookup_table.clear();
-+            m_candidate_panel_mode = true;
-             foreach (unowned string favorate in m_favorites) {
-                 IBus.Text text = new IBus.Text.from_string(favorate);
-                 m_lookup_table.append_candidate(text);
-@@ -911,25 +898,26 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         } else if (category == EMOJI_CATEGORY_UNICODE) {
-             m_category_active_index = -1;
-             m_show_unicode = true;
--            show_unicode_blocks();
-+            update_unicode_blocks();
-             return;
-         } else {
-             unowned GLib.SList<unowned string> emojis =
-                     m_category_to_emojis_dict.lookup(category);
-             m_lookup_table.clear();
-+            m_candidate_panel_mode = true;
-             foreach (unowned string emoji in emojis) {
-                 IBus.Text text = new IBus.Text.from_string(emoji);
-                 m_lookup_table.append_candidate(text);
-             }
-             m_backward = category;
-         }
-+        m_annotation = m_lookup_table.get_candidate(0).text;
-         // Restore the cursor position before the special table of
-         // emoji variants is shown.
-         if (m_backward_index >= 0) {
-             m_lookup_table.set_cursor_pos((uint)m_backward_index);
-             m_backward_index = -1;
-         }
--        show_candidate_panel();
-     }
- 
- 
-@@ -940,18 +928,28 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             IBus.Text text = new IBus.Text.from_string(emoji);
-             m_lookup_table.append_candidate(text);
-         }
--        show_candidate_panel();
-     }
- 
- 
-     private void show_unicode_blocks() {
-+        // Do not call remove_all_children() to work adjustment.clamp_page()
-+        // with PageUp/Down.
-+        // After show_candidate_panel() is called, m_category_active_index
-+        // is saved for Escape key but m_list_box is null by
-+        // remove_all_children().
-+        if (m_category_active_index >= 0 && m_list_box != null) {
-+            var row = m_list_box.get_row_at_index(m_category_active_index);
-+            m_list_box.select_row(row);
-+            return;
-+        }
-+        if (m_category_active_index < 0)
-+            m_category_active_index = 0;
-         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,
-@@ -964,10 +962,10 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             m_category_active_index = -1;
-             m_show_unicode = false;
-             hide_candidate_panel();
-+            show_all();
-             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);
-@@ -977,9 +975,10 @@ public 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 = -1;
-+            m_category_active_index = gtkrow.get_index();
-             EBoxRow row = gtkrow as EBoxRow;
-             show_unicode_for_block(row.text);
-+            show_candidate_panel();
-         });
- 
-         uint n = 0;
-@@ -1007,44 +1006,18 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             m_list_box.unselect_all();
-         m_list_box.invalidate_filter();
-         m_list_box.set_selection_mode(Gtk.SelectionMode.SINGLE);
-+        Gtk.ListBoxRow row = m_list_box.get_row_at_index((int)n - 1);
-+
-+        // If clamp_page() would be called without the allocation signal,
-+        // the jumping page could be failed when returns from 
-+        // show_unicode_for_block() with Escape key.
-+        row.size_allocate.connect((w, a) => {
-+            clamp_page();
-+        });
-     }
- 
-+
-     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) {
-@@ -1055,6 +1028,7 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             }
-         }
-         m_lookup_table.clear();
-+        m_candidate_panel_mode = true;
-         for (unichar ch = start; ch < end; ch++) {
-             unowned IBus.UnicodeData? data =
-                     m_unicode_to_data_dict.lookup(ch);
-@@ -1064,7 +1038,7 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             m_lookup_table.append_candidate(text);
-         }
-         m_backward = block_name;
--        show_candidate_panel();
-+        m_annotation = m_lookup_table.get_candidate(0).text;
-     }
- 
- 
-@@ -1091,6 +1065,41 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         prev_button.set_relief(Gtk.ReliefStyle.NONE);
-         prev_button.set_tooltip_text(_("Page Up"));
- 
-+        var menu = new GLib.Menu();
-+        menu.append(_("Show emoji variants"), "win.variant");
-+        menu.append(_("Close"), "win.close");
-+        var menu_button = new Gtk.MenuButton();
-+        menu_button.set_direction(Gtk.ArrowType.NONE);
-+        menu_button.set_valign(Gtk.Align.CENTER);
-+        menu_button.set_menu_model(menu);
-+        menu_button.set_relief(Gtk.ReliefStyle.NONE);
-+        menu_button.set_tooltip_text(_("Menu"));
-+
-+        IBus.Text text = this.get_title_text();
-+        Pango.AttrList attrs = get_pango_attr_list_from_ibus_text(text);
-+        Gtk.Label title_label = new Gtk.Label(text.get_text());
-+        title_label.set_attributes(attrs);
-+
-+        Gtk.Button? warning_button = null;
-+        if (m_warning_message != "") { 
-+            warning_button = new Gtk.Button();
-+            warning_button.set_tooltip_text(
-+                    _("Click to view a warning message"));
-+            warning_button.set_image(new Gtk.Image.from_icon_name(
-+                                  "dialog-warning",
-+                                  Gtk.IconSize.MENU));
-+            warning_button.set_relief(Gtk.ReliefStyle.NONE);
-+            warning_button.clicked.connect(() => {
-+                Gtk.Label warning_label = new Gtk.Label(m_warning_message);
-+                warning_label.set_line_wrap(true);
-+                warning_label.set_max_width_chars(40);
-+                Gtk.Popover popover = new Gtk.Popover(warning_button);
-+                popover.add(warning_label);
-+                popover.show_all();
-+                popover.popup();
-+            });
-+        }
-+
-         Gtk.Box buttons_hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
-         Gtk.Label state_label = new Gtk.Label(null);
-         state_label.set_size_request(10, -1);
-@@ -1099,14 +1108,55 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         buttons_hbox.pack_start(state_label, false, true, 0);
-         buttons_hbox.pack_start(prev_button, false, false, 0);
-         buttons_hbox.pack_start(next_button, false, false, 0);
-+        buttons_hbox.pack_start(title_label, false, false, 0);
-+        if (warning_button != null)
-+            buttons_hbox.pack_start(warning_button, false, false, 0);
-+        buttons_hbox.pack_end(menu_button, false, false, 0);
-         m_vbox.pack_start(buttons_hbox, false, false, 0);
-         buttons_hbox.show_all();
-     }
- 
- 
--    private bool check_unicode_point() {
--        string annotation = m_entry.get_text();
--        m_unicode_point = null;
-+    private void show_unicode_progress_bar() {
-+        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;
-+        });
-+        if (m_unicode_progress_id > 0) {
-+            GLib.Source.remove(m_unicode_progress_id);
-+        }
-+        m_unicode_progress_id = GLib.Timeout.add(100, () => {
-+            m_unicode_progress_id = 0;
-+            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_candidate_panel();
-+            }
-+            return !m_loaded_unicode;
-+        });
-+    }
-+
-+
-+    private static string? check_unicode_point(string annotation) {
-+        string unicode_point = null;
-         // Add "0x" because uint64.ascii_strtoull() is not accessible
-         // and need to use uint64.parse()
-         var buff = new GLib.StringBuilder("0x");
-@@ -1114,33 +1164,31 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         for (int i = 0; i < annotation.char_count(); i++) {
-             unichar ch = annotation.get_char(i);
-             if (ch == 0)
--                return false;
-+                return null;
-             if (ch.isspace()) {
-                 unichar code = (unichar)uint64.parse(buff.str);
-                 buff.assign("0x");
-                 if (!code.validate())
--                    return false;
-+                    return null;
-                 retval.append(code.to_string());
-                 continue;
-             }
-             if (!ch.isxdigit())
--                return false;
-+                return null;
-             buff.append_unichar(ch);
-         }
-         unichar code = (unichar)uint64.parse(buff.str);
-         if (!code.validate())
--            return false;
-+            return null;
-         retval.append(code.to_string());
--        m_unicode_point = retval.str;
--        if (m_unicode_point == null)
--            return true;
--        IBus.Text text = new IBus.Text.from_string(m_unicode_point);
--        m_lookup_table.append_candidate(text);
--        return true;
-+        unicode_point = retval.str;
-+        if (unicode_point == null)
-+            return null;
-+        return unicode_point;
-     }
- 
- 
--    private GLib.SList<string>?
-+    private static GLib.SList<string>?
-     lookup_emojis_from_annotation(string annotation) {
-         GLib.SList<string>? total_emojis = null;
-         unowned GLib.SList<string>? sub_emojis = null;
-@@ -1221,19 +1269,19 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         return total_emojis;
-     }
- 
-+
-     private void update_candidate_window() {
--        string annotation = m_entry.get_text();
-+        string annotation = m_annotation;
-         if (annotation.length == 0) {
--            hide_candidate_panel();
-             m_backward = null;
-             return;
-         }
-+        m_lookup_table.clear();
-+        m_category_active_index = -1;
-         if (annotation.length > m_emoji_max_seq_len) {
--            hide_candidate_panel();
-             return;
-         }
--        // Call check_unicode_point() to get m_unicode_point
--        check_unicode_point();
-+        string? unicode_point = check_unicode_point(annotation);
-         GLib.SList<string>? total_emojis =
-             lookup_emojis_from_annotation(annotation);
-         if (total_emojis == null) {
-@@ -1246,18 +1294,75 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             annotation = annotation.down();
-             total_emojis = lookup_emojis_from_annotation(annotation);
-         }
--        if (total_emojis == null && m_unicode_point == null) {
--            hide_candidate_panel();
-+        if (total_emojis == null && unicode_point == null) {
-             return;
-         }
--        m_lookup_table.clear();
--        // Call check_unicode_point() to update m_lookup_table
--        check_unicode_point();
-+        if (unicode_point != null) {
-+            IBus.Text text = new IBus.Text.from_string(unicode_point);
-+            m_lookup_table.append_candidate(text);
-+        }
-         foreach (unowned string emoji in total_emojis) {
-             IBus.Text text = new IBus.Text.from_string(emoji);
-             m_lookup_table.append_candidate(text);
-         }
--        show_candidate_panel();
-+        m_candidate_panel_is_visible =
-+            (m_lookup_table.get_number_of_candidates() > 0) ? true : false;
-+        m_candidate_panel_mode = true;
-+    }
-+
-+
-+    private void update_category_list() {
-+        // Always update m_lookup_table even if the contents are same
-+        // because m_category_active_index needs to be kept after
-+        // bring back this API from show_emoji_for_category().
-+        reset_window_mode();
-+        m_lookup_table.clear();
-+        IBus.Text text;
-+        if (m_favorites.length > 0) {
-+            text = new IBus.Text.from_string(EMOJI_CATEGORY_FAVORITES);
-+            m_lookup_table.append_candidate(text);
-+        }
-+        GLib.List<unowned string> categories =
-+                m_category_to_emojis_dict.get_keys();
-+        // FIXME: How to cast GLib.CompareFunc<string> to strcmp?
-+        categories.sort((a, b) => {
-+            if (a == EMOJI_CATEGORY_OTHERS && b != EMOJI_CATEGORY_OTHERS)
-+                return 1;
-+            else if (a != EMOJI_CATEGORY_OTHERS && b == EMOJI_CATEGORY_OTHERS)
-+                return -1;
-+            return GLib.strcmp(_(a), _(b));
-+        });
-+        foreach (unowned string category in categories) {
-+            // "Others" category includes next unicode chars and fonts do not
-+            // support the base and varints yet.
-+            if (category == EMOJI_CATEGORY_OTHERS)
-+               continue;
-+            text = new IBus.Text.from_string(category);
-+            m_lookup_table.append_candidate(text);
-+        }
-+        if (m_unicode_block_list.length() > 0) {
-+            text = new IBus.Text.from_string(EMOJI_CATEGORY_UNICODE);
-+            m_lookup_table.append_candidate(text);
-+        }
-+        // Do not set m_category_active_index to 0 here so that
-+        // show_category_list() handles it.
-+    }
-+
-+
-+    private void update_unicode_blocks() {
-+        // Always update m_lookup_table even if the contents are same
-+        // because m_category_active_index needs to be kept after
-+        // bring back this API from show_emoji_for_category().
-+        reset_window_mode();
-+        m_lookup_table.clear();
-+        m_show_unicode = true;
-+        foreach (unowned IBus.UnicodeBlock block in m_unicode_block_list) {
-+            string name = block.get_name();
-+            IBus.Text text = new IBus.Text.from_string(name);
-+            m_lookup_table.append_candidate(text);
-+        }
-+        // Do not set m_category_active_index to 0 here so that
-+        // show_unicode_blocks() handles it.
-     }
- 
- 
-@@ -1283,27 +1388,27 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         uint page_size = m_lookup_table.get_page_size();
-         uint ncandidates = m_lookup_table.get_number_of_candidates();
-         uint cursor = m_lookup_table.get_cursor_pos();
--
-         uint page_start_pos = cursor / page_size * page_size;
-         uint page_end_pos = uint.min(page_start_pos + page_size, ncandidates);
-+        Gtk.Button? backward_button = null;
-         if (m_backward != null) {
--            string backward_desc =
--                    "%s (%u / %u)".printf(_(m_backward), cursor, ncandidates - 1);
-+            string backward_desc = _(m_backward);
-             EPaddedLabelBox label =
-                     new EPaddedLabelBox(backward_desc,
-                                         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) => {
-+            backward_button = new Gtk.Button();
-+            backward_button.add(label);
-+            backward_button.button_press_event.connect((w, e) => {
-                 // Bring back to emoji candidate panel in case
-                 // m_show_emoji_variant is enabled and shows variants.
--                if (m_backward_index >= 0 && m_backward != null)
-+                if (m_backward_index >= 0 && m_backward != null) {
-                     show_emoji_for_category(m_backward);
--                else
-+                    show_candidate_panel();
-+                } else {
-                     hide_candidate_panel();
-+                    show_all();
-+                }
-                 return true;
-             });
-         }
-@@ -1385,34 +1490,60 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         }
-         if (n > 0) {
-             m_candidate_panel_is_visible = true;
--            show_arrow_buttons();
--            m_vbox.add(grid);
--            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) {
--                show_emoji_description(data, text);
--                return;
-+            if (!m_is_up_side_down) {
-+                show_arrow_buttons();
-+                if (backward_button != null) {
-+                    m_vbox.add(backward_button);
-+                    backward_button.show_all();
-+                }
-+                m_vbox.add(grid);
-+                grid.show_all();
-+                show_description();
-+                if (!m_loaded_unicode)
-+                    show_unicode_progress_bar();
-             }
--            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 (m_is_up_side_down) {
-+                if (!m_loaded_unicode)
-+                    show_unicode_progress_bar();
-+                show_description();
-+                m_vbox.add(grid);
-+                grid.show_all();
-+                if (backward_button != null) {
-+                    m_vbox.add(backward_button);
-+                    backward_button.show_all();
-                 }
-+                show_arrow_buttons();
-             }
--            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_description() {
-+        uint cursor = m_lookup_table.get_cursor_pos();
-+        string text = m_lookup_table.get_candidate(cursor).text;
-+        unowned IBus.EmojiData? data = m_emoji_to_data_dict.lookup(text);
-+        if (data != null) {
-+            show_emoji_description(data, text);
-+            return;
-+        }
-+        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;
-+            }
-+        }
-+        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();
-@@ -1473,14 +1604,17 @@ public class IBusEmojier : Gtk.ApplicationWindow {
- 
- 
-     private void hide_candidate_panel() {
-+        hide();
-         m_enter_notify_enable = true;
--        m_candidate_panel_is_visible = false;
--        if (m_loop.is_running()) {
--            if (m_show_unicode)
--                show_unicode_blocks();
--            else
--                show_category_list();
--        }
-+        m_annotation = "";
-+        // Call remove_all_children() instead of show_category_list()
-+        // so that show_category_list do not remove children with
-+        // PageUp/PageDown.
-+        remove_all_children();
-+        if (m_show_unicode)
-+            update_unicode_blocks();
-+        else
-+            update_category_list();
-     }
- 
- 
-@@ -1498,20 +1632,34 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     }
- 
- 
--    private void candidate_panel_select_index(uint index) {
-+    private void candidate_panel_select_index(uint index,
-+                                              uint button) {
-+        if (button == BUTTON_CLOSE_BUTTON) {
-+            hide();
-+            if (m_candidate_panel_mode &&
-+                m_lookup_table.get_number_of_candidates() > 0) {
-+                // Call remove_all_children() instead of show_category_list()
-+                // so that show_category_list do not remove children with
-+                // PageUp/PageDown.
-+                remove_all_children();
-+            }
-+            m_result = "";
-+            return;
-+        }
-         string text = m_lookup_table.get_candidate(index).text;
-         unowned GLib.SList<string>? emojis =
-                 m_emoji_to_emoji_variants_dict.lookup(text);
-         if (m_show_emoji_variant && emojis != null &&
-             m_backward_index < 0) {
-             show_emoji_variants(emojis);
-+            show_all();
-         } else {
-             m_result = text;
--            m_loop.quit();
--            hide_candidate_panel();
-+            hide();
-         }
-     }
- 
-+
-     private void candidate_panel_cursor_down() {
-         enter_notify_disable_with_timer();
-         uint ncandidates = m_lookup_table.get_number_of_candidates();
-@@ -1523,7 +1671,6 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         } else {
-             m_lookup_table.set_cursor_pos(0);
-         }
--        show_candidate_panel();
-     }
- 
- 
-@@ -1541,7 +1688,6 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         } else {
-             m_lookup_table.set_cursor_pos(0);
-         }
--        show_candidate_panel();
-     }
- 
- 
-@@ -1558,7 +1704,9 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         return page_num;
-     }
- 
-+
-     private bool category_list_cursor_move(uint keyval) {
-+        return_val_if_fail (m_list_box != null, false);
-         GLib.List<weak Gtk.Widget> list = m_list_box.get_children();
-         int length = (int)list.length();
-         if (length == 0)
-@@ -1600,32 +1748,37 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         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);
-+        clamp_page ();
-         return true;
-     }
- 
- 
--    private bool key_press_cursor_horizontal(uint keyval,
--                                             uint modifiers) {
-+    public bool has_variants(uint index) {
-+        if (index >= m_lookup_table.get_number_of_candidates())
-+            return false;
-+        string text = m_lookup_table.get_candidate(index).text;
-+        unowned GLib.SList<string>? emojis =
-+                m_emoji_to_emoji_variants_dict.lookup(text);
-+        if (m_show_emoji_variant && emojis != null &&
-+            m_backward_index < 0) {
-+            show_emoji_variants(emojis);
-+            return true;
-+        }
-+        return false;
-+    }
-+
-+
-+    public bool key_press_cursor_horizontal(uint keyval,
-+                                            uint modifiers) {
-         assert (keyval == Gdk.Key.Left || keyval == Gdk.Key.Right);
- 
--        uint ncandidates = m_lookup_table.get_number_of_candidates();
--        if (m_candidate_panel_is_visible && ncandidates > 1) {
-+        if (m_candidate_panel_mode &&
-+            m_lookup_table.get_number_of_candidates() > 0) {
-             enter_notify_disable_with_timer();
-             if (keyval == Gdk.Key.Left)
-                 m_lookup_table.cursor_up();
-             else if (keyval == Gdk.Key.Right)
-                 m_lookup_table.cursor_down();
--            show_candidate_panel();
-         } else if (m_entry.get_text().length > 0) {
-             int step = 0;
-             if (keyval == Gdk.Key.Left)
-@@ -1650,8 +1803,8 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     }
- 
- 
--    private bool key_press_cursor_vertical(uint keyval,
--                                           uint modifiers) {
-+    public bool key_press_cursor_vertical(uint keyval,
-+                                          uint modifiers) {
-         assert (keyval == Gdk.Key.Down || keyval == Gdk.Key.Up ||
-                 keyval == Gdk.Key.Page_Down || keyval == Gdk.Key.Page_Up);
- 
-@@ -1661,8 +1814,8 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             else if (keyval == Gdk.Key.Up)
-                 keyval = Gdk.Key.Page_Up;
-         }
--        uint ncandidates = m_lookup_table.get_number_of_candidates();
--        if (m_candidate_panel_is_visible && ncandidates > 1) {
-+        if ((m_candidate_panel_is_visible || m_annotation.length > 0)
-+            && m_lookup_table.get_number_of_candidates() > 0) {
-             switch (keyval) {
-             case Gdk.Key.Down:
-                 candidate_panel_cursor_down();
-@@ -1673,12 +1826,10 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             case Gdk.Key.Page_Down:
-                 enter_notify_disable_with_timer();
-                 m_lookup_table.page_down();
--                show_candidate_panel();
-                 break;
-             case Gdk.Key.Page_Up:
-                 enter_notify_disable_with_timer();
-                 m_lookup_table.page_up();
--                show_candidate_panel();
-                 break;
-             }
-         } else {
-@@ -1688,19 +1839,18 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     }
- 
- 
--    private bool key_press_cursor_home_end(uint keyval,
--                                           uint modifiers) {
-+    public bool key_press_cursor_home_end(uint keyval,
-+                                          uint modifiers) {
-         assert (keyval == Gdk.Key.Home || keyval == Gdk.Key.End);
- 
-         uint ncandidates = m_lookup_table.get_number_of_candidates();
--        if (m_candidate_panel_is_visible && ncandidates > 1) {
-+        if (m_candidate_panel_mode && ncandidates > 0) {
-             enter_notify_disable_with_timer();
-             if (keyval == Gdk.Key.Home) {
-                 m_lookup_table.set_cursor_pos(0);
-             } else if (keyval == Gdk.Key.End) {
-                 m_lookup_table.set_cursor_pos(ncandidates - 1);
-             }
--            show_candidate_panel();
-             return true;
-         }
-         if (m_entry.get_text().length > 0) {
-@@ -1717,44 +1867,41 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-                             ? true : false);
-             return true;
-         }
--        if (!m_candidate_panel_is_visible)
--            return category_list_cursor_move(keyval);
--        return false;
-+        return category_list_cursor_move(keyval);
-     }
- 
- 
--    private bool key_press_escape() {
-+    public bool key_press_escape() {
-         if (m_show_unicode) {
--            if (m_candidate_panel_is_visible) {
--                m_candidate_panel_is_visible = false;
--                show_unicode_blocks();
--                return true;
--            } else {
-+            if (!m_candidate_panel_is_visible) {
-                 m_show_unicode = false;
-                 m_category_active_index = -1;
--                hide_candidate_panel();
--                return true;
-             }
-+            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) {
--            hide_candidate_panel();
--            return true;
--        } else if (m_entry.get_text().length == 0) {
--            m_loop.quit();
-+        } else if (m_candidate_panel_is_visible && m_backward != null) {
-             hide_candidate_panel();
-             return true;
-         }
--        m_entry.delete_text(0, -1);
--        return true;
-+        hide();
-+        if (m_candidate_panel_mode &&
-+            m_lookup_table.get_number_of_candidates() > 0) {
-+            // Call remove_all_children() instead of show_category_list()
-+            // so that show_category_list do not remove children with
-+            // PageUp/PageDown.
-+            remove_all_children();
-+        }
-+        return false;
-     }
- 
- 
--    private bool key_press_enter() {
-+    public bool key_press_enter() {
-         if (m_candidate_panel_is_visible) {
-             uint index = m_lookup_table.get_cursor_pos();
--            candidate_panel_select_index(index);
-+            return has_variants(index);
-         } else if (m_category_active_index >= 0) {
-             Gtk.ListBoxRow gtkrow = m_list_box.get_selected_row();
-             EBoxRow row = gtkrow as EBoxRow;
-@@ -1789,13 +1936,111 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     }
- 
- 
-+    private Gdk.Rectangle get_monitor_geometry() {
-+        Gdk.Rectangle monitor_area = { 0, };
-+
-+        // Use get_monitor_geometry() instead of get_monitor_area().
-+        // get_monitor_area() excludes docks, but the lookup window should be
-+        // shown over them.
-+#if VALA_0_34
-+        Gdk.Monitor monitor = Gdk.Display.get_default().get_monitor_at_point(
-+                m_cursor_location.x,
-+                m_cursor_location.y);
-+        monitor_area = monitor.get_geometry();
-+#else
-+        Gdk.Screen screen = Gdk.Screen.get_default();
-+        int monitor_num = screen.get_monitor_at_point(m_cursor_location.x,
-+                                                      m_cursor_location.y);
-+        screen.get_monitor_geometry(monitor_num, out monitor_area);
-+#endif
-+        return monitor_area;
-+    }
-+
-+
-+    private void adjust_window_position() {
-+        Gdk.Point cursor_right_bottom = {
-+                m_cursor_location.x + m_cursor_location.width,
-+                m_cursor_location.y + m_cursor_location.height
-+        };
-+
-+        Gtk.Allocation allocation;
-+        get_allocation(out allocation);
-+        Gdk.Point window_right_bottom = {
-+            cursor_right_bottom.x + allocation.width,
-+            cursor_right_bottom.y + allocation.height
-+        };
-+
-+        Gdk.Rectangle monitor_area = get_monitor_geometry();
-+        int monitor_right = monitor_area.x + monitor_area.width;
-+        int monitor_bottom = monitor_area.y + monitor_area.height;
-+
-+        int x, y;
-+        if (window_right_bottom.x > monitor_right)
-+            x = monitor_right - allocation.width;
-+        else
-+            x = cursor_right_bottom.x;
-+        if (x < 0)
-+            x = 0;
-+
-+        bool changed = false;
-+        if (window_right_bottom.y > monitor_bottom) {
-+            y = m_cursor_location.y - allocation.height;
-+            // Do not up side down in Wayland
-+            if (m_input_context_path == "") {
-+                changed = (m_is_up_side_down == false);
-+                m_is_up_side_down = true;
-+            } else {
-+                changed = (m_is_up_side_down == true);
-+                m_is_up_side_down = false;
-+            }
-+        } else {
-+            y = cursor_right_bottom.y;
-+            changed = (m_is_up_side_down == true);
-+            m_is_up_side_down = false;
-+        }
-+        if (y < 0)
-+            y = 0;
-+
-+        move(x, y);
-+        if (changed) {
-+            if (m_redraw_window_id > 0)
-+                GLib.Source.remove(m_redraw_window_id);
-+            m_redraw_window_id = GLib.Timeout.add(100, () => {
-+                m_redraw_window_id = 0;
-+                this.show_all();
-+                return false;
-+            });
-+        }
-+    }
-+
-+
-+#if 0
-+    private void check_action_variant_cb(Gtk.MenuItem item) {
-+        Gtk.CheckMenuItem check = item as Gtk.CheckMenuItem;
-+        m_show_emoji_variant = check.get_active();
-+        // Redraw emoji candidate panel for m_show_emoji_variant
-+        if (m_candidate_panel_is_visible) {
-+            // DOTO: queue_draw() does not effect at the real time.
-+            this.queue_draw();
-+        }
-+    }
-+#else
-     private void check_action_variant_cb(GLib.SimpleAction action,
-                                          GLib.Variant?     parameter) {
-         m_show_emoji_variant = !action.get_state().get_boolean();
-         action.set_state(new GLib.Variant.boolean(m_show_emoji_variant));
-         // Redraw emoji candidate panel for m_show_emoji_variant
--        if (m_candidate_panel_is_visible)
--            show_candidate_panel();
-+        if (m_candidate_panel_is_visible) {
-+            // DOTO: queue_draw() does not effect at the real time.
-+            this.queue_draw();
-+        }
-+    }
-+#endif
-+
-+
-+    private void action_close_cb(GLib.SimpleAction action,
-+                                 GLib.Variant?     parameter) {
-+        candidate_clicked(0, BUTTON_CLOSE_BUTTON, 0);
-     }
- 
- 
-@@ -1842,6 +2087,123 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     }
- 
- 
-+    public void set_annotation(string annotation) {
-+        m_annotation = annotation;
-+        remove_all_children();
-+        if (annotation.length > 0) {
-+            update_candidate_window();
-+        } else {
-+            if (m_show_unicode)
-+                update_unicode_blocks();
-+            else
-+                update_category_list();
-+        }
-+    }
-+
-+
-+    public IBus.LookupTable get_one_dimension_lookup_table() {
-+        var lookup_table = new IBus.LookupTable(EMOJI_GRID_PAGE, 0, true, true);
-+        uint i = 0;
-+        for (; i < m_lookup_table.get_number_of_candidates(); i++) {
-+            IBus.Text text = new IBus.Text.from_string("");
-+            text.copy(m_lookup_table.get_candidate(i));
-+            lookup_table.append_candidate(text);
-+        }
-+        if (i > 0)
-+            lookup_table.set_cursor_pos(m_lookup_table.get_cursor_pos());
-+        return lookup_table;
-+    }
-+
-+
-+    public uint get_number_of_candidates() {
-+        return m_lookup_table.get_number_of_candidates();
-+    }
-+
-+
-+    public uint get_cursor_pos() {
-+        return m_lookup_table.get_cursor_pos();
-+    }
-+
-+
-+    public void set_cursor_pos(uint cursor_pos) {
-+        m_lookup_table.set_cursor_pos(cursor_pos);
-+    }
-+
-+
-+    public string get_current_candidate() {
-+        // If category_list mode, do not show the category name on preedit.
-+        // If candidate_panel mode, the first space key does not show the
-+        // lookup table but the first candidate is avaiable on preedit.
-+        if (!m_candidate_panel_mode)
-+            return "";
-+        uint cursor = m_lookup_table.get_cursor_pos();
-+        return m_lookup_table.get_candidate(cursor).text;
-+    }
-+
-+
-+    public IBus.Text get_title_text() {
-+        var language = _(IBus.get_language_name(m_current_lang_id));
-+        uint ncandidates = this.get_number_of_candidates();
-+        string main_title = _("Emoji Choice");
-+        if (m_show_unicode)
-+            main_title = _("Unicode Choice");
-+        var text = new IBus.Text.from_string(
-+                "%s (%s) (%u / %u)".printf(
-+                        main_title,
-+                        language,
-+                        this.get_cursor_pos() + 1,
-+                        ncandidates));
-+        int char_count = text.text.char_count();
-+        int start_index = -1;
-+        for (int i = 0; i < char_count; i++) {
-+            if (text.text.utf8_offset(i).has_prefix(language)) {
-+                start_index = i;
-+                break;
-+            }
-+        }
-+        if (start_index >= 0) {
-+            var attr = new IBus.Attribute(
-+                    IBus.AttrType.FOREGROUND,
-+                    0x808080,
-+                    start_index,
-+                    start_index + language.char_count());
-+            var attrs = new IBus.AttrList();
-+            attrs.append(attr);
-+            text.set_attributes(attrs);
-+        }
-+        return text;
-+    }
-+
-+
-+#if 0
-+    public GLib.SList<string>? get_candidates() {
-+        if (m_annotation.length == 0) {
-+            return null;
-+        }
-+        if (m_annotation.length > m_emoji_max_seq_len) {
-+            return null;
-+        }
-+        string? unicode_point = check_unicode_point(m_annotation);
-+        GLib.SList<string>? total_emojis =
-+            lookup_emojis_from_annotation(m_annotation);
-+        if (total_emojis == null) {
-+            /* Users can type title strings against lower case.
-+             * E.g. "Smile" against "smile"
-+             * But the dictionary has the case sensitive annotations.
-+             * E.g. ":D" and ":q"
-+             * So need to call lookup_emojis_from_annotation() twice.
-+             */
-+            string lower_annotation = m_annotation.down();
-+            total_emojis = lookup_emojis_from_annotation(lower_annotation);
-+        }
-+        if (unicode_point != null)
-+            total_emojis.prepend(unicode_point);
-+        return total_emojis;
-+    }
-+#endif
-+
-+
-+#if 0
-     public string run(string    input_context_path,
-                       Gdk.Event event) {
-         assert (m_loop == null);
-@@ -1915,12 +2277,34 @@ public class IBusEmojier : Gtk.ApplicationWindow {
- 
-         return m_result;
-     }
-+#endif
- 
- 
-     /* override virtual functions */
--    public override void show() {
--        base.show();
--        set_focus_visible(true);
-+    public override void show_all() {
-+        base.show_all();
-+        if (m_candidate_panel_mode)
-+            show_candidate_panel();
-+        else if (m_show_unicode)
-+            show_unicode_blocks();
-+        else
-+            show_category_list();
-+    }
-+
-+
-+    public override void hide() {
-+        base.hide();
-+        m_candidate_panel_is_visible = false;
-+        // m_candidate_panel_mode is not false in when you type something
-+        // during enabling the candidate panel.
-+        if (m_redraw_window_id > 0) {
-+            GLib.Source.remove(m_redraw_window_id);
-+            m_redraw_window_id = 0;
-+        }
-+        if (m_unicode_progress_id > 0) {
-+            GLib.Source.remove(m_unicode_progress_id);
-+            m_unicode_progress_id = 0;
-+        }
-     }
- 
- 
-@@ -1935,11 +2319,16 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         switch (keyval) {
-         case Gdk.Key.Escape:
-             if (key_press_escape())
--                return true;
--            break;
-+                show_all();
-+            return true;
-         case Gdk.Key.Return:
-         case Gdk.Key.KP_Enter:
--            key_press_enter();
-+            if (key_press_enter()) {
-+                show_all();
-+            } else {
-+                m_result = get_current_candidate();
-+                hide();
-+            }
-             return true;
-         case Gdk.Key.BackSpace:
-             if (m_entry.get_text().length > 0) {
-@@ -1977,42 +2366,49 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             }
-             else {
-                 category_list_cursor_move(Gdk.Key.Down);
-+                show_all();
-             }
-             return true;
-         case Gdk.Key.Right:
-         case Gdk.Key.KP_Right:
-             key_press_cursor_horizontal(Gdk.Key.Right, modifiers);
-+            show_all();
-             return true;
-         case Gdk.Key.Left:
-         case Gdk.Key.KP_Left:
-             key_press_cursor_horizontal(Gdk.Key.Left, modifiers);
-+            show_all();
-             return true;
-         case Gdk.Key.Down:
-         case Gdk.Key.KP_Down:
-             key_press_cursor_vertical(Gdk.Key.Down, modifiers);
-+            show_all();
-             return true;
-         case Gdk.Key.Up:
-         case Gdk.Key.KP_Up:
-             key_press_cursor_vertical(Gdk.Key.Up, modifiers);
-+            show_all();
-             return true;
-         case Gdk.Key.Page_Down:
-         case Gdk.Key.KP_Page_Down:
-             key_press_cursor_vertical(Gdk.Key.Page_Down, modifiers);
-+            show_all();
-             return true;
-         case Gdk.Key.Page_Up:
-         case Gdk.Key.KP_Page_Up:
-             key_press_cursor_vertical(Gdk.Key.Page_Up, modifiers);
-+            show_all();
-             return true;
-         case Gdk.Key.Home:
-         case Gdk.Key.KP_Home:
--            if (key_press_cursor_home_end(Gdk.Key.Home, modifiers))
--                return true;
--            break;
-+            key_press_cursor_home_end(Gdk.Key.Home, modifiers);
-+            show_all();
-+            return true;
-         case Gdk.Key.End:
-         case Gdk.Key.KP_End:
--            if (key_press_cursor_home_end(Gdk.Key.End, modifiers))
--                return true;
--            break;
-+            key_press_cursor_home_end(Gdk.Key.End, modifiers);
-+            show_all();
-+            return true;
-         case Gdk.Key.Insert:
-         case Gdk.Key.KP_Insert:
-             GLib.Signal.emit_by_name(m_entry, "toggle-overwrite");
-@@ -2023,26 +2419,30 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             switch (keyval) {
-             case Gdk.Key.f:
-                 key_press_cursor_horizontal(Gdk.Key.Right, modifiers);
-+                show_all();
-                 return true;
-             case Gdk.Key.b:
-                 key_press_cursor_horizontal(Gdk.Key.Left, modifiers);
-+                show_all();
-                 return true;
-             case Gdk.Key.n:
-             case Gdk.Key.N:
-                 key_press_cursor_vertical(Gdk.Key.Down, modifiers);
-+                show_all();
-                 return true;
-             case Gdk.Key.p:
-             case Gdk.Key.P:
-                 key_press_cursor_vertical(Gdk.Key.Up, modifiers);
-+                show_all();
-                 return true;
-             case Gdk.Key.h:
--                if (key_press_cursor_home_end(Gdk.Key.Home, modifiers))
--                    return true;
--                break;
-+                key_press_cursor_home_end(Gdk.Key.Home, modifiers);
-+                show_all();
-+                return true;
-             case Gdk.Key.e:
--                if (key_press_cursor_home_end(Gdk.Key.End, modifiers))
--                    return true;
--                break;
-+                key_press_cursor_home_end(Gdk.Key.End, modifiers);
-+                show_all();
-+                return true;
-             case Gdk.Key.u:
-                 if (m_entry.get_text().length > 0) {
-                     GLib.Signal.emit_by_name(m_entry,
-@@ -2103,14 +2503,41 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     }
- 
- 
-+    public void set_input_context_path(string input_context_path) {
-+        m_input_context_path = input_context_path;
-+        if (input_context_path == "") {
-+            m_warning_message = _("" +
-+                "Failed to get the current text application. " +
-+                "Please re-focus your application. E.g. Press Esc key " +
-+                "several times to release the emoji typing mode, " +
-+                "click your desktop and click your text application again."
-+            );
-+        } else {
-+            m_warning_message = "";
-+        }
-+    }
-+
-+
-     public string get_selected_string() {
-         return m_result;
-     }
- 
- 
-+    private void reset_window_mode() {
-+        m_backward_index = -1;
-+        m_backward = null;
-+        m_candidate_panel_is_visible = false;
-+        m_candidate_panel_mode = false;
-+        // Do not clear m_lookup_table to work with space key later.
-+    }
-+
-+
-     public void reset() {
-+        reset_window_mode();
-         m_input_context_path = "";
-         m_result = null;
-+        m_category_active_index = -1;
-+        m_show_unicode = false;
-     }
- 
- 
-@@ -2145,6 +2572,23 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     }
- 
- 
-+    public void set_cursor_location(int x,
-+                                    int y,
-+                                    int width,
-+                                    int height) {
-+        Gdk.Rectangle location = Gdk.Rectangle(){
-+            x = x, y = y, width = width, height = height };
-+        if (m_cursor_location == location)
-+            return;
-+        m_cursor_location = location;
-+    }
-+
-+
-+    public bool is_candidate_panel_mode() {
-+        return m_candidate_panel_mode;
-+    }
-+
-+
-     public static bool has_loaded_emoji_dict() {
-         if (m_emoji_to_data_dict == null)
-             return false;
-@@ -2165,6 +2609,10 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     }
- 
- 
-+    public static string get_annotation_lang() {
-+        return m_current_lang_id;
-+    }
-+
-     public static void set_emoji_font(string? emoji_font) {
-         return_if_fail(emoji_font != null && emoji_font != "");
-         Pango.FontDescription font_desc =
-@@ -2182,18 +2630,21 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         m_has_partial_match = has_partial_match;
-     }
- 
-+
-     public static void set_partial_match_length(int length) {
-         if (length < 1)
-             return;
-         m_partial_match_length = length;
-     }
- 
-+
-     public static void set_partial_match_condition(int condition) {
-         if (condition < 0)
-             return;
-         m_partial_match_condition = condition;
-     }
- 
-+
-     public static void set_favorites(string[]? unowned_favorites,
-                                      string[]? unowned_favorite_annotations) {
-         m_favorites = {};
-diff --git a/ui/gtk3/emojierapp.vala b/ui/gtk3/emojierapp.vala
-index 9506a945..787d448f 100644
---- a/ui/gtk3/emojierapp.vala
-+++ b/ui/gtk3/emojierapp.vala
-@@ -28,8 +28,9 @@ int partial_match_condition = -1;
- 
- public class EmojiApplication : Gtk.Application {
-     private IBusEmojier? m_emojier;
--    GLib.Settings m_settings_emoji =
-+    private GLib.Settings m_settings_emoji =
-             new GLib.Settings("org.freedesktop.ibus.panel.emoji");
-+    private ApplicationCommandLine? m_command_line = null;
- 
- 
-     private EmojiApplication() {
-@@ -40,25 +41,39 @@ public class EmojiApplication : Gtk.Application {
- 
- 
-     private void show_dialog(ApplicationCommandLine command_line) {
--        m_emojier = new IBusEmojier();
--        // For title handling in gnome-shell
--        add_window(m_emojier);
--        Gdk.Event event = Gtk.get_current_event();
--        // Plasma and GNOME3 desktop returns null event
--        if (event == null) {
--            event = new Gdk.Event(Gdk.EventType.KEY_PRESS);
--            event.key.time = Gdk.CURRENT_TIME;
--            // event.get_seat() refers event.any.window
--            event.key.window = Gdk.get_default_root_window();
--            event.key.window.ref();
-+        m_command_line = command_line;
-+        m_emojier.reset();
-+        m_emojier.set_annotation("");
-+        m_emojier.show_all();
-+    }
-+
-+
-+    public void candidate_clicked_lookup_table(uint index,
-+                                               uint button,
-+                                               uint state) {
-+        if (m_command_line == null)
-+            return;
-+        if (button == IBusEmojier.BUTTON_CLOSE_BUTTON) {
-+            m_emojier.hide();
-+            m_command_line.print("%s\n", _("Canceled to choose an emoji."));
-+            m_command_line = null;
-+            return;
-         }
--        string emoji = m_emojier.run("", event);
--        remove_window(m_emojier);
--        if (emoji == null) {
--            m_emojier = null;
--            command_line.print("%s\n", _("Canceled to choose an emoji."));
-+        if (m_emojier == null)
-+            return;
-+        bool show_candidate = false;
-+        uint ncandidates = m_emojier.get_number_of_candidates();
-+        if (ncandidates > 0 && ncandidates >= index) {
-+            m_emojier.set_cursor_pos(index);
-+            show_candidate = m_emojier.has_variants(index);
-+        } else {
-+            return;
-+        }
-+        if (show_candidate) {
-             return;
-         }
-+        string emoji = m_emojier.get_current_candidate();
-+        m_emojier.hide();
-         Gtk.Clipboard clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD);
-         clipboard.set_text(emoji, -1);
-         clipboard.store();
-@@ -75,9 +90,8 @@ public class EmojiApplication : Gtk.Application {
-             emojier_favorites += emoji;
-             m_settings_emoji.set_strv("favorites", emojier_favorites);
-         }
--
--        m_emojier = null;
--        command_line.print("%s\n", _("Copied an emoji to your clipboard."));
-+        m_command_line.print("%s\n", _("Copied an emoji to your clipboard."));
-+        m_command_line = null;
-     }
- 
- 
-@@ -88,7 +102,7 @@ public class EmojiApplication : Gtk.Application {
-     }
- 
- 
--    private int _command_line (ApplicationCommandLine command_line) {
-+    private int _command_line(ApplicationCommandLine command_line) {
-         // Set default font size
-         IBusEmojier.set_emoji_font(m_settings_emoji.get_string("font"));
- 
-@@ -181,13 +195,22 @@ public class EmojiApplication : Gtk.Application {
- 
-         IBusEmojier.load_unicode_dict();
- 
-+        if (m_emojier == null) {
-+            m_emojier = new IBusEmojier();
-+            // For title handling in gnome-shell
-+            add_window(m_emojier);
-+            m_emojier.candidate_clicked.connect((i, b, s) => {
-+                candidate_clicked_lookup_table(i, b, s);
-+            });
-+        }
-+
-         activate_dialog(command_line);
- 
-         return Posix.EXIT_SUCCESS;
-     }
- 
- 
--    public override int command_line (ApplicationCommandLine command_line) {
-+    public override int command_line(ApplicationCommandLine command_line) {
-         // keep the application running until we are done with this commandline
-         this.hold();
-         int result = _command_line(command_line);
-@@ -196,6 +219,13 @@ public class EmojiApplication : Gtk.Application {
-     }
- 
- 
-+    public override void shutdown() {
-+        base.shutdown();
-+        remove_window(m_emojier);
-+        m_emojier = null;
-+    }
-+
-+
-     public static int main (string[] args) {
-         GLib.Intl.bindtextdomain(Config.GETTEXT_PACKAGE,
-                                  Config.GLIB_LOCALE_DIR);
-diff --git a/ui/gtk3/extension.vala b/ui/gtk3/extension.vala
-index 7d6d76e7..c729fd7e 100644
---- a/ui/gtk3/extension.vala
-+++ b/ui/gtk3/extension.vala
-@@ -50,20 +50,20 @@ class ExtensionGtk : Gtk.Application {
-                                     "org.freedesktop.DBus",
-                                     "NameAcquired",
-                                     "/org/freedesktop/DBus",
--                                    IBus.SERVICE_PANEL_EXTENSION,
-+                                    IBus.SERVICE_PANEL_EXTENSION_EMOJI,
-                                     DBusSignalFlags.NONE,
-                                     bus_name_acquired_cb);
-         connection.signal_subscribe("org.freedesktop.DBus",
-                                     "org.freedesktop.DBus",
-                                     "NameLost",
-                                     "/org/freedesktop/DBus",
--                                    IBus.SERVICE_PANEL_EXTENSION,
-+                                    IBus.SERVICE_PANEL_EXTENSION_EMOJI,
-                                     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);
-+        m_bus.request_name(IBus.SERVICE_PANEL_EXTENSION_EMOJI, flags);
-     }
- 
- 
-diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala
-index d9238c89..4c3b00ca 100644
---- a/ui/gtk3/panel.vala
-+++ b/ui/gtk3/panel.vala
-@@ -1148,26 +1148,15 @@ class Panel : IBus.PanelService {
- #if EMOJI_DICT
-             item = new Gtk.MenuItem.with_label(_("Emoji Choice"));
-             item.activate.connect((i) => {
--                Gdk.Event event = Gtk.get_current_event();
--                if (event == null) {
--                    event = new Gdk.Event(Gdk.EventType.KEY_PRESS);
--                    event.key.time = Gdk.CURRENT_TIME;
--                    // event.get_seat() refers event.any.window
--                    event.key.window = Gdk.get_default_root_window();
--                    event.key.window.ref();
--                }
--                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())
-+                IBus.ExtensionEvent event = new IBus.ExtensionEvent(
-+                        "name", "emoji", "is-enabled", true,
-+                        "params", "category-list");
-+                /* new GLib.Variant("(sv)", "emoji", event.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.
-+                 * the purpose to IBus.ExtensionEvent above.
-                  */
--                panel_extension(xevent.serialize_object());
-+                panel_extension(event);
-             });
-             m_sys_menu.append(item);
- #endif
-diff --git a/ui/gtk3/panelbinding.vala b/ui/gtk3/panelbinding.vala
-index 581f721e..52b78c17 100644
---- a/ui/gtk3/panelbinding.vala
-+++ b/ui/gtk3/panelbinding.vala
-@@ -21,7 +21,193 @@
-  * USA
-  */
- 
-+class Preedit : Gtk.Window {
-+    private Gtk.Label m_extension_preedit_text;
-+    private Gtk.Label m_extension_preedit_emoji;
-+    private IBus.Text? m_engine_preedit_text;
-+    private bool m_engine_preedit_text_show;
-+    private uint m_engine_preedit_cursor_pos;
-+    private string m_prefix = "@";
-+    private bool m_is_shown = true;
-+
-+
-+    public Preedit() {
-+        GLib.Object(
-+            name : "IBusPreedit",
-+            type: Gtk.WindowType.POPUP
-+        );
-+        m_extension_preedit_text  = new Gtk.Label("");
-+        m_extension_preedit_emoji  = new Gtk.Label("");
-+    }
-+
-+
-+    public new void hide() {
-+        reset();
-+        base.hide();
-+        m_is_shown = false;
-+    }
-+
-+
-+    public bool is_shown() {
-+        return m_is_shown;
-+    }
-+
-+
-+    public void reset() {
-+        set_emoji("");
-+        set_text("");
-+        resize(1, 1);
-+        m_is_shown = true;
-+    }
-+
-+    public void append_text(string text) {
-+        if (text.length == 0)
-+            return;
-+        string total = m_extension_preedit_text.get_text();
-+        total += text;
-+        m_extension_preedit_text.set_text(total);
-+    }
-+
-+
-+    public string get_text() {
-+        return m_extension_preedit_text.get_text();
-+    }
-+
-+
-+    public void set_text(string text) {
-+        m_extension_preedit_text.set_text(text);
-+    }
-+
-+
-+    public string get_emoji() {
-+        return m_extension_preedit_emoji.get_text();
-+    }
-+
-+
-+    public void set_emoji(string text) {
-+        m_extension_preedit_emoji.set_text(text);
-+    }
-+
-+
-+    public bool backspace() {
-+        string total = m_extension_preedit_emoji.get_text();
-+        if (total.length > 0) {
-+            m_extension_preedit_emoji.set_text("");
-+            resize(1, 1);
-+            return false;
-+        }
-+        total = m_extension_preedit_text.get_text();
-+        int char_count = total.char_count();
-+        if (char_count == 0)
-+            return true;
-+        total = total[0:total.index_of_nth_char(char_count - 1)];
-+        resize(1, 1);
-+        m_extension_preedit_text.set_text(total);
-+        if (total.length == 0)
-+            resize(1, 1);
-+        return true;
-+    }
-+
-+
-+    private string get_extension_text () {
-+        string extension_text = m_extension_preedit_emoji.get_text();
-+        if (extension_text.length == 0)
-+            extension_text = m_extension_preedit_text.get_text();
-+        return m_prefix + extension_text;
-+    }
-+
-+
-+    private void set_preedit_color(IBus.Text text,
-+                                   uint start_index,
-+                                   uint end_index) {
-+        text.append_attribute(IBus.AttrType.UNDERLINE,
-+                              IBus.AttrUnderline.SINGLE,
-+                              start_index, (int)end_index);
-+    }
-+
-+
-+    public IBus.Text get_engine_preedit_text() {
-+        string extension_text = get_extension_text();
-+        uint char_count = extension_text.char_count();
-+        IBus.Text retval;
-+        if (m_engine_preedit_text == null || !m_engine_preedit_text_show) {
-+            retval = new IBus.Text.from_string(extension_text);
-+            set_preedit_color(retval, 0, char_count);
-+            return retval;
-+        }
-+        retval = new IBus.Text.from_string(
-+                extension_text + m_engine_preedit_text.get_text());
-+        set_preedit_color(retval, 0, char_count);
-+
-+        unowned IBus.AttrList attrs = m_engine_preedit_text.get_attributes();
-+
-+        if (attrs == null)
-+            return retval;
-+
-+        int i = 0;
-+        while (true) {
-+            IBus.Attribute attr = attrs.get(i++);
-+            if (attr == null)
-+                break;
-+            long start_index = attr.start_index;
-+            long end_index = attr.end_index;
-+            if (start_index < 0)
-+                start_index = 0;
-+            if (end_index < 0)
-+                end_index = m_engine_preedit_text.get_length();
-+            retval.append_attribute(attr.type, attr.value,
-+                                    char_count + (uint)start_index,
-+                                    (int)char_count + (int)end_index);
-+        }
-+        return retval;
-+    }
-+
-+
-+    public void set_engine_preedit_text(IBus.Text? text) {
-+        m_engine_preedit_text = text;
-+    }
-+
-+
-+    public void show_engine_preedit_text() {
-+        m_engine_preedit_text_show = true;
-+    }
-+
-+
-+    public void hide_engine_preedit_text() {
-+        m_engine_preedit_text_show = false;
-+    }
-+
-+
-+    public uint get_engine_preedit_cursor_pos() {
-+        return get_extension_text().char_count() + m_engine_preedit_cursor_pos;
-+    }
-+
-+
-+    public void set_engine_preedit_cursor_pos(uint cursor_pos) {
-+        m_engine_preedit_cursor_pos = cursor_pos;
-+    }
-+
-+
-+    public IBus.Text get_commit_text() {
-+        string extension_text = m_extension_preedit_emoji.get_text();
-+        if (extension_text.length == 0)
-+            extension_text = m_extension_preedit_text.get_text();
-+        return new IBus.Text.from_string(extension_text);
-+    }
-+
-+
-+    public void set_extension_name(string extension_name) {
-+        if (extension_name.length == 0)
-+            m_prefix = "@";
-+        else
-+            m_prefix = extension_name[0:1];
-+    }
-+}
-+
-+
- class PanelBinding : IBus.PanelService {
-+    private bool m_is_wayland;
-+    private bool m_wayland_lookup_table_is_visible;
-     private IBus.Bus m_bus;
-     private Gtk.Application m_application;
-     private GLib.Settings m_settings_panel = null;
-@@ -38,18 +224,26 @@ class PanelBinding : IBus.PanelService {
-     private bool m_loaded_emoji = false;
-     private bool m_load_unicode_at_startup;
-     private bool m_loaded_unicode = false;
-+    private bool m_enable_extension;
-+    private string m_extension_name = "";
-+    private Preedit m_preedit;
- 
-     public PanelBinding(IBus.Bus bus,
-                         Gtk.Application application) {
-         GLib.assert(bus.is_connected());
-         // Chain up base class constructor
-         GLib.Object(connection : bus.get_connection(),
--                    object_path : IBus.PATH_PANEL_EXTENSION);
-+                    object_path : IBus.PATH_PANEL_EXTENSION_EMOJI);
-+
-+        Type instance_type = Gdk.Display.get_default().get_type();
-+        Type wayland_type = typeof(GdkWayland.Display);
-+        m_is_wayland = instance_type.is_a(wayland_type);
- 
-         m_bus = bus;
-         m_application = application;
- 
-         init_settings();
-+        m_preedit = new Preedit();
-     }
- 
- 
-@@ -69,12 +263,20 @@ class PanelBinding : IBus.PanelService {
-                                               ref m_css_provider);
-         });
- 
-+        m_settings_emoji.changed["unicode-hotkey"].connect((key) => {
-+                set_emoji_hotkey();
-+        });
-+
-         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["hotkey"].connect((key) => {
-+                set_emoji_hotkey();
-+        });
-+
-         m_settings_emoji.changed["favorites"].connect((key) => {
-                 set_emoji_favorites();
-         });
-@@ -109,6 +311,54 @@ class PanelBinding : IBus.PanelService {
-     }
- 
- 
-+    private unowned
-+    IBus.ProcessKeyEventData? parse_accelerator(string accelerator) {
-+        IBus.ProcessKeyEventData key = {};
-+        uint keysym = 0;
-+        IBus.ModifierType modifiers = 0;
-+        IBus.accelerator_parse(accelerator,
-+                out keysym, out modifiers);
-+        if (keysym == 0U && modifiers == 0) {
-+            warning("Failed to parse shortcut key '%s'".printf(accelerator));
-+            return null;
-+        }
-+        if ((modifiers & IBus.ModifierType.SUPER_MASK) != 0) {
-+            modifiers ^= IBus.ModifierType.SUPER_MASK;
-+            modifiers |= IBus.ModifierType.MOD4_MASK;
-+        }
-+        key.keyval = keysym;
-+        key.state = modifiers;
-+        return key;
-+    }
-+
-+
-+    private void set_emoji_hotkey() {
-+        IBus.ProcessKeyEventData[] emoji_keys = {};
-+        IBus.ProcessKeyEventData key;
-+        string[] accelerators = m_settings_emoji.get_strv("hotkey");
-+        foreach (var accelerator in accelerators) {
-+            key = parse_accelerator(accelerator);
-+            emoji_keys += key;
-+        }
-+
-+        /* Since {} is not allocated, parse_accelerator() should be unowned. */
-+        key = {};
-+        emoji_keys += key;
-+
-+        IBus.ProcessKeyEventData[] unicode_keys = {};
-+        accelerators = m_settings_emoji.get_strv("unicode-hotkey");
-+        foreach (var accelerator in accelerators) {
-+            key = parse_accelerator(accelerator);
-+            unicode_keys += key;
-+        }
-+        key = {};
-+        unicode_keys += key;
-+
-+        panel_extension_register_keys("emoji", emoji_keys,
-+                                      "unicode", unicode_keys);
-+    }
-+
-+
-     private void set_emoji_favorites() {
-         m_emojier_favorites = m_settings_emoji.get_strv("favorites");
-         IBusEmojier.set_favorites(
-@@ -159,6 +409,7 @@ class PanelBinding : IBus.PanelService {
- 
-     public void load_settings() {
- 
-+        set_emoji_hotkey();
-         set_load_emoji_at_startup();
-         set_load_unicode_at_startup();
-         BindingCommon.set_custom_font(m_settings_panel,
-@@ -181,36 +432,37 @@ class PanelBinding : IBus.PanelService {
-             GLib.Source.remove(m_emojier_set_emoji_lang_id);
-             m_emojier_set_emoji_lang_id = 0;
-         }
--        m_application = null;
--    }
--
--
--    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();
--        // For title handling in gnome-shell
--        m_application.add_window(m_emojier);
--        string emoji = m_emojier.run(m_real_current_context_path, event);
--        m_application.remove_window(m_emojier);
--        if (emoji == null) {
-+        if (m_emojier != null) {
-+            m_application.remove_window(m_emojier);
-             m_emojier = null;
--            return;
-         }
--        this.emojier_focus_commit();
-+        m_application = null;
-     }
- 
- 
--    private void handle_emoji_typing(Gdk.Event event) {
--        if (m_emojier != null && m_emojier.is_running()) {
--            m_emojier.present_centralize(event);
-+    private void commit_text_update_favorites(IBus.Text text) {
-+        commit_text(text);
-+        IBus.ExtensionEvent event = new IBus.ExtensionEvent(
-+                    "name", m_extension_name,
-+                    "is-enabled", false,
-+                    "is-extension", true);
-+        panel_extension(event);
-+        string committed_string = text.text;
-+        string preedit_string = m_preedit.get_text();
-+        m_preedit.hide();
-+        if (preedit_string == committed_string)
-             return;
-+        bool has_favorite = false;
-+        foreach (unowned string favorite in m_emojier_favorites) {
-+            if (favorite == committed_string) {
-+                has_favorite = true;
-+                break;
-+            }
-+        }
-+        if (!has_favorite) {
-+            m_emojier_favorites += committed_string;
-+            m_settings_emoji.set_strv("favorites", m_emojier_favorites);
-         }
--        show_emojier(event);
-     }
- 
- 
-@@ -223,19 +475,8 @@ class PanelBinding : IBus.PanelService {
-             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);
--            }
-+            commit_text_update_favorites(text);
-+            m_emojier.reset();
-             return true;
-         }
- 
-@@ -249,8 +490,7 @@ class PanelBinding : IBus.PanelService {
-         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()) {
-+            prev_context_path != "") {
-             var context = GLib.MainContext.default();
-             if (m_emojier_focus_commit_text_id > 0 &&
-                 context.find_source_by_id(m_emojier_focus_commit_text_id)
-@@ -277,6 +517,243 @@ class PanelBinding : IBus.PanelService {
-     }
- 
- 
-+    private bool key_press_escape() {
-+        if (is_emoji_lookup_table()) {
-+            bool show_candidate = m_emojier.key_press_escape();
-+            convert_preedit_text();
-+            return show_candidate;
-+        }
-+        if (m_preedit.get_emoji() != "") {
-+            m_preedit.set_emoji("");
-+            string annotation = m_preedit.get_text();
-+            m_emojier.set_annotation(annotation);
-+            return false;
-+        }
-+        m_enable_extension = false;
-+        hide_emoji_lookup_table();
-+        m_preedit.hide();
-+        IBus.ExtensionEvent event = new IBus.ExtensionEvent(
-+                "name", m_extension_name,
-+                "is-enabled", false,
-+                "is-extension", true);
-+        panel_extension(event);
-+        return false;
-+    }
-+
-+
-+    private bool key_press_enter() {
-+        if (m_extension_name != "unicode" && is_emoji_lookup_table()) {
-+            // Check if variats exist
-+            if (m_emojier.key_press_enter())
-+                return true;
-+        }
-+        IBus.Text text = m_preedit.get_commit_text();
-+        commit_text_update_favorites(text);
-+        return false;
-+    }
-+
-+
-+    private void convert_preedit_text() {
-+        if (m_emojier.get_number_of_candidates() > 0)
-+            m_preedit.set_emoji(m_emojier.get_current_candidate());
-+        else
-+            m_preedit.set_emoji("");
-+    }
-+
-+
-+    private bool key_press_space() {
-+        bool show_candidate = false;
-+        if (m_preedit.get_emoji() != "") {
-+            m_emojier.key_press_cursor_horizontal(Gdk.Key.Right, 0);
-+            show_candidate = true;
-+        } else {
-+            string annotation = m_preedit.get_text();
-+            if (annotation.length == 0) {
-+                show_candidate = true;
-+                if (is_emoji_lookup_table())
-+                    m_emojier.key_press_cursor_horizontal(Gdk.Key.Right, 0);
-+            } else {
-+                m_emojier.set_annotation(annotation);
-+            }
-+        }
-+        convert_preedit_text();
-+        return show_candidate;
-+    }
-+
-+
-+    private bool key_press_cursor_horizontal(uint keyval,
-+                                             uint modifiers) {
-+        if (is_emoji_lookup_table()) {
-+            m_emojier.key_press_cursor_horizontal(keyval, modifiers);
-+            convert_preedit_text();
-+            return true;
-+        }
-+        return false;
-+    }
-+
-+
-+    private bool key_press_cursor_vertical(uint keyval,
-+                                           uint modifiers) {
-+        if (is_emoji_lookup_table()) {
-+            m_emojier.key_press_cursor_vertical(keyval, modifiers);
-+            convert_preedit_text();
-+            return true;
-+        }
-+        return false;
-+    }
-+
-+
-+    private bool key_press_cursor_home_end(uint keyval,
-+                                           uint modifiers) {
-+        if (is_emoji_lookup_table()) {
-+            m_emojier.key_press_cursor_home_end(keyval, modifiers);
-+            convert_preedit_text();
-+            return true;
-+        }
-+        return false;
-+    }
-+
-+
-+    private bool key_press_control_keyval(uint keyval,
-+                                          uint modifiers) {
-+        bool show_candidate = false;
-+        switch(keyval) {
-+        case Gdk.Key.f:
-+            show_candidate = key_press_cursor_horizontal(Gdk.Key.Right,
-+                                                         modifiers);
-+            break;
-+        case Gdk.Key.b:
-+            show_candidate = key_press_cursor_horizontal(Gdk.Key.Left,
-+                                                         modifiers);
-+            break;
-+        case Gdk.Key.n:
-+        case Gdk.Key.N:
-+            show_candidate = key_press_cursor_vertical(Gdk.Key.Down, modifiers);
-+            break;
-+        case Gdk.Key.p:
-+        case Gdk.Key.P:
-+            show_candidate = key_press_cursor_vertical(Gdk.Key.Up, modifiers);
-+            break;
-+        case Gdk.Key.h:
-+            show_candidate = key_press_cursor_home_end(Gdk.Key.Home, modifiers);
-+            break;
-+        case Gdk.Key.e:
-+            show_candidate = key_press_cursor_home_end(Gdk.Key.End, modifiers);
-+            break;
-+        case Gdk.Key.u:
-+            m_preedit.reset();
-+            m_emojier.set_annotation("");
-+            hide_emoji_lookup_table();
-+            break;
-+        case Gdk.Key.C:
-+        case Gdk.Key.c:
-+            if ((modifiers & Gdk.ModifierType.SHIFT_MASK) != 0) {
-+                if (!m_is_wayland && m_emojier != null &&
-+                    m_emojier.get_number_of_candidates() > 0) {
-+                    var text = m_emojier.get_current_candidate();
-+                    Gtk.Clipboard clipboard =
-+                            Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD);
-+                    clipboard.set_text(text, -1);
-+                    clipboard.store();
-+                }
-+                show_candidate = is_emoji_lookup_table();
-+            }
-+            break;
-+        default:
-+            show_candidate = is_emoji_lookup_table();
-+            break;
-+        }
-+        return show_candidate;
-+    }
-+
-+
-+    private void hide_wayland_lookup_table() {
-+        m_wayland_lookup_table_is_visible = false;
-+        var text = new IBus.Text.from_string("");
-+        update_auxiliary_text_received(text, false);
-+        update_lookup_table_received(
-+                new IBus.LookupTable(1, 0, false, true),
-+                false);
-+    }
-+
-+
-+    private void show_wayland_lookup_table(IBus.Text text) {
-+        m_wayland_lookup_table_is_visible = true;
-+        var table = m_emojier.get_one_dimension_lookup_table();
-+        uint ncandidates = table.get_number_of_candidates();
-+        update_auxiliary_text_received(
-+                text,
-+                ncandidates > 0 ? true : false);
-+        update_lookup_table_received(
-+                table,
-+                ncandidates > 0 ? true : false);
-+    }
-+
-+
-+    private bool is_visible_wayland_lookup_table() {
-+        return m_wayland_lookup_table_is_visible;
-+    }
-+
-+
-+    private void hide_emoji_lookup_table() {
-+        if (m_emojier == null)
-+            return;
-+        if (m_is_wayland)
-+            hide_wayland_lookup_table();
-+        else
-+            m_emojier.hide();
-+    }
-+
-+
-+    private void show_emoji_lookup_table() {
-+        /* Emojier category_list is shown in both Xorg and Wayland
-+         * because the annotation information is useful but the Wayland lookup
-+         * window is alway one dimension. So the category_list is shown
-+         * when the user annotation is null.
-+         */
-+        if (m_is_wayland && m_preedit.get_text() != "") {
-+            var text = m_emojier.get_title_text();
-+            show_wayland_lookup_table(text);
-+        } else {
-+            // POPUP window takes the focus in Wayland.
-+            if (m_is_wayland)
-+                m_emojier.set_input_context_path(m_real_current_context_path);
-+            m_emojier.show_all();
-+        }
-+    }
-+
-+
-+    private bool is_emoji_lookup_table() {
-+        if (m_is_wayland)
-+            return is_visible_wayland_lookup_table();
-+        else
-+            return m_emojier.get_visible();
-+    }
-+
-+
-+    private void show_preedit_and_candidate(bool show_candidate) {
-+        uint cursor_pos = 0;
-+        if (!show_candidate)
-+            cursor_pos = m_preedit.get_engine_preedit_cursor_pos();
-+        update_preedit_text_received(
-+                m_preedit.get_engine_preedit_text(),
-+                cursor_pos,
-+                true);
-+        if (!show_candidate) {
-+            hide_emoji_lookup_table();
-+            return;
-+        }
-+        if (m_emojier == null)
-+            return;
-+        /* Wayland gives the focus on Emojir which is a GTK popup window
-+         * and move the focus fom the current input context to Emojier.
-+         * This forwards the lookup table to gnome-shell's lookup table
-+         * but it enables one dimension lookup table only.
-+         */
-+        show_emoji_lookup_table();
-+    }
-+
-+
-     public override void focus_in(string input_context_path) {
-         m_current_context_path = input_context_path;
- 
-@@ -299,48 +776,280 @@ class PanelBinding : IBus.PanelService {
-     }
- 
- 
--    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");
-+    public override void panel_extension_received(IBus.ExtensionEvent event) {
-+        m_extension_name = event.get_name();
-+        if (m_extension_name != "emoji" && m_extension_name != "unicode") {
-+            string format = "The name %s is not implemented in PanelExtension";
-+            warning (format.printf(m_extension_name));
-+            m_extension_name = "";
-             return;
-         }
--        if (xevent.get_purpose() != "emoji") {
--            string format = "The purpose %s is not implemented in PanelExtension";
--            warning (format.printf(xevent.get_purpose()));
-+        m_enable_extension = event.is_enabled;
-+        if (!m_enable_extension) {
-+            hide_emoji_lookup_table();
-+            return;
-+        }
-+        if (!m_loaded_emoji)
-+            set_emoji_lang();
-+        if (!m_loaded_unicode && m_loaded_emoji) {
-+            IBusEmojier.load_unicode_dict();
-+            m_loaded_unicode = true;
-+        }
-+        if (m_emojier == null) {
-+            m_emojier = new IBusEmojier();
-+            // For title handling in gnome-shell
-+            m_application.add_window(m_emojier);
-+            m_emojier.candidate_clicked.connect((i, b, s) => {
-+                if (!m_is_wayland)
-+                    candidate_clicked_lookup_table(i, b, s);
-+            });
-+        }
-+        m_emojier.reset();
-+        m_emojier.set_annotation("");
-+        m_preedit.set_extension_name(m_extension_name);
-+        m_preedit.reset();
-+        update_preedit_text_received(
-+                m_preedit.get_engine_preedit_text(),
-+                m_preedit.get_engine_preedit_cursor_pos(),
-+                true);
-+        string params = event.get_params();
-+        if (params == "category-list") {
-+            key_press_space();
-+            show_preedit_and_candidate(true);
-+        }
-+    }
-+
-+
-+    public override void set_cursor_location(int x,
-+                                             int y,
-+                                             int width,
-+                                             int height) {
-+        if (m_emojier != null)
-+            m_emojier.set_cursor_location(x, y, width, height);
-+    }
-+
-+
-+    public override void update_preedit_text(IBus.Text text,
-+                                             uint      cursor_pos,
-+                                             bool      visible) {
-+        m_preedit.set_engine_preedit_text(text);
-+        if (visible)
-+            m_preedit.show_engine_preedit_text();
-+        else
-+            m_preedit.hide_engine_preedit_text();
-+        m_preedit.set_engine_preedit_cursor_pos(cursor_pos);
-+        update_preedit_text_received(m_preedit.get_engine_preedit_text(),
-+                                     m_preedit.get_engine_preedit_cursor_pos(),
-+                                     visible);
-+    }
-+
-+
-+    public override void show_preedit_text() {
-+        m_preedit.show_engine_preedit_text();
-+        show_preedit_and_candidate(false);
-+    }
-+
-+
-+    public override void hide_preedit_text() {
-+        m_preedit.hide_engine_preedit_text();
-+        show_preedit_and_candidate(false);
-+    }
-+
-+
-+    public override bool process_key_event(uint keyval,
-+                                           uint keycode,
-+                                           uint state) {
-+        if ((state & IBus.ModifierType.RELEASE_MASK) != 0)
-+            return false;
-+        uint modifiers = state;
-+        bool show_candidate = false;
-+        switch(keyval) {
-+        case Gdk.Key.Escape:
-+            show_candidate = key_press_escape();
-+            if (!m_preedit.is_shown())
-+                return true;
-+            break;
-+        case Gdk.Key.Return:
-+        case Gdk.Key.KP_Enter:
-+            if (m_extension_name == "unicode")
-+                key_press_space();
-+            show_candidate = key_press_enter();
-+            if (!m_preedit.is_shown()) {
-+                hide_emoji_lookup_table();
-+                return true;
-+            }
-+            break;
-+        case Gdk.Key.BackSpace:
-+            m_preedit.backspace();
-+            string annotation = m_preedit.get_text();
-+            if (annotation == "" && m_extension_name == "unicode") {
-+                key_press_escape();
-+                return true;
-+            }
-+            m_emojier.set_annotation(annotation);
-+            break;
-+        case Gdk.Key.space:
-+        case Gdk.Key.KP_Space:
-+            show_candidate = key_press_space();
-+            if (m_extension_name == "unicode") {
-+                key_press_enter();
-+                return true;
-+            }
-+            break;
-+        case Gdk.Key.Right:
-+        case Gdk.Key.KP_Right:
-+            /* one dimension in Wayland, two dimensions in X11 */
-+            if (m_is_wayland) {
-+                show_candidate = key_press_cursor_vertical(Gdk.Key.Down,
-+                                                           modifiers);
-+            } else {
-+                show_candidate = key_press_cursor_horizontal(Gdk.Key.Right,
-+                                                             modifiers);
-+            }
-+            break;
-+        case Gdk.Key.Left:
-+        case Gdk.Key.KP_Left:
-+            if (m_is_wayland) {
-+                show_candidate = key_press_cursor_vertical(Gdk.Key.Up,
-+                                                           modifiers);
-+            } else {
-+                show_candidate = key_press_cursor_horizontal(Gdk.Key.Left,
-+                                                             modifiers);
-+            }
-+            break;
-+        case Gdk.Key.Down:
-+        case Gdk.Key.KP_Down:
-+            if (m_is_wayland) {
-+                show_candidate = key_press_cursor_horizontal(Gdk.Key.Right,
-+                                                             modifiers);
-+            } else {
-+                show_candidate = key_press_cursor_vertical(Gdk.Key.Down,
-+                                                           modifiers);
-+            }
-+            break;
-+        case Gdk.Key.Up:
-+        case Gdk.Key.KP_Up:
-+            if (m_is_wayland) {
-+                show_candidate = key_press_cursor_horizontal(Gdk.Key.Left,
-+                                                             modifiers);
-+            } else {
-+                show_candidate = key_press_cursor_vertical(Gdk.Key.Up,
-+                                                           modifiers);
-+            }
-+            break;
-+        case Gdk.Key.Page_Down:
-+        case Gdk.Key.KP_Page_Down:
-+            if (m_is_wayland) {
-+                show_candidate = key_press_cursor_vertical(Gdk.Key.Down,
-+                                                           modifiers);
-+            } else {
-+                show_candidate = key_press_cursor_vertical(Gdk.Key.Page_Down,
-+                                                           modifiers);
-+            }
-+            break;
-+        case Gdk.Key.Page_Up:
-+        case Gdk.Key.KP_Page_Up:
-+            if (m_is_wayland) {
-+                show_candidate = key_press_cursor_vertical(Gdk.Key.Up,
-+                                                           modifiers);
-+            } else {
-+                show_candidate = key_press_cursor_vertical(Gdk.Key.Page_Up,
-+                                                           modifiers);
-+            }
-+            break;
-+        case Gdk.Key.Home:
-+        case Gdk.Key.KP_Home:
-+            show_candidate = key_press_cursor_home_end(Gdk.Key.Home, modifiers);
-+            break;
-+        case Gdk.Key.End:
-+        case Gdk.Key.KP_End:
-+            show_candidate = key_press_cursor_home_end(Gdk.Key.End, modifiers);
-+            break;
-+        default:
-+            if ((modifiers & Gdk.ModifierType.CONTROL_MASK) != 0) {
-+                show_candidate = key_press_control_keyval(keyval, modifiers);
-+                break;
-+            }
-+            unichar ch = IBus.keyval_to_unicode(keyval);
-+            if (ch.iscntrl())
-+                return true;
-+            string str = ch.to_string();
-+            m_preedit.append_text(str);
-+            string annotation = m_preedit.get_text();
-+            m_emojier.set_annotation(annotation);
-+            m_preedit.set_emoji("");
-+            show_candidate = is_emoji_lookup_table();
-+            break;
-+        }
-+        show_preedit_and_candidate(show_candidate);
-+        return true;
-+    }
-+
-+    public override void commit_text_received(IBus.Text text) {
-+        unowned string? str = text.text;
-+        if (str == null)
-+            return;
-+        /* Do not call convert_preedit_text() because it depends on
-+         * each IME whether process_key_event() receives Shift-space or not.
-+         */
-+        m_preedit.append_text(str);
-+        m_preedit.set_emoji("");
-+        string annotation = m_preedit.get_text();
-+        m_emojier.set_annotation(annotation);
-+        show_preedit_and_candidate(false);
-+    }
-+
-+    public override void page_up_lookup_table() {
-+        bool show_candidate = key_press_cursor_vertical(Gdk.Key.Up, 0);
-+        show_preedit_and_candidate(show_candidate);
-+    }
-+
-+    public override void page_down_lookup_table() {
-+        bool show_candidate = key_press_cursor_vertical(Gdk.Key.Down, 0);
-+        show_preedit_and_candidate(show_candidate);
-+    }
-+
-+    public override void cursor_up_lookup_table() {
-+        bool show_candidate = key_press_cursor_horizontal(Gdk.Key.Left, 0);
-+        show_preedit_and_candidate(show_candidate);
-+    }
-+
-+    public override void cursor_down_lookup_table() {
-+        bool show_candidate = key_press_cursor_horizontal(Gdk.Key.Right, 0);
-+        show_preedit_and_candidate(show_candidate);
-+    }
-+
-+    public override void candidate_clicked_lookup_table(uint index,
-+                                                        uint button,
-+                                                        uint state) {
-+        if (button == IBusEmojier.BUTTON_CLOSE_BUTTON) {
-+            m_enable_extension = false;
-+            hide_emoji_lookup_table();
-+            m_preedit.hide();
-+            IBus.ExtensionEvent event = new IBus.ExtensionEvent(
-+                    "name", m_extension_name,
-+                    "is-enabled", false,
-+                    "is-extension", true);
-+            panel_extension(event);
-             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;
-+        if (m_emojier == null)
-+            return;
-+        bool show_candidate = false;
-+        uint ncandidates = m_emojier.get_number_of_candidates();
-+        if (ncandidates > 0 && ncandidates >= index) {
-+            m_emojier.set_cursor_pos(index);
-+            show_candidate = m_emojier.has_variants(index);
-+            m_preedit.set_emoji(m_emojier.get_current_candidate());
-         } else {
--            warning ("Not supported type %d".printf(xevent.get_event_type()));
-             return;
-         }
--        Gdk.Event event = new Gdk.Event(event_type);
--        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.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);
--        }
--        if (window == null) {
--            window = Gdk.get_default_root_window();
--            window.ref();
--        }
--        event.key.window = window;
--        handle_emoji_typing(event);
-+        if (!show_candidate) {
-+            IBus.Text text = m_preedit.get_commit_text();
-+            commit_text_update_favorites(text);
-+            hide_emoji_lookup_table();
-+            return;
-+        }
-+        show_preedit_and_candidate(show_candidate);
-     }
- }
--- 
-2.14.3
-
-From 7cef5bf572596361bc502e8fa917569676a80372 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Wed, 20 Jun 2018 19:01:59 +0900
-Subject: [PATCH] setup: Replace emoji font with Unicode font
-
-Now the font settings of emoji is configurable in the session base
-but not the application base and the current font setting on ibus-setup
-effects on Unicode characters.
-Also fixed the progress bar on Unicode candidate table.
----
- setup/setup.ui       |   4 +-
- src/tests/runtest    |   2 +-
- ui/gtk3/emojier.vala | 213 ++++++++++++++++++++++++++++-----------------------
- 3 files changed, 120 insertions(+), 99 deletions(-)
-
-diff --git a/setup/setup.ui b/setup/setup.ui
-index f1beb1de..9d9d7ee9 100644
---- a/setup/setup.ui
-+++ b/setup/setup.ui
-@@ -1010,9 +1010,9 @@
-                           <object class="GtkLabel" id="label_emoji_font">
-                             <property name="visible">True</property>
-                             <property name="can_focus">False</property>
--                            <property name="tooltip_text" translatable="yes">Set a font of emoji candidates on the emoji dialog</property>
-+                            <property name="tooltip_text" translatable="yes">Set a font of Unicode candidates on the emoji dialog</property>
-                             <property name="halign">start</property>
--                            <property name="label" translatable="yes">Emoji font:</property>
-+                            <property name="label" translatable="yes">Unicode font:</property>
-                             <property name="justify">right</property>
-                           </object>
-                           <packing>
-diff --git a/src/tests/runtest b/src/tests/runtest
-index b6b845d6..5c163083 100755
---- a/src/tests/runtest
-+++ b/src/tests/runtest
-@@ -142,7 +142,7 @@ run_test_case()
-         --daemonize \
-         --cache=none \
-         --panel=disable \
--        --panel-extension=disable \
-+        --emoji-extension=disable \
-         --config=default \
-         --verbose;
- 
-diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala
-index cd98c9d7..7beb6f0a 100644
---- a/ui/gtk3/emojier.vala
-+++ b/ui/gtk3/emojier.vala
-@@ -253,6 +253,7 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     private static string m_current_lang_id;
-     private static string m_emoji_font_family;
-     private static int m_emoji_font_size;
-+    private static bool m_emoji_font_changed = false;
-     private static string[] m_favorites;
-     private static string[] m_favorite_annotations;
-     private static int m_emoji_max_seq_len;
-@@ -348,88 +349,20 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         add_action(action);
-         if (m_current_lang_id == null)
-             m_current_lang_id = "en";
--        if (m_emoji_font_family == null)
-+        if (m_emoji_font_family == null) {
-             m_emoji_font_family = "Monospace";
--        if (m_emoji_font_size == 0)
-+            m_emoji_font_changed = true;
-+        }
-+        if (m_emoji_font_size == 0) {
-             m_emoji_font_size = 16;
-+            m_emoji_font_changed = true;
-+        }
-         if (m_favorites == null)
-             m_favorites = {};
-         if (m_favorite_annotations == null)
-             m_favorite_annotations = {};
- 
--        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;
--        }
--        // Set en locale because de_DE's decimal_point is ',' instead of '.'
--        string? backup_locale =
--            Intl.setlocale(LocaleCategory.NUMERIC, null).dup();
--        if (Intl.setlocale(LocaleCategory.NUMERIC, "en_US.UTF-8") == null) {
--          if (Intl.setlocale(LocaleCategory.NUMERIC, "C.UTF-8") == null) {
--              if (Intl.setlocale(LocaleCategory.NUMERIC, "C") == null) {
--                  warning("You don't install either en_US.UTF-8 or C.UTF-8 " +
--                          "or C locale");
--              }
--          }
--        }
--        m_rgba = new ThemedRGBA(this);
--        uint bg_red = (uint)(m_rgba.normal_bg.red * 255);
--        uint bg_green = (uint)(m_rgba.normal_bg.green * 255);
--        uint bg_blue = (uint)(m_rgba.normal_bg.blue * 255);
--        double bg_alpha = m_rgba.normal_bg.alpha;
--        string data =
--                "#IBusEmojierWhiteLabel { background-color: " +
--                        "rgba(%u, %u, %u, %lf); ".printf(
--                        bg_red, bg_green, bg_blue, bg_alpha) +
--                "font-family: %s; font-size: %dpt; ".printf(
--                        m_emoji_font_family, m_emoji_font_size) +
--                "border-width: 4px; border-radius: 3px; } ";
--
--        uint fg_red = (uint)(m_rgba.selected_fg.red * 255);
--        uint fg_green = (uint)(m_rgba.selected_fg.green * 255);
--        uint fg_blue = (uint)(m_rgba.selected_fg.blue * 255);
--        double fg_alpha = m_rgba.selected_fg.alpha;
--        bg_red = (uint)(m_rgba.selected_bg.red * 255);
--        bg_green = (uint)(m_rgba.selected_bg.green * 255);
--        bg_blue = (uint)(m_rgba.selected_bg.blue * 255);
--        bg_alpha = m_rgba.selected_bg.alpha;
--        data += "#IBusEmojierSelectedLabel { color: " +
--                        "rgba(%u, %u, %u, %lf); ".printf(
--                        fg_red, fg_green, fg_blue, fg_alpha) +
--                "font-family: %s; font-size: %dpt; ".printf(
--                        m_emoji_font_family, m_emoji_font_size) +
--                "background-color: " +
--                        "rgba(%u, %u, %u, %lf); ".printf(
--                        bg_red, bg_green, bg_blue, bg_alpha) +
--                "border-width: 4px; border-radius: 3px; }";
--        data += "#IBusEmojierGoldLabel { color: " +
--                        "rgba(%u, %u, %u, %lf); ".printf(
--                        fg_red, fg_green, fg_blue, fg_alpha) +
--                "font-family: %s; font-size: %dpt; ".printf(
--                        m_emoji_font_family, m_emoji_font_size) +
--                "background-color: #b09c5f; " +
--                "border-width: 4px; border-radius: 3px; }";
--
--        Gtk.CssProvider css_provider = new Gtk.CssProvider();
--        try {
--            css_provider.load_from_data(data, -1);
--        } catch (GLib.Error e) {
--            warning("Failed css_provider_from_data: %s", e.message);
--            return;
--        }
--        if (backup_locale != null)
--            Intl.setlocale(LocaleCategory.NUMERIC, backup_locale);
--        else
--            Intl.setlocale(LocaleCategory.NUMERIC, "");
--
--        Gtk.StyleContext.add_provider_for_screen(
--                screen,
--                css_provider,
--                Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-+        set_css_data();
- 
-         m_vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
-         add(m_vbox);
-@@ -795,6 +728,84 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     }
- 
- 
-+    private void set_css_data() {
-+        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;
-+        }
-+        // Set en locale because de_DE's decimal_point is ',' instead of '.'
-+        string? backup_locale =
-+            Intl.setlocale(LocaleCategory.NUMERIC, null).dup();
-+        if (Intl.setlocale(LocaleCategory.NUMERIC, "en_US.UTF-8") == null) {
-+          if (Intl.setlocale(LocaleCategory.NUMERIC, "C.UTF-8") == null) {
-+              if (Intl.setlocale(LocaleCategory.NUMERIC, "C") == null) {
-+                  warning("You don't install either en_US.UTF-8 or C.UTF-8 " +
-+                          "or C locale");
-+              }
-+          }
-+        }
-+        if (m_rgba == null)
-+            m_rgba = new ThemedRGBA(this);
-+        uint bg_red = (uint)(m_rgba.normal_bg.red * 255);
-+        uint bg_green = (uint)(m_rgba.normal_bg.green * 255);
-+        uint bg_blue = (uint)(m_rgba.normal_bg.blue * 255);
-+        double bg_alpha = m_rgba.normal_bg.alpha;
-+        string data =
-+                "#IBusEmojierWhiteLabel { background-color: " +
-+                        "rgba(%u, %u, %u, %lf); ".printf(
-+                        bg_red, bg_green, bg_blue, bg_alpha) +
-+                "font-family: %s; font-size: %dpt; ".printf(
-+                        m_emoji_font_family, m_emoji_font_size) +
-+                "border-width: 4px; border-radius: 3px; } ";
-+
-+        uint fg_red = (uint)(m_rgba.selected_fg.red * 255);
-+        uint fg_green = (uint)(m_rgba.selected_fg.green * 255);
-+        uint fg_blue = (uint)(m_rgba.selected_fg.blue * 255);
-+        double fg_alpha = m_rgba.selected_fg.alpha;
-+        bg_red = (uint)(m_rgba.selected_bg.red * 255);
-+        bg_green = (uint)(m_rgba.selected_bg.green * 255);
-+        bg_blue = (uint)(m_rgba.selected_bg.blue * 255);
-+        bg_alpha = m_rgba.selected_bg.alpha;
-+        data += "#IBusEmojierSelectedLabel { color: " +
-+                        "rgba(%u, %u, %u, %lf); ".printf(
-+                        fg_red, fg_green, fg_blue, fg_alpha) +
-+                "font-family: %s; font-size: %dpt; ".printf(
-+                        m_emoji_font_family, m_emoji_font_size) +
-+                "background-color: " +
-+                        "rgba(%u, %u, %u, %lf); ".printf(
-+                        bg_red, bg_green, bg_blue, bg_alpha) +
-+                "border-width: 4px; border-radius: 3px; }";
-+        data += "#IBusEmojierGoldLabel { color: " +
-+                        "rgba(%u, %u, %u, %lf); ".printf(
-+                        fg_red, fg_green, fg_blue, fg_alpha) +
-+                "font-family: %s; font-size: %dpt; ".printf(
-+                        m_emoji_font_family, m_emoji_font_size) +
-+                "background-color: #b09c5f; " +
-+                "border-width: 4px; border-radius: 3px; }";
-+
-+        Gtk.CssProvider css_provider = new Gtk.CssProvider();
-+        try {
-+            css_provider.load_from_data(data, -1);
-+        } catch (GLib.Error e) {
-+            warning("Failed css_provider_from_data: %s", e.message);
-+            return;
-+        }
-+        if (backup_locale != null)
-+            Intl.setlocale(LocaleCategory.NUMERIC, backup_locale);
-+        else
-+            Intl.setlocale(LocaleCategory.NUMERIC, "");
-+
-+        Gtk.StyleContext.add_provider_for_screen(
-+                screen,
-+                css_provider,
-+                Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-+    }
-+
-+
-     private void set_fixed_size() {
-         resize(20, 1);
-     }
-@@ -1038,7 +1049,8 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             m_lookup_table.append_candidate(text);
-         }
-         m_backward = block_name;
--        m_annotation = m_lookup_table.get_candidate(0).text;
-+        if (m_lookup_table.get_number_of_candidates() > 0)
-+            m_annotation = m_lookup_table.get_candidate(0).text;
-     }
- 
- 
-@@ -1385,6 +1397,10 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-     private void show_candidate_panel() {
-         remove_all_children();
-         set_fixed_size();
-+        if (m_emoji_font_changed) {
-+            set_css_data();
-+            m_emoji_font_changed = false;
-+        }
-         uint page_size = m_lookup_table.get_page_size();
-         uint ncandidates = m_lookup_table.get_number_of_candidates();
-         uint cursor = m_lookup_table.get_cursor_pos();
-@@ -1488,32 +1504,33 @@ public class IBusEmojier : Gtk.ApplicationWindow {
- 
-             m_candidates += label;
-         }
--        if (n > 0) {
--            m_candidate_panel_is_visible = true;
--            if (!m_is_up_side_down) {
--                show_arrow_buttons();
--                if (backward_button != null) {
--                    m_vbox.add(backward_button);
--                    backward_button.show_all();
--                }
-+        m_candidate_panel_is_visible = true;
-+        if (!m_is_up_side_down) {
-+            show_arrow_buttons();
-+            if (backward_button != null) {
-+                m_vbox.add(backward_button);
-+                backward_button.show_all();
-+            }
-+            if (n > 0) {
-                 m_vbox.add(grid);
-                 grid.show_all();
-                 show_description();
--                if (!m_loaded_unicode)
--                    show_unicode_progress_bar();
-             }
--            if (m_is_up_side_down) {
--                if (!m_loaded_unicode)
--                    show_unicode_progress_bar();
-+            if (!m_loaded_unicode)
-+                show_unicode_progress_bar();
-+        } else {
-+            if (!m_loaded_unicode)
-+                show_unicode_progress_bar();
-+            if (n > 0) {
-                 show_description();
-                 m_vbox.add(grid);
-                 grid.show_all();
--                if (backward_button != null) {
--                    m_vbox.add(backward_button);
--                    backward_button.show_all();
--                }
--                show_arrow_buttons();
-             }
-+            if (backward_button != null) {
-+                m_vbox.add(backward_button);
-+                backward_button.show_all();
-+            }
-+            show_arrow_buttons();
-         }
-     }
- 
-@@ -2618,11 +2635,15 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-         Pango.FontDescription font_desc =
-                 Pango.FontDescription.from_string(emoji_font);
-         string font_family = font_desc.get_family();
--        if (font_family != null)
-+        if (font_family != null) {
-             m_emoji_font_family = font_family;
-+            m_emoji_font_changed = true;
-+        }
-         int font_size = font_desc.get_size() / Pango.SCALE;
--        if (font_size != 0)
-+        if (font_size != 0) {
-             m_emoji_font_size = font_size;
-+            m_emoji_font_changed = true;
-+        }
-     }
- 
- 
--- 
-2.14.3
-
-From f9e30359d328054793e1e225dcf2fe537e6c8c48 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Wed, 27 Jun 2018 12:11:41 +0900
-Subject: [PATCH] ibusenginesimple: Enable preedit for compose keys
-
-BUG=https://github.com/ibus/ibus/issues/1935
----
- src/ibusenginesimple.c | 166 ++++++++++++++++++++++++++++++++++---------------
- 1 file changed, 115 insertions(+), 51 deletions(-)
-
-diff --git a/src/ibusenginesimple.c b/src/ibusenginesimple.c
-index 94ce53b7..61dfb89f 100644
---- a/src/ibusenginesimple.c
-+++ b/src/ibusenginesimple.c
-@@ -189,11 +189,12 @@ ibus_engine_simple_reset (IBusEngine *engine)
-         priv->tentative_match = 0;
-         priv->tentative_match_len = 0;
-         ibus_engine_hide_preedit_text ((IBusEngine *)simple);
--    }
--    if (priv->tentative_emoji || priv->in_emoji_sequence) {
-+    } else if (priv->tentative_emoji || priv->in_emoji_sequence) {
-         priv->in_emoji_sequence = FALSE;
-         g_clear_pointer (&priv->tentative_emoji, g_free);
-         ibus_engine_hide_preedit_text ((IBusEngine *)simple);
-+    } else if (!priv->in_hex_sequence && !priv->in_emoji_sequence) {
-+        ibus_engine_hide_preedit_text ((IBusEngine *)simple);
-     }
- }
- 
-@@ -209,18 +210,78 @@ ibus_engine_simple_commit_char (IBusEngineSimple *simple,
-         priv->in_hex_sequence = FALSE;
-         priv->tentative_match = 0;
-         priv->tentative_match_len = 0;
--        ibus_engine_simple_update_preedit_text (simple);
-     }
-     if (priv->tentative_emoji || priv->in_emoji_sequence) {
-         priv->in_emoji_sequence = FALSE;
-         g_clear_pointer (&priv->tentative_emoji, g_free);
--        ibus_engine_simple_update_preedit_text (simple);
-     }
--
-     ibus_engine_commit_text ((IBusEngine *)simple,
-             ibus_text_new_from_unichar (ch));
- }
- 
-+#define COMPOSE_KEYSYM_TO_UNICHAR(keysym, unichar) {                    \
-+
-+static gunichar
-+ibus_keysym_to_unicode (guint16 keysym) {
-+#define CASE(keysym_suffix, unicode) \
-+        case IBUS_KEY_dead_##keysym_suffix: return unicode
-+    switch (keysym) {
-+    CASE(a, 0x03041);
-+    CASE(A, 0x03042);
-+    CASE(i, 0x03043);
-+    CASE(I, 0x03044);
-+    CASE(u, 0x03045);
-+    CASE(U, 0x03046);
-+    CASE(e, 0x03047);
-+    CASE(E, 0x03048);
-+    CASE(o, 0x03049);
-+    CASE(O, 0x0304a);
-+    CASE(abovecomma,                    0x0313);
-+    CASE(abovedot,                      0x0307);
-+    CASE(abovereversedcomma,            0x0314);
-+    CASE(abovering,                     0x030a);
-+    CASE(acute,                         0x0301);
-+    CASE(belowbreve,                    0x032e);
-+    CASE(belowcircumflex,               0x032d);
-+    CASE(belowcomma,                    0x0326);
-+    CASE(belowdiaeresis,                0x0324);
-+    CASE(belowdot,                      0x0323);
-+    CASE(belowmacron,                   0x0331);
-+    CASE(belowring,                     0x030a);
-+    CASE(belowtilde,                    0x0330);
-+    CASE(breve,                         0x0306);
-+    CASE(capital_schwa,                 0x018f);
-+    CASE(caron,                         0x030c);
-+    CASE(cedilla,                       0x0327);
-+    CASE(circumflex,                    0x0302);
-+    CASE(currency,                      0x00a4);
-+    // IBUS_KEY_dead_dasia == IBUS_KEY_dead_abovereversedcomma
-+    CASE(diaeresis,                     0x0308);
-+    CASE(doubleacute,                   0x030b);
-+    CASE(doublegrave,                   0x030f);
-+    CASE(grave,                         0x0300);
-+    CASE(greek,                         0x03b1);
-+    CASE(hook,                          0x0309);
-+    CASE(horn,                          0x031b);
-+    CASE(invertedbreve,                 0x032f);
-+    CASE(iota,                          0x0345);
-+    CASE(macron,                        0x0304);
-+    CASE(ogonek,                        0x0328);
-+    // IBUS_KEY_dead_perispomeni == IBUS_KEY_dead_tilde
-+    // IBUS_KEY_dead_psili == IBUS_KEY_dead_abovecomma
-+    CASE(semivoiced_sound,              0x309a);
-+    CASE(small_schwa,                   0x1d4a);
-+    CASE(stroke,                        0x29f8);
-+    CASE(tilde,                         0x0303);
-+    CASE(voiced_sound,                  0x3099);
-+    case IBUS_KEY_Multi_key:
-+        return 0x2384;
-+    default:;
-+    }
-+    return 0x0;
-+#undef CASE
-+}
-+
- static void
- ibus_engine_simple_commit_str (IBusEngineSimple *simple,
-                                const gchar      *str)
-@@ -278,8 +339,7 @@ ibus_engine_simple_update_preedit_text (IBusEngineSimple *simple)
-             g_assert (len <= IBUS_MAX_COMPOSE_LEN + 1);
-         else
-             g_assert (len <= EMOJI_SOURCE_LEN + 1);
--    }
--    else if (priv->tentative_match) {
-+    } else if (priv->tentative_match) {
-         outbuf[len++] = priv->tentative_match;
-     } else if (priv->tentative_emoji && *priv->tentative_emoji) {
-         IBusText *text = ibus_text_new_from_string (priv->tentative_emoji);
-@@ -288,6 +348,24 @@ ibus_engine_simple_update_preedit_text (IBusEngineSimple *simple)
-                 IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, len);
-         ibus_engine_update_preedit_text ((IBusEngine *)simple, text, len, TRUE);
-         return;
-+    } else {
-+        int hexchars = 0;
-+        while (priv->compose_buffer[hexchars] != 0) {
-+            guint16 keysym= priv->compose_buffer[hexchars];
-+            gunichar unichar = ibus_keysym_to_unicode (keysym);
-+            if (unichar > 0)
-+                outbuf[len] = unichar;
-+            else
-+                outbuf[len] = ibus_keyval_to_unicode (keysym);
-+            if (!outbuf[len]) {
-+                g_warning (
-+                        "Not found alternative character of compose key 0x%X",
-+                        priv->compose_buffer[hexchars]);
-+            }
-+            ++len;
-+            ++hexchars;
-+        }
-+        g_assert (len <= IBUS_MAX_COMPOSE_LEN + 1);
-     }
- 
-     outbuf[len] = L'\0';
-@@ -569,8 +647,9 @@ check_table (IBusEngineSimple       *simple,
-         }
- 
-         ibus_engine_simple_commit_char (simple, value);
--        // g_debug ("U+%04X\n", value);
-         priv->compose_buffer[0] = 0;
-+        ibus_engine_simple_update_preedit_text (simple);
-+        // g_debug ("U+%04X\n", value);
-     }
-     return TRUE;
- }
-@@ -768,44 +847,10 @@ ibus_check_algorithmically (const guint16 *compose_buffer,
-         combination_buffer[n_compose] = 0;
-         i--;
-         while (i >= 0) {
--        switch (compose_buffer[i]) {
--#define CASE(keysym, unicode) \
--        case IBUS_KEY_dead_##keysym: \
--            combination_buffer[i+1] = unicode; \
--            break
--        CASE (grave, 0x0300);
--        CASE (acute, 0x0301);
--        CASE (circumflex, 0x0302);
--        CASE (tilde, 0x0303);    /* Also used with perispomeni, 0x342. */
--        CASE (macron, 0x0304);
--        CASE (breve, 0x0306);
--        CASE (abovedot, 0x0307);
--        CASE (diaeresis, 0x0308);
--        CASE (hook, 0x0309);
--        CASE (abovering, 0x030A);
--        CASE (doubleacute, 0x030B);
--        CASE (caron, 0x030C);
--        CASE (abovecomma, 0x0313);         /* Equivalent to psili */
--        CASE (abovereversedcomma, 0x0314); /* Equivalent to dasia */
--        CASE (horn, 0x031B);    /* Legacy use for psili, 0x313 (or 0x343). */
--        CASE (belowdot, 0x0323);
--        CASE (cedilla, 0x0327);
--        CASE (ogonek, 0x0328);    /* Legacy use for dasia, 0x314.*/
--        CASE (iota, 0x0345);
--        CASE (voiced_sound, 0x3099);    /* Per Markus Kuhn keysyms.txt file. */
--        CASE (semivoiced_sound, 0x309A);    /* Per Markus Kuhn keysyms.txt file. */
--
--        /* The following cases are to be removed once xkeyboard-config,
--          * xorg are fully updated.
--          */
--            /* Workaround for typo in 1.4.x xserver-xorg */
--        case 0xfe66: combination_buffer[i+1] = 0x314; break;
--        /* CASE (dasia, 0x314); */
--        /* CASE (perispomeni, 0x342); */
--        /* CASE (psili, 0x343); */
--#undef CASE
--        default:
--            combination_buffer[i+1] = ibus_keyval_to_unicode (compose_buffer[i]);
-+        combination_buffer[i+1] = ibus_keysym_to_unicode (compose_buffer[i]);
-+        if (!combination_buffer[i+1]) {
-+            combination_buffer[i+1] =
-+                    ibus_keyval_to_unicode (compose_buffer[i]);
-         }
-         i--;
-     }
-@@ -853,6 +898,7 @@ no_sequence_matches (IBusEngineSimple *simple,
- 
-         ibus_engine_simple_commit_char (simple, priv->tentative_match);
-         priv->compose_buffer[0] = 0;
-+        ibus_engine_simple_update_preedit_text (simple);
- 
-         for (i=0; i < n_compose - len - 1; i++) {
-             ibus_engine_simple_process_key_event (
-@@ -872,20 +918,21 @@ no_sequence_matches (IBusEngineSimple *simple,
-         if (n_compose > 1) {
-             /* Invalid sequence */
-             // FIXME beep_window (event->window);
-+            ibus_engine_simple_update_preedit_text (simple);
-             return TRUE;
-         }
- 
-+        ibus_engine_simple_update_preedit_text (simple);
-         ch = ibus_keyval_to_unicode (keyval);
-         /* IBUS_CHANGE: RH#769133
-          * Since we use ibus xkb engines as the disable state,
-          * do not commit the characters locally without in_hex_sequence. */
-         if (ch != 0 && !g_unichar_iscntrl (ch) &&
-             priv->in_hex_sequence) {
--            ibus_engine_simple_commit_char (simple, ch);
-             return TRUE;
--        }
--        else
-+        } else {
-             return FALSE;
-+        }
-     }
-     return FALSE;
- }
-@@ -1027,6 +1074,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
-             if (priv->tentative_match &&
-                 g_unichar_validate (priv->tentative_match)) {
-                 ibus_engine_simple_commit_char (simple, priv->tentative_match);
-+                ibus_engine_simple_update_preedit_text (simple);
-             } else if (n_compose == 0) {
-                 priv->modifiers_dropped = TRUE;
-             } else {
-@@ -1176,12 +1224,21 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
- 
-         return TRUE;
-     }
-+    if (!priv->in_hex_sequence && !priv->in_emoji_sequence && is_backspace) {
-+        if (n_compose > 0) {
-+            n_compose--;
-+            priv->compose_buffer[n_compose] = 0;
-+            ibus_engine_simple_update_preedit_text (simple);
-+            return TRUE;
-+        }
-+    }
- 
-     /* Check for hex sequence restart */
-     if (priv->in_hex_sequence && have_hex_mods && is_hex_start) {
-         if (priv->tentative_match &&
-             g_unichar_validate (priv->tentative_match)) {
-             ibus_engine_simple_commit_char (simple, priv->tentative_match);
-+            ibus_engine_simple_update_preedit_text (simple);
-         }
-         else {
-             /* invalid hex sequence */
-@@ -1283,6 +1340,12 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
-             return TRUE;
-         }
-     } else {
-+        if (is_escape) {
-+            if (n_compose > 0) {
-+                ibus_engine_simple_reset (engine);
-+                return TRUE;
-+            }
-+        }
-         SET_COMPOSE_BUFFER_ELEMENT_NEXT (priv->compose_buffer,
-                                          n_compose,
-                                          keyval);
-@@ -1302,6 +1365,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
-                     ibus_engine_simple_commit_char (simple,
-                             priv->tentative_match);
-                     priv->compose_buffer[0] = 0;
-+                    ibus_engine_simple_update_preedit_text (simple);
-                 } else {
-                     // FIXME
-                     /* invalid hex sequence */
-@@ -1417,9 +1481,8 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
-             if (compose_finish) {
-                 ibus_engine_simple_commit_char (simple, output_char);
-                 priv->compose_buffer[0] = 0;
--            } else {
--                ibus_engine_simple_update_preedit_text (simple);
-             }
-+            ibus_engine_simple_update_preedit_text (simple);
-             return TRUE;
-         }
- 
-@@ -1430,6 +1493,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
-                 ibus_engine_simple_commit_char (simple, output_char);
-                 priv->compose_buffer[0] = 0;
-             }
-+            ibus_engine_simple_update_preedit_text (simple);
-             return TRUE;
-         }
-     }
--- 
-2.14.3
-
-From 3a68ded197b3ad2e45ac08fe52c0514aff987367 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Fri, 29 Jun 2018 16:02:32 +0900
-Subject: [PATCH] ibusenginesimple: Do not show combined character on
- compose preedit
-
-Some applications could combine their committed string with compose
-character on preedit. E.g. dead_grave after 'e' on firefox
-
-BUG=https://github.com/ibus/ibus/issues/1935
----
- src/ibusenginesimple.c | 119 ++++++++++++++++++++++++++-----------------------
- 1 file changed, 63 insertions(+), 56 deletions(-)
-
-diff --git a/src/ibusenginesimple.c b/src/ibusenginesimple.c
-index 61dfb89f..68d6fb1e 100644
---- a/src/ibusenginesimple.c
-+++ b/src/ibusenginesimple.c
-@@ -219,67 +219,73 @@ ibus_engine_simple_commit_char (IBusEngineSimple *simple,
-             ibus_text_new_from_unichar (ch));
- }
- 
--#define COMPOSE_KEYSYM_TO_UNICHAR(keysym, unichar) {                    \
--
- static gunichar
--ibus_keysym_to_unicode (guint16 keysym) {
--#define CASE(keysym_suffix, unicode) \
-+ibus_keysym_to_unicode (guint16  keysym,
-+                        gboolean combining) {
-+#define CASE(keysym_suffix, unicode)                                    \
-         case IBUS_KEY_dead_##keysym_suffix: return unicode
-+#define CASE_COMBINE(keysym_suffix, combined_unicode, isolated_unicode) \
-+        case IBUS_KEY_dead_##keysym_suffix:                             \
-+            if (combining)                                              \
-+                return combined_unicode;                                \
-+            else                                                        \
-+                return isolated_unicode
-     switch (keysym) {
--    CASE(a, 0x03041);
--    CASE(A, 0x03042);
--    CASE(i, 0x03043);
--    CASE(I, 0x03044);
--    CASE(u, 0x03045);
--    CASE(U, 0x03046);
--    CASE(e, 0x03047);
--    CASE(E, 0x03048);
--    CASE(o, 0x03049);
--    CASE(O, 0x0304a);
--    CASE(abovecomma,                    0x0313);
--    CASE(abovedot,                      0x0307);
--    CASE(abovereversedcomma,            0x0314);
--    CASE(abovering,                     0x030a);
--    CASE(acute,                         0x0301);
--    CASE(belowbreve,                    0x032e);
--    CASE(belowcircumflex,               0x032d);
--    CASE(belowcomma,                    0x0326);
--    CASE(belowdiaeresis,                0x0324);
--    CASE(belowdot,                      0x0323);
--    CASE(belowmacron,                   0x0331);
--    CASE(belowring,                     0x030a);
--    CASE(belowtilde,                    0x0330);
--    CASE(breve,                         0x0306);
--    CASE(capital_schwa,                 0x018f);
--    CASE(caron,                         0x030c);
--    CASE(cedilla,                       0x0327);
--    CASE(circumflex,                    0x0302);
--    CASE(currency,                      0x00a4);
-+    CASE (a, 0x03041);
-+    CASE (A, 0x03042);
-+    CASE (i, 0x03043);
-+    CASE (I, 0x03044);
-+    CASE (u, 0x03045);
-+    CASE (U, 0x03046);
-+    CASE (e, 0x03047);
-+    CASE (E, 0x03048);
-+    CASE (o, 0x03049);
-+    CASE (O, 0x0304A);
-+    CASE         (abovecomma,                   0x0313);
-+    CASE_COMBINE (abovedot,                     0x0307, 0x02D9);
-+    CASE         (abovereversedcomma,           0x0314);
-+    CASE_COMBINE (abovering,                    0x030A, 0x02DA);
-+    CASE_COMBINE (acute,                        0x0301, 0x00B4);
-+    CASE         (belowbreve,                   0x032E);
-+    CASE_COMBINE (belowcircumflex,              0x032D, 0xA788);
-+    CASE_COMBINE (belowcomma,                   0x0326, 0x002C);
-+    CASE         (belowdiaeresis,               0x0324);
-+    CASE_COMBINE (belowdot,                     0x0323, 0x002E);
-+    CASE_COMBINE (belowmacron,                  0x0331, 0x02CD);
-+    CASE_COMBINE (belowring,                    0x030A, 0x02F3);
-+    CASE_COMBINE (belowtilde,                   0x0330, 0x02F7);
-+    CASE_COMBINE (breve,                        0x0306, 0x02D8);
-+    CASE_COMBINE (capital_schwa,                0x018F, 0x04D8);
-+    CASE_COMBINE (caron,                        0x030C, 0x02C7);
-+    CASE_COMBINE (cedilla,                      0x0327, 0x00B8);
-+    CASE_COMBINE (circumflex,                   0x0302, 0x005E);
-+    CASE         (currency,                     0x00A4);
-     // IBUS_KEY_dead_dasia == IBUS_KEY_dead_abovereversedcomma
--    CASE(diaeresis,                     0x0308);
--    CASE(doubleacute,                   0x030b);
--    CASE(doublegrave,                   0x030f);
--    CASE(grave,                         0x0300);
--    CASE(greek,                         0x03b1);
--    CASE(hook,                          0x0309);
--    CASE(horn,                          0x031b);
--    CASE(invertedbreve,                 0x032f);
--    CASE(iota,                          0x0345);
--    CASE(macron,                        0x0304);
--    CASE(ogonek,                        0x0328);
-+    CASE_COMBINE (diaeresis,                    0x0308, 0x00A8);
-+    CASE_COMBINE (doubleacute,                  0x030B, 0x02DD);
-+    CASE_COMBINE (doublegrave,                  0x030F, 0x02F5);
-+    CASE_COMBINE (grave,                        0x0300, 0x0060);
-+    CASE         (greek,                        0x03BC);
-+    CASE         (hook,                         0x0309);
-+    CASE         (horn,                         0x031B);
-+    CASE         (invertedbreve,                0x032F);
-+    CASE_COMBINE (iota,                         0x0345, 0x037A);
-+    CASE_COMBINE (macron,                       0x0304, 0x00AF);
-+    CASE_COMBINE (ogonek,                       0x0328, 0x02DB);
-     // IBUS_KEY_dead_perispomeni == IBUS_KEY_dead_tilde
-     // IBUS_KEY_dead_psili == IBUS_KEY_dead_abovecomma
--    CASE(semivoiced_sound,              0x309a);
--    CASE(small_schwa,                   0x1d4a);
--    CASE(stroke,                        0x29f8);
--    CASE(tilde,                         0x0303);
--    CASE(voiced_sound,                  0x3099);
-+    CASE_COMBINE (semivoiced_sound,             0x309A, 0x309C);
-+    CASE_COMBINE (small_schwa,                  0x1D4A, 0x04D9);
-+    CASE         (stroke,                       0x002F);
-+    CASE_COMBINE (tilde,                        0x0303, 0x007E);
-+    CASE_COMBINE (voiced_sound,                 0x3099, 0x309B);
-     case IBUS_KEY_Multi_key:
-         return 0x2384;
-     default:;
-     }
-     return 0x0;
- #undef CASE
-+#undef CASE_COMBINE
- }
- 
- static void
-@@ -352,7 +358,7 @@ ibus_engine_simple_update_preedit_text (IBusEngineSimple *simple)
-         int hexchars = 0;
-         while (priv->compose_buffer[hexchars] != 0) {
-             guint16 keysym= priv->compose_buffer[hexchars];
--            gunichar unichar = ibus_keysym_to_unicode (keysym);
-+            gunichar unichar = ibus_keysym_to_unicode (keysym, FALSE);
-             if (unichar > 0)
-                 outbuf[len] = unichar;
-             else
-@@ -847,13 +853,14 @@ ibus_check_algorithmically (const guint16 *compose_buffer,
-         combination_buffer[n_compose] = 0;
-         i--;
-         while (i >= 0) {
--        combination_buffer[i+1] = ibus_keysym_to_unicode (compose_buffer[i]);
--        if (!combination_buffer[i+1]) {
--            combination_buffer[i+1] =
--                    ibus_keyval_to_unicode (compose_buffer[i]);
-+            combination_buffer[i+1] = ibus_keysym_to_unicode (compose_buffer[i],
-+                                                              TRUE);
-+            if (!combination_buffer[i+1]) {
-+                combination_buffer[i+1] =
-+                        ibus_keyval_to_unicode (compose_buffer[i]);
-+            }
-+            i--;
-         }
--        i--;
--    }
- 
-         /* If the buffer normalizes to a single character,
-          * then modify the order of combination_buffer accordingly, if necessary,
--- 
-2.14.3
-
-From caffeaeee5be121713104fba331b9cf30726aa91 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Fri, 29 Jun 2018 16:06:52 +0900
-Subject: [PATCH] panelbinding: Fix SEGV in panel_binding_parse_accelerator
-
-panel_binding_parse_accelerator() could return NULL of the unowned
-IBus.ProcessKeyEventData with gcc optimization.
-Since Vala does not provice a static local variable, the variable is
-moved to the class member to fix this SEGV.
-Also fixed an infinite loop to show a compose preedit in xterm.
-Also a NULL preedit is fixed in the first emoji candidate from the
-emoji category window.
----
- bus/inputcontext.c        |  9 +++++++++
- bus/panelproxy.c          | 38 ++++++++++++++++++++++++++++++++++++--
- ui/gtk3/panelbinding.vala | 28 ++++++++++++++++------------
- 3 files changed, 61 insertions(+), 14 deletions(-)
-
-diff --git a/bus/inputcontext.c b/bus/inputcontext.c
-index bf9eafcf..98639a24 100644
---- a/bus/inputcontext.c
-+++ b/bus/inputcontext.c
-@@ -1730,6 +1730,15 @@ bus_input_context_hide_auxiliary_text (BusInputContext *context)
-     }
- }
- 
-+/**
-+ * bus_input_context_update_lookup_table:
-+ * @context: #BusInputContext
-+ * @table: #IBusLookupTable
-+ * @visible: %TRUE if the lookup table is visible, otherwise %FALSE.
-+ * @is_extension: %TRUE if the lookup table is called by a panel extension.
-+ *                %FALSE if it's called by an engine.
-+ * I.e. is_extension_lookup_table means the owner of the lookup table.
-+ */
- void
- bus_input_context_update_lookup_table (BusInputContext *context,
-                                        IBusLookupTable *table,
-diff --git a/bus/panelproxy.c b/bus/panelproxy.c
-index 1c0fcca2..3e6d5be2 100644
---- a/bus/panelproxy.c
-+++ b/bus/panelproxy.c
-@@ -743,6 +743,16 @@ _context_update_preedit_text_cb (BusInputContext *context,
- 
-     g_return_if_fail (panel->focused_context == context);
- 
-+    /* The callback is called with X11 applications but
-+     * the callback is not called for extensions and panel
-+     * extensions are always calls by
-+     * bus_panel_proxy_update_preedit_text() directly
-+     * because panel extensions foward UpdatePreeditText to
-+     * UpdatePreeditTextReceived and it can be an infinite
-+     * loop.
-+     */
-+    if (panel->panel_type != PANEL_TYPE_PANEL)
-+        return;
-     bus_panel_proxy_update_preedit_text (panel,
-                                          text,
-                                          cursor_pos,
-@@ -847,8 +857,31 @@ _context_set_content_type_cb (BusInputContext *context,
-         bus_panel_proxy_##name (panel);                         \
-     }
- 
--DEFINE_FUNCTION (show_preedit_text)
--DEFINE_FUNCTION (hide_preedit_text)
-+#define DEFINE_FUNCTION_NO_EXTENSION(name)                      \
-+    static void _context_##name##_cb (BusInputContext *context, \
-+                                      BusPanelProxy   *panel)   \
-+    {                                                           \
-+        g_assert (BUS_IS_INPUT_CONTEXT (context));              \
-+        g_assert (BUS_IS_PANEL_PROXY (panel));                  \
-+                                                                \
-+        g_return_if_fail (panel->focused_context == context);   \
-+                                                                \
-+        /* The callback is called with X11 applications but     \
-+         * the callback is not called for extensions and panel  \
-+         * extensions are always calls by                       \
-+         * bus_panel_proxy_update_preedit_text() directly       \
-+         * because panel extensions foward UpdatePreeditText to \
-+         * UpdatePreeditTextReceived and it can be an infinite  \
-+         * loop.                                                \
-+         */                                                     \
-+        if (panel->panel_type != PANEL_TYPE_PANEL)              \
-+            return;                                             \
-+        bus_panel_proxy_##name (panel);                         \
-+    }
-+
-+
-+DEFINE_FUNCTION_NO_EXTENSION (show_preedit_text)
-+DEFINE_FUNCTION_NO_EXTENSION (hide_preedit_text)
- DEFINE_FUNCTION (show_auxiliary_text)
- DEFINE_FUNCTION (hide_auxiliary_text)
- DEFINE_FUNCTION (show_lookup_table)
-@@ -860,6 +893,7 @@ DEFINE_FUNCTION (cursor_down_lookup_table)
- DEFINE_FUNCTION (state_changed)
- 
- #undef DEFINE_FUNCTION
-+#undef DEFINE_FUNCTION_NO_EXTENSION
- 
- static const struct {
-     gchar *name;
-diff --git a/ui/gtk3/panelbinding.vala b/ui/gtk3/panelbinding.vala
-index 52b78c17..95115b13 100644
---- a/ui/gtk3/panelbinding.vala
-+++ b/ui/gtk3/panelbinding.vala
-@@ -227,6 +227,8 @@ class PanelBinding : IBus.PanelService {
-     private bool m_enable_extension;
-     private string m_extension_name = "";
-     private Preedit m_preedit;
-+    private IBus.ProcessKeyEventData m_key_event_data =
-+            IBus.ProcessKeyEventData();
- 
-     public PanelBinding(IBus.Bus bus,
-                         Gtk.Application application) {
-@@ -311,24 +313,24 @@ class PanelBinding : IBus.PanelService {
-     }
- 
- 
--    private unowned
--    IBus.ProcessKeyEventData? parse_accelerator(string accelerator) {
--        IBus.ProcessKeyEventData key = {};
-+    // Returning unowned IBus.KeyEventData causes NULL with gcc optimization
-+    // and use m_key_event_data.
-+    private void parse_accelerator(string accelerator) {
-+        m_key_event_data = {};
-         uint keysym = 0;
-         IBus.ModifierType modifiers = 0;
-         IBus.accelerator_parse(accelerator,
-                 out keysym, out modifiers);
-         if (keysym == 0U && modifiers == 0) {
-             warning("Failed to parse shortcut key '%s'".printf(accelerator));
--            return null;
-+            return;
-         }
-         if ((modifiers & IBus.ModifierType.SUPER_MASK) != 0) {
-             modifiers ^= IBus.ModifierType.SUPER_MASK;
-             modifiers |= IBus.ModifierType.MOD4_MASK;
-         }
--        key.keyval = keysym;
--        key.state = modifiers;
--        return key;
-+        m_key_event_data.keyval = keysym;
-+        m_key_event_data.state = modifiers;
-     }
- 
- 
-@@ -337,8 +339,8 @@ class PanelBinding : IBus.PanelService {
-         IBus.ProcessKeyEventData key;
-         string[] accelerators = m_settings_emoji.get_strv("hotkey");
-         foreach (var accelerator in accelerators) {
--            key = parse_accelerator(accelerator);
--            emoji_keys += key;
-+            parse_accelerator(accelerator);
-+            emoji_keys += m_key_event_data;
-         }
- 
-         /* Since {} is not allocated, parse_accelerator() should be unowned. */
-@@ -348,8 +350,8 @@ class PanelBinding : IBus.PanelService {
-         IBus.ProcessKeyEventData[] unicode_keys = {};
-         accelerators = m_settings_emoji.get_strv("unicode-hotkey");
-         foreach (var accelerator in accelerators) {
--            key = parse_accelerator(accelerator);
--            unicode_keys += key;
-+            parse_accelerator(accelerator);
-+            unicode_keys += m_key_event_data;
-         }
-         key = {};
-         unicode_keys += key;
-@@ -544,8 +546,10 @@ class PanelBinding : IBus.PanelService {
-     private bool key_press_enter() {
-         if (m_extension_name != "unicode" && is_emoji_lookup_table()) {
-             // Check if variats exist
--            if (m_emojier.key_press_enter())
-+            if (m_emojier.key_press_enter()) {
-+                convert_preedit_text();
-                 return true;
-+            }
-         }
-         IBus.Text text = m_preedit.get_commit_text();
-         commit_text_update_favorites(text);
--- 
-2.14.3
-
-From 6b47e41d66497dd35752a89ea80e4bac55b64e45 Mon Sep 17 00:00:00 2001
-From: Takuro Ashie <ashie@clear-code.com>
-Date: Fri, 20 Jul 2018 12:30:09 +0900
-Subject: [PATCH] Remove a misleading "const" modifier of a return value
-
-ibus_key_event_to_string() uses g_string_free(str, FALSE) to return
-a string so that users must free it. To clarify it, the const
-modifier should be removed.
----
- src/ibuskeynames.c | 2 +-
- src/ibusshare.h    | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/ibuskeynames.c b/src/ibuskeynames.c
-index fe7836ee..c3665127 100644
---- a/src/ibuskeynames.c
-+++ b/src/ibuskeynames.c
-@@ -124,7 +124,7 @@ modifier_name[] = {
-     NULL,        // 31
- };
- 
--const gchar *
-+gchar *
- ibus_key_event_to_string (guint keyval,
-                           guint modifiers)
- {
-diff --git a/src/ibusshare.h b/src/ibusshare.h
-index 4f5a306b..d70af29f 100644
---- a/src/ibusshare.h
-+++ b/src/ibusshare.h
-@@ -326,7 +326,7 @@ void             ibus_free_strv         (gchar          **strv)
-  *
-  * Returns: The name of a key symbol and modifier.
-  */
--const gchar     *ibus_key_event_to_string
-+gchar           *ibus_key_event_to_string
-                                         (guint           keyval,
-                                          guint           modifiers);
- 
--- 
-2.17.1
-
-From 0dde239a3c786dcc479e3103ccd49938fcb47191 Mon Sep 17 00:00:00 2001
-From: Kentaro Hayashi <hayashi@clear-code.com>
-Date: Tue, 24 Jul 2018 15:20:51 +0900
-Subject: [PATCH] bus: warn deprecated --mem-profile option
-
-Since GLib 2.46, memory profiling feature does not work anymore.
-
-GLib 2.46 or later means that Ubuntu 16.04 or later. Ubuntu
-14.04 (trusty) are still supported as LTS phase, but it seems that
-GLib is old enough (2.40) to drop support.
-
-As a result:
-
-  * older than GLib 2.46: Just drop support
-  * GLib 2.46 or later: Show a warning message if --mem-profile is
-    used.
----
- bus/main.c   | 15 +--------------
- configure.ac |  4 ++--
- 2 files changed, 3 insertions(+), 16 deletions(-)
-
-diff --git a/bus/main.c b/bus/main.c
-index 2fb37b69..6f1f39ca 100644
---- a/bus/main.c
-+++ b/bus/main.c
-@@ -160,18 +160,6 @@ daemon (gint nochdir, gint noclose)
- }
- #endif
- 
--/*
-- * _sig_usr2_handler:
-- * @sig: the signal number, which is usually SIGUSR2.
-- *
-- * A signal handler for SIGUSR2 signal. Dump a summary of memory usage to stderr.
-- */
--static void
--_sig_usr2_handler (int sig)
--{
--    g_mem_profile ();
--}
--
- gint
- main (gint argc, gchar **argv)
- {
-@@ -196,8 +184,7 @@ main (gint argc, gchar **argv)
-     }
- 
-     if (g_mempro) {
--        g_mem_set_vtable (glib_mem_profiler_table);
--        signal (SIGUSR2, _sig_usr2_handler);
-+        g_warning ("--mem-profile no longer works with the GLib 2.46 or later");
-     }
- 
-     /* check uid */
-diff --git a/configure.ac b/configure.ac
-index f332a775..8e01c266 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -52,12 +52,12 @@ m4_define([ibus_binary_version],
-           [ibus_major_version.ibus_abi_current_minus_age.ibus_abi_age.ibus_abi_revision])
- 
- # Required versions of other packages.
--m4_define([glib_required_version], [2.36.0])
-+m4_define([glib_required_version], [2.46.0])
- 
- # VALA_TARGET_GLIB_VERSION is used by valac --ccode --target-glib .
- # VALA_TARGET_GLIB_VERSION and glib_required_version will be different
- # in the future.
--VALA_TARGET_GLIB_VERSION=2.36
-+VALA_TARGET_GLIB_VERSION=2.46
- AC_SUBST(VALA_TARGET_GLIB_VERSION)
- 
- # Init automake.
--- 
-2.17.1
-
-From 8d302c853f4e88f81652e0aeeca86ff1b5779ecb Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Tue, 24 Jul 2018 16:04:31 +0900
-Subject: [PATCH] RHEL code reviews
-
----
- client/x11/main.c             |  4 ++--
- setup/enginetreeview.py       | 10 ++--------
- setup/ibus-setup.in           |  5 ++---
- src/emoji-parser.c            |  8 +++++---
- src/ibusbus.c                 |  9 ++++++---
- src/ibuscomposetable.c        |  4 ++--
- src/ibusenginesimple.c        | 22 +++++++++++++++++-----
- src/ibushotkey.c              |  5 +++--
- src/ibuskeymap.c              | 10 ++++++----
- src/ibuskeynames.c            |  3 +--
- src/ibusregistry.c            |  4 ++--
- src/ibusservice.c             | 13 +++++++++----
- src/ibusxml.c                 |  9 ++++++---
- src/unicode-parser.c          |  3 ++-
- util/IMdkit/FrameMgr.c        |  7 +++++++
- util/IMdkit/IMConn.c          |  6 ++++--
- util/IMdkit/i18nClbk.c        | 10 ++++++++++
- util/IMdkit/i18nIc.c          | 11 +++++++++--
- util/IMdkit/i18nMethod.c      |  4 ++++
- util/IMdkit/i18nOffsetCache.c | 21 +++++++++++++++++----
- util/IMdkit/i18nPtHdr.c       | 28 +++++++++++++++++++++++-----
- util/IMdkit/i18nUtil.c        | 12 +++++++++---
- util/IMdkit/i18nX.c           | 10 ++++++++--
- 23 files changed, 156 insertions(+), 62 deletions(-)
-
-diff --git a/client/x11/main.c b/client/x11/main.c
-index 159f4303..3bea94b7 100644
---- a/client/x11/main.c
-+++ b/client/x11/main.c
-@@ -2,7 +2,7 @@
- /* vim:set et sts=4: */
- /* ibus
-  * 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-2015 Red Hat, Inc.
-  *
-  * main.c:
-@@ -196,7 +196,7 @@ _xim_preedit_callback_draw (XIMS xims, X11IC *x11ic, const gchar *preedit_string
-         }
-     }
- 
--    for (i = 0; i < len; i++) {
-+    for (i = 0; feedback && i < len; i++) {
-         feedback[i] = 0;
-     }
- 
-diff --git a/setup/enginetreeview.py b/setup/enginetreeview.py
-index 4de4a516..aea84593 100644
---- a/setup/enginetreeview.py
-+++ b/setup/enginetreeview.py
-@@ -3,7 +3,8 @@
- # ibus - The Input Bus
- #
- # Copyright (c) 2007-2015 Peng Huang <shawn.p.huang@gmail.com>
--# Copyright (c) 2007-2015 Red Hat, Inc.
-+# Copyright (c) 2014-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
-@@ -91,7 +92,6 @@ class EngineTreeView(Gtk.TreeView):
-         renderer.set_property("text-column", 0)
-         renderer.set_property("has-entry", False)
-         renderer.set_property("editable", True)
--        renderer.connect("changed", self.__engine_layout_changed_cb)
- 
-         column = Gtk.TreeViewColumn(_("Kbd"))
-         column.set_expand(False)
-@@ -167,12 +167,6 @@ class EngineTreeView(Gtk.TreeView):
-         renderer.set_property("text", layout)
-         renderer.set_property("weight", Pango.Weight.NORMAL)
- 
--    def __engine_layout_changed_cb(self, combo, path, it):
--        return
--        i = self.__model.get_iter(path)
--        layout = combo.get_property("model").get_value(it, 0)
--        self.__model.set_value(i, 1, layout)
--
-     def do_get_property(self, prop):
-         if prop.name == "active-engine":
-             it = self.get_selected_iter()
-diff --git a/setup/ibus-setup.in b/setup/ibus-setup.in
-index e0ed9ff5..bb5c85cf 100644
---- a/setup/ibus-setup.in
-+++ b/setup/ibus-setup.in
-@@ -3,7 +3,8 @@
- # ibus - The Input Bus
- #
- # Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
--# Copyright (c) 2007-2010 Red Hat, Inc.
-+# Copyright (c) 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
-@@ -21,8 +22,6 @@
- # USA
- 
- prefix=@prefix@
--exec_prefix=@exec_prefix@
--datarootdir=@datarootdir@
- libexecdir=@libexecdir@
- export IBUS_PREFIX=@prefix@
- export IBUS_DATAROOTDIR=@datarootdir@
-diff --git a/src/emoji-parser.c b/src/emoji-parser.c
-index 0f7c8cfb..b8f4dcf1 100644
---- a/src/emoji-parser.c
-+++ b/src/emoji-parser.c
-@@ -466,7 +466,8 @@ unicode_annotations_parse_xml_file (const gchar  *filename,
-     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);
-+        g_warning ("Failed to load %s: %s", filename,
-+                   error ? error->message : "");
-         goto failed_to_parse_unicode_annotations;
-     }
- 
-@@ -611,7 +612,7 @@ unicode_emoji_test_parse_line (const gchar *line,
-             int i;
-             gchar *amp;
-             segments = g_strsplit(data->subcategory, "-", -1);
--            for (i = 0; segments[i]; i++) {
-+            for (i = 0; segments && segments[i]; i++) {
-                 if ((amp = strchr (segments[i], '&')) != NULL) {
-                     if (amp - segments[i] <= 1) {
-                         g_warning ("Wrong ampersand");
-@@ -665,7 +666,8 @@ unicode_emoji_test_parse_file (const gchar *filename,
-     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);
-+        g_warning ("Failed to load %s: %s",
-+                   filename, error ? error->message : "");
-         goto failed_to_parse_unicode_emoji_test;
-     }
-     head = end = content;
-diff --git a/src/ibusbus.c b/src/ibusbus.c
-index 98820e8a..30c2e321 100644
---- a/src/ibusbus.c
-+++ b/src/ibusbus.c
-@@ -2,7 +2,7 @@
- /* vim:set et sts=4: */
- /* ibus - The Input Bus
-  * Copyright (C) 2008-2015 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
-@@ -22,6 +22,7 @@
-  */
- 
- #include "ibusbus.h"
-+#include <errno.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <unistd.h>
-@@ -565,7 +566,9 @@ ibus_bus_init (IBusBus *bus)
-             return;
-         }
-         if (buf.st_mode != (S_IFDIR | S_IRWXU)) {
--            g_chmod (path, 0700);
-+            errno = 0;
-+            if (g_chmod (path, 0700))
-+                g_warning ("chmod failed: %s", errno ? g_strerror (errno) : "");
-         }
-     }
- 
-@@ -673,7 +676,7 @@ ibus_bus_constructor (GType                  type,
-             ibus_bus_connect (_bus);
-     }
-     else {
--        object = g_object_ref (_bus);
-+        object = g_object_ref (G_OBJECT (_bus));
-     }
- 
-     return object;
-diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c
-index d473f581..b843e7e1 100644
---- a/src/ibuscomposetable.c
-+++ b/src/ibuscomposetable.c
-@@ -1,7 +1,7 @@
- /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
- /* ibus - The Input Bus
-  * Copyright (C) 2013-2014 Peng Huang <shawn.p.huang@gmail.com>
-- * Copyright (C) 2013-2017 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * Copyright (C) 2013-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
-@@ -532,7 +532,7 @@ ibus_compose_table_serialize (IBusComposeTable *compose_table)
- 
-     variant_data = g_variant_new_fixed_array (G_VARIANT_TYPE_UINT16,
-                                               compose_table->data,
--                                              index_stride * n_seqs,
-+                                              (gsize)index_stride * n_seqs,
-                                               sizeof (guint16));
-     if (variant_data == NULL) {
-         g_warning ("Could not change compose data to GVariant.");
-diff --git a/src/ibusenginesimple.c b/src/ibusenginesimple.c
-index 68d6fb1e..aae6b8df 100644
---- a/src/ibusenginesimple.c
-+++ b/src/ibusenginesimple.c
-@@ -2,7 +2,7 @@
- /* vim:set et sts=4: */
- /* ibus - The Input Bus
-  * Copyright (C) 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) 2014-2017 Red Hat, Inc.
-  *
-  * This library is free software; you can redistribute it and/or
-@@ -814,9 +814,21 @@ check_normalize_nfc (gunichar* combination_buffer, gint n_compose)
-         g_free (nfc_temp);
- 
-         if (n_compose > 2) {
--            temp_swap = combination_buffer_temp[i % (n_compose - 1) + 1];
--            combination_buffer_temp[i % (n_compose - 1) + 1] = combination_buffer_temp[(i+1) % (n_compose - 1) + 1];
--            combination_buffer_temp[(i+1) % (n_compose - 1) + 1] = temp_swap;
-+            gint j = i % (n_compose - 1) + 1;
-+            gint k = (i+1) % (n_compose - 1) + 1;
-+            if (j >= IBUS_MAX_COMPOSE_LEN) {
-+                g_warning ("j >= IBUS_MAX_COMPOSE_LEN for " \
-+                           "combination_buffer_temp");
-+                break;
-+            }
-+            if (k >= IBUS_MAX_COMPOSE_LEN) {
-+                g_warning ("k >= IBUS_MAX_COMPOSE_LEN for " \
-+                           "combination_buffer_temp");
-+                break;
-+            }
-+            temp_swap = combination_buffer_temp[j];
-+            combination_buffer_temp[j] = combination_buffer_temp[k];
-+            combination_buffer_temp[k] = temp_swap;
-         }
-         else
-             break;
-@@ -1067,7 +1079,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine,
-     gboolean compose_finish;
-     gunichar output_char;
- 
--    while (priv->compose_buffer[n_compose] != 0 && n_compose < EMOJI_SOURCE_LEN)
-+    while (n_compose < EMOJI_SOURCE_LEN && priv->compose_buffer[n_compose] != 0)
-         n_compose++;
-     if (n_compose >= EMOJI_SOURCE_LEN) {
-         g_warning ("copmose table buffer is full.");
-diff --git a/src/ibushotkey.c b/src/ibushotkey.c
-index 0cdfa78b..00d502fc 100644
---- a/src/ibushotkey.c
-+++ b/src/ibushotkey.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
-@@ -453,7 +454,7 @@ ibus_hotkey_profile_remove_hotkey (IBusHotkeyProfile *profile,
-             break;
-     }
- 
--    g_assert (p2->event == event);
-+    g_assert (p2 && p2->event == event);
- 
-     p2->hotkeys = g_list_remove (p2->hotkeys, p1);
-     if (p2->hotkeys == NULL) {
-diff --git a/src/ibuskeymap.c b/src/ibuskeymap.c
-index d7428c5d..27a56754 100644
---- a/src/ibuskeymap.c
-+++ b/src/ibuskeymap.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
-@@ -72,7 +73,7 @@ static gboolean
- ibus_keymap_parse_line (gchar  *str,
-                         KEYMAP  keymap)
- {
--    gchar *p1, *p2;
-+    gchar *p1, *p2, ch;
-     gint i;
-     guint keycode;
-     guint keysym;
-@@ -139,11 +140,12 @@ ibus_keymap_parse_line (gchar  *str,
-     if (keysym == IBUS_KEY_VoidSymbol)
-         return FALSE;
- 
-+    /* Do not assign *p1 to g_ascii_isalpha() directly for the syntax check */
-     if (i == 0 &&
-         strncmp (p2, "addupper", sizeof ("addupper") - 1) == 0 &&
--        g_ascii_isalpha (*p1)) {
-+        (ch = *p1) && g_ascii_isalpha (ch)) {
-         gchar buf[] = "a";
--        buf[0] = g_ascii_toupper(*p1);
-+        buf[0] = g_ascii_toupper(ch);
-         keymap[keycode][0] = keymap[keycode][3] = keysym;
-         keymap[keycode][1] = keymap[keycode][2] = ibus_keyval_from_name (buf);
- 
-diff --git a/src/ibuskeynames.c b/src/ibuskeynames.c
-index c3665127..08505598 100644
---- a/src/ibuskeynames.c
-+++ b/src/ibuskeynames.c
-@@ -192,8 +192,7 @@ ibus_key_event_from_string (const gchar *string,
-     if (*keyval != IBUS_KEY_VoidSymbol)
-         retval = TRUE;
- _out:
--    if (tokens)
--        g_strfreev (tokens);
-+    g_strfreev (tokens);
-     return retval;
- }
- 
-diff --git a/src/ibusregistry.c b/src/ibusregistry.c
-index dfda2af3..b0483998 100644
---- a/src/ibusregistry.c
-+++ b/src/ibusregistry.c
-@@ -2,7 +2,7 @@
- /* vim:set et sts=4: */
- /* bus - The Input Bus
-  * Copyright (C) 2015 Peng Huang <shawn.p.huang@gmail.com>
-- * Copyright (C) 2015 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+ * Copyright (C) 2015-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
-  * Copyright (C) 2015 Red Hat, Inc.
-  *
-  * This library is free software; you can redistribute it and/or
-@@ -472,7 +472,7 @@ ibus_registry_save_cache_file (IBusRegistry *registry,
-     }
- 
-     if (g_str_has_prefix (filename, g_get_user_cache_dir ())) {
--        g_chmod (filename, 0644);
-+        g_warn_if_fail (!g_chmod (filename, 0644));
-     }
- 
-     return TRUE;
-diff --git a/src/ibusservice.c b/src/ibusservice.c
-index 2199d61d..8023527b 100644
---- a/src/ibusservice.c
-+++ b/src/ibusservice.c
-@@ -2,7 +2,8 @@
- /* vim:set et sts=4: */
- /* ibus - The Input Bus
-  * Copyright (C) 2008-2015 Peng Huang <shawn.p.huang@gmail.com>
-- * Copyright (C) 2008-2015 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
-@@ -500,12 +501,14 @@ ibus_service_register (IBusService     *service,
-                        GDBusConnection *connection,
-                        GError         **error)
- {
-+    GArray *array = NULL;
-+    GArray *interfaces;
-+    GDBusInterfaceInfo **p;
-+
-     g_return_val_if_fail (IBUS_IS_SERVICE (service), FALSE);
-     g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
-     g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- 
--    GArray *array = NULL;
--
-     if (g_hash_table_lookup (service->priv->table, connection)) {
-         if (error) {
-             *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_OBJECT_PATH_IN_USE,
-@@ -515,7 +518,9 @@ ibus_service_register (IBusService     *service,
-         goto error_out;
-     }
- 
--    GDBusInterfaceInfo **p = (GDBusInterfaceInfo **)IBUS_SERVICE_GET_CLASS (service)->interfaces->data;
-+    interfaces = IBUS_SERVICE_GET_CLASS (service)->interfaces;
-+    g_assert (interfaces);
-+    p = (GDBusInterfaceInfo **)interfaces->data;
-     if (*p == NULL) {
-         if (error) {
-             *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
-diff --git a/src/ibusxml.c b/src/ibusxml.c
-index 5cacc5af..266a8207 100644
---- a/src/ibusxml.c
-+++ b/src/ibusxml.c
-@@ -2,7 +2,8 @@
- /* vim:set et sts=4: */
- /* bus - The Input Bus
-  * Copyright (C) 2008-2015 Peng Huang <shawn.p.huang@gmail.com>
-- * Copyright (C) 2008-2015 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
-@@ -240,8 +241,10 @@ ibus_xml_parse_file (const gchar *filename)
-         return node;
-     } while (0);
- 
--    g_warning ("Parse %s failed: %s", filename, error->message);
--    g_error_free (error);
-+    if (error) {
-+        g_warning ("Parse %s failed: %s", filename, error->message);
-+        g_error_free (error);
-+    }
-     g_markup_parse_context_free (context);
-     return NULL;
- }
-diff --git a/src/unicode-parser.c b/src/unicode-parser.c
-index e98c6d5f..0e4fe8b7 100644
---- a/src/unicode-parser.c
-+++ b/src/unicode-parser.c
-@@ -281,7 +281,8 @@ ucd_parse_file (const gchar *filename,
-     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);
-+        g_warning ("Failed to load %s: %s",
-+                   filename, error ? error->message : "");
-         goto failed_to_parse_ucd_names_list;
-     }
-     head = end = content;
-diff --git a/util/IMdkit/FrameMgr.c b/util/IMdkit/FrameMgr.c
-index 9b497948..084b8810 100644
---- a/util/IMdkit/FrameMgr.c
-+++ b/util/IMdkit/FrameMgr.c
-@@ -27,6 +27,7 @@ SOFTWARE.
- ******************************************************************/
- 
- #include <X11/Xlibint.h>
-+#include <assert.h>
- #include <stdlib.h>
- #include "FrameMgr.h"
- 
-@@ -989,6 +990,7 @@ static XimFrameType FrameInstGetNextType(FrameInst fi, XimFrameTypeInfo info)
-             while (number > 0)
-             {
-                 i = _FrameInstDecrement (fi->template, i);
-+                assert (i >= 0);
-                 size += _FrameInstGetItemSize (fi, i);
-                 number--;
-             }
-@@ -1138,6 +1140,7 @@ static XimFrameType FrameInstPeekNextType (FrameInst fi, XimFrameTypeInfo info)
-             while (number > 0)
-             {
-                 i = _FrameInstDecrement (fi->template, i);
-+                assert (i >= 0);
-                 size += _FrameInstGetItemSize (fi, i);
-                 number--;
-             }
-@@ -1356,6 +1359,7 @@ static FmStatus FrameInstSetSize (FrameInst fi, int num)
- 	    break;
-         }
-         /*endswitch*/
-+        assert (i >= 0);
-         i = _FrameInstIncrement(fi->template, i);
-     }
-     /*endwhile*/
-@@ -1457,6 +1461,7 @@ static FmStatus FrameInstSetIterCount (FrameInst fi, int num)
- 	    break;
-         }
-         /*endswitch*/
-+        assert (i >= 0);
-         i = _FrameInstIncrement (fi->template, i);
-     }
-     /*endwhile*/
-@@ -1474,6 +1479,7 @@ static int FrameInstGetTotalSize (FrameInst fi)
-     while (fi->template[i].type != EOL)
-     {
-         size += _FrameInstGetItemSize (fi, i);
-+        assert (i >= 0);
-         i = _FrameInstIncrement (fi->template, i);
-     }
-     /*endwhile*/
-@@ -2419,6 +2425,7 @@ static int _FrameInstGetItemSize (FrameInst fi, int cur_no)
-             size = 0;
-             while (number > 0)
-             {
-+                assert (i >= 0);
-                 i = _FrameInstDecrement (fi->template, i);
-                 size += _FrameInstGetItemSize (fi, i);
-                 number--;
-diff --git a/util/IMdkit/IMConn.c b/util/IMdkit/IMConn.c
-index 6d365893..8e8b8ece 100644
---- a/util/IMdkit/IMConn.c
-+++ b/util/IMdkit/IMConn.c
-@@ -83,7 +83,7 @@ static char *_FindModifiers (XIMArg *args)
- {
-     char *modifiers;
- 
--    while (args->name)
-+    while (args && args->name)
-     {
- 	if (strcmp (args->name, IMModifiers) == 0)
- 	{
-@@ -144,8 +144,10 @@ XIMS IMOpenIM (Display *display, ...)
-     modifiers = _FindModifiers (args);
- 
-     ims = _GetIMS (modifiers);
--    if (ims == (XIMS) NULL)
-+    if (ims == (XIMS) NULL) {
-+        XFree (args);
-         return (XIMS) NULL;
-+    }
-     /*endif*/
-     
-     ims->core.display = display;
-diff --git a/util/IMdkit/i18nClbk.c b/util/IMdkit/i18nClbk.c
-index b3edf3ad..f55f970f 100644
---- a/util/IMdkit/i18nClbk.c
-+++ b/util/IMdkit/i18nClbk.c
-@@ -55,6 +55,7 @@ int _Xi18nGeometryCallback (XIMS ims, IMProtocol *call_data)
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return False;
-     }
-     /*endif*/
-@@ -97,6 +98,7 @@ int _Xi18nPreeditStartCallback (XIMS ims, IMProtocol *call_data)
-     if (!reply)
-     {
-         _Xi18nSendMessage(ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return False;
-     }
-     /*endif*/
-@@ -159,6 +161,7 @@ int _Xi18nPreeditDrawCallback (XIMS ims, IMProtocol *call_data)
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return False;
-     }
-     /*endif*/
-@@ -212,6 +215,7 @@ int _Xi18nPreeditCaretCallback (XIMS ims, IMProtocol *call_data)
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return False;
-     }
-     /*endif*/
-@@ -256,6 +260,7 @@ int _Xi18nPreeditDoneCallback (XIMS ims, IMProtocol *call_data)
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return False;
-     }
-     /*endif*/
-@@ -297,6 +302,7 @@ int _Xi18nStatusStartCallback (XIMS ims, IMProtocol *call_data)
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return False;
-     }
-     /*endif*/
-@@ -363,6 +369,7 @@ int _Xi18nStatusDrawCallback (XIMS ims, IMProtocol *call_data)
-         if (!reply)
-         {
-             _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+            FrameMgrFree (fm);
-             return False;
-         }
-         /*endif*/
-@@ -390,6 +397,7 @@ int _Xi18nStatusDrawCallback (XIMS ims, IMProtocol *call_data)
-         if (!reply)
-         {
-             _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+            FrameMgrFree (fm);
-             return False;
-         }
-         /*endif*/
-@@ -435,6 +443,7 @@ int _Xi18nStatusDoneCallback (XIMS ims, IMProtocol *call_data)
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return False;
-     }
-     /*endif*/
-@@ -479,6 +488,7 @@ int _Xi18nStringConversionCallback (XIMS ims, IMProtocol *call_data)
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return False;
-     }
-     /*endif*/
-diff --git a/util/IMdkit/i18nIc.c b/util/IMdkit/i18nIc.c
-index 87445986..289837a6 100644
---- a/util/IMdkit/i18nIc.c
-+++ b/util/IMdkit/i18nIc.c
-@@ -475,8 +475,10 @@ static XICAttribute *CreateNestedList (CARD16 attr_id,
-     /*endif*/
-     memset (nest_list, 0, sizeof (XICAttribute));
-     nest_list->value = (void *) malloc (value_length);
--    if (nest_list->value == NULL)
-+    if (nest_list->value == NULL) {
-+        XFree (nest_list);
-         return NULL;
-+    }
-     /*endif*/
-     memset (nest_list->value, 0, value_length);
- 
-@@ -816,6 +818,7 @@ void _Xi18nChangeIC (XIMS ims,
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return;
-     }
-     /*endif*/
-@@ -973,8 +976,10 @@ void _Xi18nGetIC (XIMS ims, IMProtocol *call_data, unsigned char *p)
-     getic->ic_attr = ic_attr;
-     if (i18n_core->address.improto)
-     {
--        if (!(i18n_core->address.improto (ims, call_data)))
-+        if (!(i18n_core->address.improto (ims, call_data))) {
-+            XFree (attrID_list);
-             return;
-+        }
-         /*endif*/
- 	if (_Xi18nNeedSwap (i18n_core, connect_id))
- 	  SwapAttributes(getic->ic_attr, getic->ic_attr_num);
-@@ -1020,6 +1025,8 @@ void _Xi18nGetIC (XIMS ims, IMProtocol *call_data, unsigned char *p)
-     if (reply == NULL)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        XFree (attrID_list);
-+        FrameMgrFree (fm);
-         return;
-     }
-     /*endif*/
-diff --git a/util/IMdkit/i18nMethod.c b/util/IMdkit/i18nMethod.c
-index 203f8315..36dd28ac 100644
---- a/util/IMdkit/i18nMethod.c
-+++ b/util/IMdkit/i18nMethod.c
-@@ -895,6 +895,7 @@ static Status xi18n_forwardEvent (XIMS ims, XPointer xp)
-                            0,
-                            0,
-                            0);
-+        FrameMgrFree (fm);
-         return False;
-     }
-     /*endif*/
-@@ -964,6 +965,7 @@ static Status xi18n_commit (XIMS ims, XPointer xp)
-                                0,
-                                0,
-                                0);
-+            FrameMgrFree (fm);
-             return False;
-         }
-         /*endif*/
-@@ -997,6 +999,7 @@ static Status xi18n_commit (XIMS ims, XPointer xp)
-                                0,
-                                0,
-                                0);
-+            FrameMgrFree (fm);
-             return False;
-         }
-         /*endif*/
-@@ -1132,6 +1135,7 @@ static int xi18n_syncXlib (XIMS ims, XPointer xp)
-     reply = (unsigned char *) malloc (total_size);
-     if (!reply) {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return False;
-     }
-     memset (reply, 0, total_size);
-diff --git a/util/IMdkit/i18nOffsetCache.c b/util/IMdkit/i18nOffsetCache.c
-index c952d5b4..d5379051 100644
---- a/util/IMdkit/i18nOffsetCache.c
-+++ b/util/IMdkit/i18nOffsetCache.c
-@@ -27,9 +27,11 @@
-  */
- 
- #include <X11/Xlib.h>
-+#include <assert.h>
- #include <stddef.h>
- #include "IMdkit.h"
- #include "Xi18n.h"
-+#include "Xi18n.h"
- 
- /*
-  * The XIM specification does not limit the number of window properties
-@@ -52,9 +54,11 @@ void _Xi18nInitOffsetCache (Xi18nOffsetCache *offset_cache)
- unsigned long _Xi18nLookupPropertyOffset (Xi18nOffsetCache *offset_cache,
-                                           Atom key)
- {
--    Xi18nAtomOffsetPair *data = offset_cache->data;
-+    Xi18nAtomOffsetPair *data;
-     size_t i;
- 
-+    assert (offset_cache);
-+    data = offset_cache->data;
-     for (i = 0; i < offset_cache->size; ++i) {
-         if (data[i].key == key) {
-             return data[i].offset;
-@@ -70,6 +74,7 @@ void _Xi18nSetPropertyOffset (Xi18nOffsetCache *offset_cache, Atom key,
-     Xi18nAtomOffsetPair *data = offset_cache->data;
-     size_t i;
- 
-+    assert (data != NULL);
-     for (i = 0; i < offset_cache->size; ++i) {
-         if (data[i].key == key) {
-             data[i].offset = offset;
-@@ -79,11 +84,19 @@ void _Xi18nSetPropertyOffset (Xi18nOffsetCache *offset_cache, Atom key,
- 
-     if (++offset_cache->size > offset_cache->capacity) {
-         offset_cache->capacity *= OFFSET_CACHE_GROWTH_FACTOR;
--        offset_cache->data = data = (Xi18nAtomOffsetPair *) realloc (data,
-+        offset_cache->data = (Xi18nAtomOffsetPair *) realloc (data,
-                 offset_cache->capacity * sizeof (Xi18nAtomOffsetPair));
-+        if (offset_cache->data == NULL) {
-+            offset_cache->data = data;
-+            --offset_cache->size;
-+        }
-+        data = offset_cache->data;
-     }
- 
--    data[i].key = key;
--    data[i].offset = offset;
-+    assert (data != NULL);
-+    if (offset_cache->size > 0) {
-+        data[i].key = key;
-+        data[i].offset = offset;
-+    }
- }
- 
-diff --git a/util/IMdkit/i18nPtHdr.c b/util/IMdkit/i18nPtHdr.c
-index 2e673541..eaeeee1c 100644
---- a/util/IMdkit/i18nPtHdr.c
-+++ b/util/IMdkit/i18nPtHdr.c
-@@ -110,6 +110,7 @@ static void ConnectMessageProc (XIMS ims,
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return;
-     }
-     /*endif*/
-@@ -230,6 +231,7 @@ static void OpenMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p)
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return;
-     }
-     /*endif*/
-@@ -312,6 +314,7 @@ static void CloseMessageProc (XIMS ims,
-                            0,
-                            0,
-                            0);
-+        FrameMgrFree (fm);
-         return;
-     }
-     /*endif*/
-@@ -513,6 +516,10 @@ static void QueryExtensionMessageProc (XIMS ims,
-                            0,
-                            0,
-                            0);
-+        FrameMgrFree (fm);
-+        for (i = 0;  i < reply_number;  i++)
-+            XFree (ext_list[i].name);
-+        XFree ((char *) ext_list);
-         return;
-     }
-     /*endif*/
-@@ -610,8 +617,10 @@ static void GetIMValueFromName (Xi18n i18n_core,
- 
-             total_size = FrameMgrGetTotalSize (fm);
-             data = (unsigned char *) malloc (total_size);
--            if (!data)
-+            if (!data) {
-+                FrameMgrFree (fm);
-                 return;
-+            }
-             /*endif*/
-             memset (data, 0, total_size);
-             FrameMgrSetBuffer (fm, data);
-@@ -666,11 +675,12 @@ static XIMAttribute *MakeIMAttributeList (Xi18n i18n_core,
-         /*endfor*/
-     }
-     /*endfor*/
--    attrib_list = (XIMAttribute *) malloc (sizeof (XIMAttribute)*list_num);
-+    attrib_list =
-+            (XIMAttribute *) malloc (sizeof (XIMAttribute)*(list_num + 1));
-     if (!attrib_list)
-         return NULL;
-     /*endif*/
--    memset (attrib_list, 0, sizeof (XIMAttribute)*list_num);
-+    memset (attrib_list, 0, sizeof (XIMAttribute)*(list_num + 1));
-     number_ret = list_num;
-     list_num = 0;
-     for (i = 0;  i < *number;  i++)
-@@ -805,6 +815,10 @@ static void GetIMValuesMessageProc (XIMS ims,
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-+        for (i = 0; i < iter_count; i++)
-+            XFree(im_attribute_list[i].value);
-+        XFree (im_attribute_list);
-         return;
-     }
-     /*endif*/
-@@ -961,6 +975,7 @@ static void DestroyICMessageProc (XIMS ims,
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return;
-     }
-     /*endif*/
-@@ -1026,6 +1041,7 @@ static void ResetICMessageProc (XIMS ims,
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return;
-     }
-     /*endif*/
-@@ -1072,7 +1088,7 @@ static int WireEventToEvent (Xi18n i18n_core,
-     /* get & set serial */
-     FrameMgrGetToken(fm, c16);
-     ev->xany.serial = (unsigned long)c16;
--    ev->xany.serial |= serial << 16;
-+    ev->xany.serial |= ((unsigned long)serial) << 16;
-     ev->xany.send_event = False;
-     ev->xany.display = i18n_core->address.dpy;
- 
-@@ -1308,6 +1324,7 @@ static void TriggerNotifyMessageProc (XIMS ims,
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return;
-     }
-     /*endif*/
-@@ -1443,7 +1460,7 @@ static void EncodingNegotiatonMessageProc (XIMS ims,
-     if (byte_length > 0)
-     {
-         enc_nego->encodinginfo = (XIMStr *) malloc (sizeof (XIMStr)*10);
--        memset (enc_nego->encoding, 0, sizeof (XIMStr)*10);
-+        memset (enc_nego->encodinginfo, 0, sizeof (XIMStr)*10);
-         i = 0;
-         while (FrameMgrIsIterLoopEnd (fm, &status) == False)
-         {
-@@ -1488,6 +1505,7 @@ static void EncodingNegotiatonMessageProc (XIMS ims,
-     if (!reply)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return;
-     }
-     /*endif*/
-diff --git a/util/IMdkit/i18nUtil.c b/util/IMdkit/i18nUtil.c
-index 6557bd1a..109dcdf9 100644
---- a/util/IMdkit/i18nUtil.c
-+++ b/util/IMdkit/i18nUtil.c
-@@ -148,6 +148,7 @@ void _Xi18nSendMessage (XIMS ims,
-     if (reply_hdr == NULL)
-     {
-         _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0);
-+        FrameMgrFree (fm);
-         return;
-     }
-     /*endif*/
-@@ -163,7 +164,8 @@ void _Xi18nSendMessage (XIMS ims,
-     replyp = reply;
-     memmove (reply, reply_hdr, header_size);
-     replyp += header_size;
--    memmove (replyp, data, length);
-+    if (length > 0 && data != NULL)
-+        memmove (replyp, data, length);
- 
-     i18n_core->methods.send (ims, connect_id, reply, reply_length);
- 
-@@ -202,8 +204,10 @@ void _Xi18nSendTriggerKey (XIMS ims, CARD16 connect_id)
-     total_size = FrameMgrGetTotalSize (fm);
- 
-     reply = (unsigned char *) malloc (total_size);
--    if (!reply)
-+    if (!reply) {
-+        FrameMgrFree (fm);
-         return;
-+    }
-     /*endif*/
-     memset (reply, 0, total_size);
-     FrameMgrSetBuffer (fm, reply);
-@@ -257,8 +261,10 @@ void _Xi18nSetEventMask (XIMS ims,
- 
-     total_size = FrameMgrGetTotalSize (fm);
-     reply = (unsigned char *) malloc (total_size);
--    if (!reply)
-+    if (!reply) {
-+        FrameMgrFree (fm);
-         return;
-+    }
-     /*endif*/
-     memset (reply, 0, total_size);
-     FrameMgrSetBuffer (fm, reply);
-diff --git a/util/IMdkit/i18nX.c b/util/IMdkit/i18nX.c
-index 8385aba9..5e5c15fa 100644
---- a/util/IMdkit/i18nX.c
-+++ b/util/IMdkit/i18nX.c
-@@ -31,6 +31,7 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-  
- ******************************************************************/
- 
-+#include <assert.h>
- #include <stddef.h>
- #include <limits.h>
- #include <X11/Xlib.h>
-@@ -92,6 +93,7 @@ static unsigned char *ReadXIMMessage (XIMS ims,
-         client = client->next;
-     }
- 
-+    assert (client);
-     if (ev->format == 8) {
-         /* ClientMessage only */
-         XimProtoHdr *hdr = (XimProtoHdr *) ev->data.b;
-@@ -158,6 +160,7 @@ static unsigned char *ReadXIMMessage (XIMS ims,
-         /* The property data is retrieved in 32-bit chunks */
-         long_begin = offset / 4;
-         long_end = (end + 3) / 4;
-+        assert (x_client);
-         return_code = XGetWindowProperty (i18n_core->address.dpy,
-                                           x_client->accept_win,
-                                           atom,
-@@ -276,11 +279,11 @@ static Bool Xi18nXEnd(XIMS ims)
- static char *MakeNewAtom (CARD16 connect_id, char *atomName)
- {
-     static int sequence = 0;
--    
-     sprintf (atomName,
-              "_server%d_%d",
-              connect_id,
--             ((sequence > 20)  ?  (sequence = 0)  :  sequence++));
-+             ((sequence > 20)  ?  (sequence = 0)  :  (0x1f & sequence)));
-+    sequence++;
-     return atomName;
- }
- 
-@@ -418,13 +421,16 @@ static Bool Xi18nXWait (XIMS ims,
-                 &&
-                 (hdr->minor_opcode == minor_opcode))
-             {
-+                XFree (packet);
-                 return True;
-             }
-             else if (hdr->major_opcode == XIM_ERROR)
-             {
-+                XFree (packet);
-                 return False;
-             }
-             /*endif*/
-+            XFree (packet);
-         }
-         /*endif*/
-     }
--- 
-2.17.1
-
-From be7554cea294aa13a65895b66b26e5f1fa4a1897 Mon Sep 17 00:00:00 2001
-From: Ryutaroh Matsumoto
- <36657667+ryutaroh-matsumoto@users.noreply.github.com>
-Date: Thu, 2 Aug 2018 08:10:04 +0900
-Subject: [PATCH] option --monitor-timeout should be removed
-
-ibus-daemon(1) has explanation of --monitor-timeout, but main.c does not accept it and make an error.
----
- bus/ibus-daemon.1.in | 3 ---
- 1 file changed, 3 deletions(-)
-
-diff --git a/bus/ibus-daemon.1.in b/bus/ibus-daemon.1.in
-index 2dc982b2..a3d0d03a 100644
---- a/bus/ibus-daemon.1.in
-+++ b/bus/ibus-daemon.1.in
-@@ -62,9 +62,6 @@ auto, refresh, none is available.
- \fB\-o\fR, \fB\-\-timeout\fR=\fItimeout\fR [default is 2000]
- dbus reply timeout in milliseconds.
- .TP
--\fB\-j\fR, \fB\-\-monitor\-timeout\fR=\fItimeout\fR [default is 0]
--timeout of poll changes of engines in seconds. 0 to disable it.
--.TP
- \fB\-m\fR, \fB\-\-mem\-profile\fR
- enable memory profile, send SIGUSR2 to print out the memory profile.
- .TP
--- 
-2.17.1
-
-From 5f44e7307771685c70202f996e39e9aa68d48d2e Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Fri, 3 Aug 2018 14:58:10 +0900
-Subject: [PATCH] data/dconf: Add man pages of 00-upstream-settings(5) and
- ibus(5)
-
-Also delete --mem-profile option in ibus-daemon(1)
----
- bus/ibus-daemon.1.in                 |  3 --
- data/dconf/00-upstream-settings.5.in | 40 ++++++++++++++++++++++
- data/dconf/Makefile.am               | 50 ++++++++++++++++++----------
- data/dconf/ibus.5.in                 | 39 ++++++++++++++++++++++
- ui/gtk3/ibus-emoji.7.in              |  6 ++--
- 5 files changed, 114 insertions(+), 24 deletions(-)
- create mode 100644 data/dconf/00-upstream-settings.5.in
- create mode 100644 data/dconf/ibus.5.in
-
-diff --git a/bus/ibus-daemon.1.in b/bus/ibus-daemon.1.in
-index a3d0d03a..ed975aed 100644
---- a/bus/ibus-daemon.1.in
-+++ b/bus/ibus-daemon.1.in
-@@ -62,9 +62,6 @@ auto, refresh, none is available.
- \fB\-o\fR, \fB\-\-timeout\fR=\fItimeout\fR [default is 2000]
- dbus reply timeout in milliseconds.
- .TP
--\fB\-m\fR, \fB\-\-mem\-profile\fR
--enable memory profile, send SIGUSR2 to print out the memory profile.
--.TP
- \fB\-v\fR, \fB\-\-verbose\fR
- verbose.
- 
-diff --git a/data/dconf/00-upstream-settings.5.in b/data/dconf/00-upstream-settings.5.in
-new file mode 100644
-index 00000000..b7a56fda
---- /dev/null
-+++ b/data/dconf/00-upstream-settings.5.in
-@@ -0,0 +1,40 @@
-+.\" This file is distributed under the same license as the ibus
-+.\" package.
-+.\" Copyright (C) Takao Fujiwara <takao.fujiwara1@gmail.com>, 2018.
-+.\"
-+.TH 00\-UPSTREAM\-SETTINGS "5" "August 2018" "@VERSION@" "User Commands"
-+.SH NAME
-+.B 00\-upstream\-settings
-+\- dconf configuration file
-+
-+.SH SYNOPSIS
-+.B /etc/dconf/db/ibus.d/00\-upstream\-settings
-+
-+.SH DESCRIPTION
-+
-+.PP
-+IBus is an Intelligent Input Bus. It is a new input framework for Linux
-+OS. It provides full featured and user friendly input method user
-+interface.  It also may help developers to develop input method easily.
-+
-+.PP
-+.B 00\-upstream\-settings
-+is a text configuration file of dconf and can be converted to
-+/etc/dconf/db/ibus by
-+.B dconf update
-+command with a write privilege in /etc/dconf/db. /etc/dconf/db/ibus is a
-+database file of dconf and saves the IBus default settings. The saved keys
-+and values can be readed by dconf command.
-+
-+.PP
-+.RS 4
-+.nf
-+env DCONF_PROFILE=ibus dconf list /desktop/ibus/
-+.RE
-+
-+.SH BUGS
-+If you find a bug, please report it at https://github.com/ibus/ibus/issues
-+
-+.SH "SEE ALSO"
-+.BR dconf (1)
-+.BR ibus (5)
-diff --git a/data/dconf/Makefile.am b/data/dconf/Makefile.am
-index 7f0d0fd8..433d9937 100644
---- a/data/dconf/Makefile.am
-+++ b/data/dconf/Makefile.am
-@@ -4,7 +4,7 @@
- #
- # Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
- # Copyright (c) 2011 Daiki Ueno <ueno@unixuser.org>
--# Copyright (c) 2007-2011 Red Hat, Inc.
-+# 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
-@@ -28,22 +28,6 @@ dist_gsettingsconvert_DATA = ibus.convert
- @GSETTINGS_RULES@
- @INTLTOOL_XML_NOMERGE_RULE@
- 
--EXTRA_DIST = \
--	$(gsettings_schemas_in_files) \
--	make-dconf-override-db.sh \
--	profile/ibus \
--	00-upstream-settings \
--	$(NULL)
--
--CLEANFILES = \
--	$(gsettings_SCHEMAS) \
--	$(NULL)
--
--MAINTAINERCLEANFILES = \
--	$(gsettings_schemas_in_files) \
--	00-upstream-settings \
--	$(NULL)
--
- dconfprofiledir = $(sysconfdir)/dconf/profile
- dconfprofile_DATA = profile/ibus
- 
-@@ -60,9 +44,39 @@ org.freedesktop.ibus.gschema.xml.in: $(top_srcdir)/data/ibus.schemas.in
- 	$(AM_V_GEN) $(srcdir)/make-dconf-override-db.sh > $@ || \
- 		{ rc=$$?; $(RM) -rf $@; exit $$rc; }
- 
-+man_5_in_files = 00-upstream-settings.5.in ibus.5.in
-+man_5_files = $(man_5_in_files:.5.in=.5)
-+man_5_DATA =$(man_5_files:.5=.5.gz)
-+man_5dir = $(mandir)/man5
-+%.5: %.5.in
-+	$(AM_V_GEN) sed \
-+	    -e 's|@VERSION[@]|$(VERSION)|g' $< > $@.tmp && \
-+	    mv $@.tmp $@
-+%.5.gz: %.5
-+	$(AM_V_GEN) gzip -c $< > $@.tmp && mv $@.tmp $@
-+
- install-data-hook:
- 	if test -z "$(DESTDIR)"; then \
--		dconf update; \
-+	    dconf update; \
- 	fi
- 
-+EXTRA_DIST = \
-+    $(gsettings_schemas_in_files) \
-+    $(man_5_in_files) \
-+    make-dconf-override-db.sh \
-+    profile/ibus \
-+    00-upstream-settings \
-+    $(NULL)
-+
-+CLEANFILES = \
-+    $(gsettings_SCHEMAS) \
-+    $(man_5_DATA) \
-+    $(man_5_files) \
-+    $(NULL)
-+
-+MAINTAINERCLEANFILES = \
-+    $(gsettings_schemas_in_files) \
-+    00-upstream-settings \
-+    $(NULL)
-+
- -include $(top_srcdir)/git.mk
-diff --git a/data/dconf/ibus.5.in b/data/dconf/ibus.5.in
-new file mode 100644
-index 00000000..d959c7e3
---- /dev/null
-+++ b/data/dconf/ibus.5.in
-@@ -0,0 +1,39 @@
-+.\" This file is distributed under the same license as the ibus
-+.\" package.
-+.\" Copyright (C) Takao Fujiwara <takao.fujiwara1@gmail.com>, 2018.
-+.\"
-+.TH IBUS "5" "August 2018" "@VERSION@" "User Commands"
-+.SH NAME
-+.B IBUS
-+\- dconf database file for IBus
-+
-+.SH SYNOPSIS
-+.B /etc/dconf/db/ibus
-+
-+.SH DESCRIPTION
-+
-+.PP
-+IBus is an Intelligent Input Bus. It is a new input framework for Linux
-+OS. It provides full featured and user friendly input method user
-+interface.  It also may help developers to develop input method easily.
-+
-+.PP
-+.B /etc/dconf/db/ibus
-+is a database file dconf and saves the IBus default settings. It can be
-+generated from /etc/dconf/db/ibus.d/00\-upstream\-settings by
-+.B dconf update
-+command with a write privilege in /etc/dconf/db. The saved keys
-+and values can be readed by dconf command.
-+
-+.PP
-+.RS 4
-+.nf
-+env DCONF_PROFILE=ibus dconf list /desktop/ibus/
-+.RE
-+
-+.SH BUGS
-+If you find a bug, please report it at https://github.com/ibus/ibus/issues
-+
-+.SH "SEE ALSO"
-+.BR dconf (1)
-+.BR 00\-upstream\-settings (5)
-diff --git a/ui/gtk3/ibus-emoji.7.in b/ui/gtk3/ibus-emoji.7.in
-index 3a2db2c0..b8b43574 100644
---- a/ui/gtk3/ibus-emoji.7.in
-+++ b/ui/gtk3/ibus-emoji.7.in
-@@ -1,10 +1,10 @@
- .\" This file is distributed under the same license as the ibus
- .\" package.
--.\" Copyright (C) Takao Fujiwara <takao.fujiwara1@gmail.com>, 2017.
-+.\" Copyright (C) Takao Fujiwara <takao.fujiwara1@gmail.com>, 2017-2018.
- .\"
--.TH "IBUS EMOJI" 1 "May 2017" "@VERSION@" "User Commands"
-+.TH "IBUS EMOJI" 1 "August 2018" "@VERSION@" "User Commands"
- .SH NAME
--.B ibus emoji utility
-+.B ibus-emoji
- \- Call the IBus emoji utility by
- .B IBus Emojier
- 
--- 
-2.17.1
-
-From f328fd67f479faa46ca87bf3c85eed7080ec5ec0 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Mon, 6 Aug 2018 12:33:44 +0900
-Subject: [PATCH] client/gtk2: Add IBUS_DISCARD_PASSWORD for firefox and
- chrome
-
-popup window in firefox is closed in Xorg GNOME when password entry
-is focus on. It's caused by gnome-shell [1].
-Now IBUS_DISCARD_PASSWORD and IBUS_DISCARD_PASSWORD_APPS enviroment
-variables are implemented in IBus GTK clients as a workaround.
-
-env IBUS_DISCARD_PASSWORD=1 firefox
-or
-export IBUS_DISCARD_PASSWORD_APPS='firefox,.*chrome.*'
-
-can discard typing characters on the password entries.
-
-[1] https://gitlab.gnome.org/GNOME/gnome-shell/issues/391
-
-BUG=https://github.com/ibus/ibus/issues/2002
----
- client/gtk2/ibusimcontext.c | 77 ++++++++++++++++++++++++++++---------
- 1 file changed, 58 insertions(+), 19 deletions(-)
-
-diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
-index a806382d..e4de52d9 100644
---- a/client/gtk2/ibusimcontext.c
-+++ b/client/gtk2/ibusimcontext.c
-@@ -91,6 +91,9 @@ static guint    _key_snooper_id = 0;
- 
- static gboolean _use_sync_mode = FALSE;
- 
-+static const gchar *_discard_password_apps  = "";
-+static gboolean _use_discard_password = FALSE;
-+
- static GtkIMContext *_focus_im_context = NULL;
- static IBusInputContext *_fake_context = NULL;
- static GdkWindow *_input_window = NULL;
-@@ -157,7 +160,7 @@ static gboolean _slave_delete_surrounding_cb
-                                              IBusIMContext      *context);
- static void     _request_surrounding_text   (IBusIMContext      *context);
- static void     _create_fake_input_context  (void);
--static void     _set_content_type           (IBusIMContext      *context);
-+static gboolean _set_content_type           (IBusIMContext      *context);
- 
- 
- 
-@@ -383,7 +386,7 @@ _request_surrounding_text (IBusIMContext *context)
-     }
- }
- 
--static void
-+static gboolean
- _set_content_type (IBusIMContext *context)
- {
- #if GTK_CHECK_VERSION (3, 6, 0)
-@@ -396,11 +399,18 @@ _set_content_type (IBusIMContext *context)
-                       "input-hints", &hints,
-                       NULL);
- 
-+        if (_use_discard_password) {
-+            if (purpose == GTK_INPUT_PURPOSE_PASSWORD ||
-+                purpose == GTK_INPUT_PURPOSE_PIN) {
-+                return FALSE;
-+            }
-+        }
-         ibus_input_context_set_content_type (context->ibuscontext,
-                                              purpose,
-                                              hints);
-     }
- #endif
-+    return TRUE;
- }
- 
- 
-@@ -608,24 +618,45 @@ ibus_im_context_class_init (IBusIMContextClass *class)
-     _use_key_snooper = !_get_boolean_env ("IBUS_DISABLE_SNOOPER",
-                                           !(ENABLE_SNOOPER));
-     _use_sync_mode = _get_boolean_env ("IBUS_ENABLE_SYNC_MODE", FALSE);
-+    _use_discard_password = _get_boolean_env ("IBUS_DISCARD_PASSWORD", FALSE);
-+
-+#define CHECK_APP_IN_CSV_ENV_VARIABLES(retval,                          \
-+                                       env_apps,                        \
-+                                       fallback_apps,                   \
-+                                       value_if_found)                  \
-+{                                                                       \
-+    const gchar * prgname = g_get_prgname ();                           \
-+    gchar **p;                                                          \
-+    gchar ** apps;                                                      \
-+    if (g_getenv ((#env_apps))) {                                       \
-+        fallback_apps = g_getenv (#env_apps);                           \
-+    }                                                                   \
-+    apps = g_strsplit ((fallback_apps), ",", 0);                        \
-+    for (p = apps; *p != NULL; p++) {                                   \
-+        if (g_regex_match_simple (*p, prgname, 0, 0)) {                 \
-+            retval = (value_if_found);                                  \
-+            break;                                                      \
-+        }                                                               \
-+    }                                                                   \
-+    g_strfreev (apps);                                                  \
-+}
- 
-     /* env IBUS_DISABLE_SNOOPER does not exist */
-     if (_use_key_snooper) {
-         /* disable snooper if app is in _no_snooper_apps */
--        const gchar * prgname = g_get_prgname ();
--        if (g_getenv ("IBUS_NO_SNOOPER_APPS")) {
--            _no_snooper_apps = g_getenv ("IBUS_NO_SNOOPER_APPS");
--        }
--        gchar **p;
--        gchar ** apps = g_strsplit (_no_snooper_apps, ",", 0);
--        for (p = apps; *p != NULL; p++) {
--            if (g_regex_match_simple (*p, prgname, 0, 0)) {
--                _use_key_snooper = FALSE;
--                break;
--            }
--        }
--        g_strfreev (apps);
-+        CHECK_APP_IN_CSV_ENV_VARIABLES (_use_key_snooper,
-+                                        IBUS_NO_SNOOPER_APPS,
-+                                        _no_snooper_apps,
-+                                        FALSE);
-     }
-+    if (!_use_discard_password) {
-+        CHECK_APP_IN_CSV_ENV_VARIABLES (_use_discard_password,
-+                                        IBUS_DISCARD_PASSWORD_APPS,
-+                                        _discard_password_apps,
-+                                        TRUE);
-+    }
-+
-+#undef CHECK_APP_IN_CSV_ENV_VARIABLES
- 
-     /* init bus object */
-     if (_bus == NULL) {
-@@ -926,7 +957,10 @@ ibus_im_context_focus_in (GtkIMContext *context)
- 
-     ibusimcontext->has_focus = TRUE;
-     if (ibusimcontext->ibuscontext) {
--        _set_content_type (ibusimcontext);
-+        if (!_set_content_type (ibusimcontext)) {
-+            ibusimcontext->has_focus = FALSE;
-+            return;
-+        }
-         ibus_input_context_focus_in (ibusimcontext->ibuscontext);
-     }
- 
-@@ -958,9 +992,14 @@ ibus_im_context_focus_out (GtkIMContext *context)
-         return;
-     }
- 
--    g_object_remove_weak_pointer ((GObject *) context,
--                                  (gpointer *) &_focus_im_context);
--    _focus_im_context = NULL;
-+    /* If _use_discard_password is TRUE or GtkEntry has no visibility,
-+     * _focus_im_context is NULL.
-+     */
-+    if (_focus_im_context) {
-+        g_object_remove_weak_pointer ((GObject *) context,
-+                                      (gpointer *) &_focus_im_context);
-+        _focus_im_context = NULL;
-+    }
- 
-     ibusimcontext->has_focus = FALSE;
-     if (ibusimcontext->ibuscontext) {
--- 
-2.17.1
-
-From dc5e7eeba30d0bc2327ffa562cdf6ca0ae23aecc Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Mon, 6 Aug 2018 15:26:42 +0900
-Subject: [PATCH] ui/gtk3: Show previous emojis with "history" annotation
-
----
- ui/gtk3/emojier.vala | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
-diff --git a/ui/gtk3/emojier.vala b/ui/gtk3/emojier.vala
-index 7beb6f0a..85dcdceb 100644
---- a/ui/gtk3/emojier.vala
-+++ b/ui/gtk3/emojier.vala
-@@ -1294,8 +1294,14 @@ public class IBusEmojier : Gtk.ApplicationWindow {
-             return;
-         }
-         string? unicode_point = check_unicode_point(annotation);
--        GLib.SList<string>? total_emojis =
--            lookup_emojis_from_annotation(annotation);
-+        GLib.SList<string>? total_emojis = null;
-+        if (annotation.ascii_casecmp("history") == 0) {
-+            for (int i = 0; i < m_favorites.length; i++) {
-+                total_emojis.append(m_favorites[i].dup());
-+            }
-+        }
-+        if (total_emojis == null)
-+            total_emojis = lookup_emojis_from_annotation(annotation);
-         if (total_emojis == null) {
-             /* Users can type title strings against lower case.
-              * E.g. "Smile" against "smile"
--- 
-2.17.1
-
-From 428e64eac8f7dc3ff60234435fe5f34d50126432 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Mon, 6 Aug 2018 15:59:06 +0900
-Subject: [PATCH] src: Describe "default" layout in ibus_engine_desc_new()
-
-BUG=https://github.com/ibus/ibus/issues/2011
----
- src/ibusenginedesc.h | 11 ++++++++++-
- 1 file changed, 10 insertions(+), 1 deletion(-)
-
-diff --git a/src/ibusenginedesc.h b/src/ibusenginedesc.h
-index 45ec06bf..00a98e41 100644
---- a/src/ibusenginedesc.h
-+++ b/src/ibusenginedesc.h
-@@ -2,7 +2,8 @@
- /* vim:set et sts=4: */
- /* bus - The Input Bus
-  * Copyright (C) 2008-2015 Peng Huang <shawn.p.huang@gmail.com>
-- * Copyright (C) 2008-2015 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
-@@ -107,6 +108,10 @@ GType            ibus_engine_desc_get_type      (void);
-  * @layout: Keyboard layout
-  *
-  * Creates a new #IBusEngineDesc.
-+ * If layout is "default", the engine inherits the current layout and
-+ * does not change the layout. The layouts "default" and "" are same.
-+ * E.g. If you switch JP XKB engine and an input method engine (IME),
-+ * the IME inherits the JP layout.
-  *
-  * Returns: A newly allocated IBusEngineDesc.
-  */
-@@ -128,6 +133,10 @@ IBusEngineDesc  *ibus_engine_desc_new           (const gchar    *name,
-  * ibus_engine_desc_new_varargs() supports the va_list format.
-  * name property is required. e.g.
-  * ibus_engine_desc_new_varargs("name", "ibus-foo", "language", "us", NULL)
-+ * If layout is "default", the engine inherits the current layout and
-+ * does not change the layout. The layouts "default" and "" are same.
-+ * E.g. If you switch JP XKB engine and an input method engine (IME),
-+ * the IME inherits the JP layout.
-  *
-  * Returns: A newly allocated IBusEngineDesc.
-  */
--- 
-2.17.1
-

                 reply	other threads:[~2026-05-31  2:06 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178019321700.1.14459109162438851166.rpms-ibus-3032216b57aa@fedoraproject.org \
    --to=tfujiwar@redhat.com \
    --cc=git-commits@fedoraproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox