From 3032216b57aac3d11c9d6323228d7a58a8b309aa Mon Sep 17 00:00:00 2001 From: Takao Fujiwara Date: Wed, 8 Aug 2018 20:07:39 +0900 Subject: [PATCH] Deleted upstreamed patches --- ibus-HEAD.patch | 11241 ---------------------------------------------- 1 file changed, 11241 deletions(-) delete mode 100644 ibus-HEAD.patch 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 -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 -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? total_emojis = null; - unowned GLib.SList? sub_emojis = null; -+ unowned GLib.SList? sub_exact_unicodes = null; - unowned GLib.SList? sub_unicodes = null; - int length = annotation.length; - if (m_has_partial_match && length >= m_partial_match_length) { -+ GLib.SList? 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? 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 -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 . ---- - 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 -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 -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 -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 --# Copyright (c) 2007-2015 Red Hat, Inc. -+# Copyright (c) 2015-2018 Takao Fujiwara -+# Copyright (c) 2007-2018 Red Hat, Inc. - # - # This library is free software; you can redistribute it and/or - # modify it under the terms of the GNU Lesser General Public -@@ -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 -+# 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 -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 -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 -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 -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 - # Copyright (c) 2014-2016 Peng Huang -+# Copyright (c) 2018 Takao Fujiwara -+# 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 -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 -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 -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 -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 -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 -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 -+#include -+#include "ibus.h" -+#include -+#include -+#include -+ -+#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 ", -+ "https://github.com/ibus/ibus/wiki", -+ "", -+ "ibus"); -+ desc = ibus_engine_desc_new ( -+ "xkbtest:us::eng", -+ "XKB Test", -+ "XKB Test", -+ "en", -+ "GPL", -+ "Takao Fujiwara ", -+ "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 -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 -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 -- * Copyright(c) 2015-2017 Takao Fujiwara -+ * Copyright(c) 2015-2018 Takao Fujiwara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -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 -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 -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 -- * Copyright(c) 2015-2017 Takao Fujiwara -+ * Copyright(c) 2015-2018 Takao Fujiwara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -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 get_ibus_schemas() { -+ string[] ids = {}; -+ if (engine_id != null) { -+ ids = engine_id.split(","); -+ } -+ GLib.SList ibus_schemas = new GLib.SList(); -+ 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 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 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 -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 @@ - 0 - none - -- -+ - True - False -- 5 -- 2 - 12 - 6 - 6 -@@ -117,8 +115,8 @@ - Next input method: - - -- GTK_FILL -- GTK_FILL -+ 0 -+ 0 - - - -@@ -131,10 +129,8 @@ - Previous input method: - - -+ 0 - 1 -- 2 -- GTK_FILL -- GTK_FILL - - - -@@ -143,6 +139,7 @@ - True - False - 6 -+ True - - - True -@@ -174,8 +171,7 @@ - - - 1 -- 2 -- GTK_FILL -+ 0 - - - -@@ -184,6 +180,7 @@ - True - False - 6 -+ True - - - > True -@@ -217,10 +214,7 @@ - - - 1 -- 2 - 1 -- 2 -- GTK_FILL - - - -@@ -232,10 +226,8 @@ - Enable or disable: - - -+ 0 - 2 -- 3 -- GTK_FILL -- GTK_FILL - - - -@@ -246,10 +238,8 @@ - Enable: - - -+ 0 - 3 -- 4 -- GTK_FILL -- GTK_FILL - - - -@@ -258,6 +248,7 @@ - True - False - 6 -+ True - - - True -@@ -289,10 +280,7 @@ - - - 1 -- 2 - 3 -- 4 -- GTK_FILL - - - -@@ -303,10 +291,8 @@ - Disable: - - -+ 0 - 4 -- 5 -- GTK_FILL -- GTK_FILL - - - -@@ -315,6 +301,7 @@ - True - False - 6 -+ True - - - True -@@ -346,10 +333,7 @@ - - - 1 -- 2 - 4 -- 5 -- GTK_FILL - - - -@@ -376,11 +360,9 @@ - 0 - none - -- -+ - True - False -- 7 -- 2 - 12 - 6 - 6 -@@ -393,10 +375,11 @@ - start - Candidates orientation: - right -+ True - - -- GTK_FILL -- GTK_FILL -+ 0 -+ 0 - - - -@@ -404,6 +387,7 @@ - True - False - model_candidates_orientation -+ True - - - -@@ -413,8 +397,7 @@ - - - 1 -- 2 -- GTK_FILL -+ 0 - - - -@@ -425,12 +408,11 @@ - start - Show property panel: - right -+ True - - -+ 0 - 1 -- 2 -- GTK_FILL -- GTK_FILL - - - -@@ -440,12 +422,11 @@ - start - Language panel position: - right -+ True - - -+ 0 - 2 -- 3 -- GTK_FILL -- GTK_FILL - - - -@@ -453,6 +434,7 @@ - True - False - model_panel_show_mode -+ True - - - -@@ -462,10 +444,7 @@ - - - 1 -- 2 - 1 -- 2 -- GTK_FILL - - - -@@ -473,6 +452,7 @@ - False - True - model_panel_position -+ True - - - -@@ -482,10 +462,7 @@ - - - 1 -- 2 - 2 -- 3 -- GTK_FILL - - - -@@ -499,13 +476,12 @@ - False - start - True -+ True - - -- 2 -+ 0 - 3 -- 4 -- GTK_FILL -- GTK_FILL -+ 2 - - - -@@ -519,13 +495,12 @@ - False - start - True -+ True - - -- 2 -+ 0 - 4 -- 5 -- GTK_FILL -- GTK_FILL -+ 2 - - - -@@ -539,13 +514,12 @@ - False - start - True -+ True - - -- 2 -+ 0 - 5 -- 6 -- GTK_FILL -- GTK_FILL -+ 2 - - - -@@ -559,12 +533,11 @@ - True - start - True -+ True - - -+ 0 - 6 -- 7 -- GTK_FILL -- GTK_FILL - - - -@@ -573,13 +546,11 @@ - True - True - False -+ True - - - 1 -- 2 - 6 -- 7 -- GTK_FILL - - - -@@ -888,11 +859,9 @@ - 0 - none - -- -+ - True - False -- 5 -- 2 - 12 - 6 - 6 -@@ -906,8 +875,8 @@ - Emoji choice: - - -- GTK_FILL -- GTK_FILL -+ 0 -+ 0 - - - -@@ -916,6 +885,7 @@ - True - False - 6 -+ true - - - True -@@ -947,8 +917,7 @@ - - - 1 -- 2 -- GTK_FILL -+ 0 - - - --- -2.14.3 - -From 5ee3f48049ecf128391da6448ae7e74786bd171b Mon Sep 17 00:00:00 2001 -From: fujiwarat -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 --# Copyright (c) 2017 Takao Fujiwara -+# Copyright (c) 2017-2018 Takao Fujiwara - # 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 -- * Copyright (C) 2008-2013 Red Hat, Inc. -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -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 @@ - Custom font name for language panel - - -+ -+ /schemas/desktop/ibus/panel/emoji/unicode-hotkey -+ /desktop/ibus/panel/emoji/unicode-hotkey -+ ibus -+ list -+ string -+ [<Control><Shift>u] -+ -+ Unicode shortcut keys for gtk_accelerator_parse -+ The shortcut keys for turning Unicode typing on or off -+ -+ - - /schemas/desktop/ibus/panel/emoji/hotkey - /desktop/ibus/panel/emoji/hotkey -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 --# Copyright (c) 2010-2017 Takao Fujiwara -+# Copyright (c) 2010-2018 Takao Fujiwara - # 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 @@ - - True - False -- The shortcut keys for showing emoji dialog -+ The shortcut keys to enable conversions of emoji annotations or Unicode names - start -- Emoji choice: -+ Emoji annotation: - - - 0 -@@ -920,6 +920,60 @@ - 0 - - -+ -+ -+ True -+ False -+ The shortcut keys to enable Unicode code point conversions -+ start -+ Unicode code point: -+ -+ -+ 0 -+ 1 -+ -+ -+ -+ -+ horizontal -+ True -+ False -+ 6 -+ true -+ -+ -+ True -+ True -+ False -+ -+ -+ True -+ True -+ 0 -+ -+ -+ -+ -+ ... -+ False -+ True -+ True -+ False -+ False -+ True -+ -+ -+ False -+ True -+ 1 -+ -+ -+ -+ -+ 1 -+ 1 -+ -+ - - - -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[] = - " " - " " - " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " - /* FIXME signals */ - " " - " " -@@ -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[] = - " " - " " - " " -+ " " -+ " " -+ " " -+ " " -+ " " - " " - " " - " " -@@ -221,7 +229,16 @@ static const gchar introspection_xml[] = - " " - " " - " " -- " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " - " " - /* Signals */ - " " -@@ -247,7 +264,23 @@ static const gchar introspection_xml[] = - " " - " " - " " -+ " " -+ " " -+ " " - " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " - " " - " " - ""; -@@ -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(). -+ * -+ * Argument @user_data is ignored in this function. -+ * -+ */ -+ 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. -+ * -+ * Argument @user_data is ignored in this function. -+ * -+ */ -+ 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 categories = -- m_category_to_emojis_dict.get_keys(); -- // FIXME: How to cast GLib.CompareFunc 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 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? -+ private static GLib.SList? - lookup_emojis_from_annotation(string annotation) { - GLib.SList? total_emojis = null; - unowned GLib.SList? 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? 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 categories = -+ m_category_to_emojis_dict.get_keys(); -+ // FIXME: How to cast GLib.CompareFunc 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? 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 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? 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? 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? 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 -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 @@ - - True - False -- Set a font of emoji candidates on the emoji dialog -+ Set a font of Unicode candidates on the emoji dialog - start -- Emoji font: -+ Unicode font: - right - - -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 -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 -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 -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 -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 -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 -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 -- * Copyright (C) 2015-2017 Takao Fujiwara -+ * Copyright (C) 2015-2018 Takao Fujiwara - * 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 --# Copyright (c) 2007-2015 Red Hat, Inc. -+# Copyright (c) 2014-2018 Takao Fujiwara -+# Copyright (c) 2007-2018 Red Hat, Inc. - # - # This library is free software; you can redistribute it and/or - # modify it under the terms of the GNU Lesser General Public -@@ -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 --# Copyright (c) 2007-2010 Red Hat, Inc. -+# Copyright (c) 2018 Takao Fujiwara -+# Copyright (c) 2007-2018 Red Hat, Inc. - # - # This library is free software; you can redistribute it and/or - # modify it under the terms of the GNU Lesser General Public -@@ -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 -- * Copyright (C) 2015-2016 Takao Fujiwara -+ * Copyright (C) 2015-2018 Takao Fujiwara - * Copyright (C) 2008-2016 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or -@@ -22,6 +22,7 @@ - */ - - #include "ibusbus.h" -+#include - #include - #include - #include -@@ -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 -- * Copyright (C) 2013-2017 Takao Fujiwara -+ * Copyright (C) 2013-2018 Takao Fujiwara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -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 -- * Copyright (C) 2015-2017 Takao Fujiwara -+ * Copyright (C) 2015-2018 Takao Fujiwara - * 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 -- * Copyright (C) 2008-2010 Red Hat, Inc. -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -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 -- * Copyright (C) 2008-2010 Red Hat, Inc. -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -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 -- * Copyright (C) 2015 Takao Fujiwara -+ * Copyright (C) 2015-2018 Takao Fujiwara - * 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 -- * Copyright (C) 2008-2015 Red Hat, Inc. -+ * Copyright (C) 2015-2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -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 -- * Copyright (C) 2008-2015 Red Hat, Inc. -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -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 -+#include - #include - #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 -+#include - #include - #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 - #include - #include - #include -@@ -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 -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 , 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 - # Copyright (c) 2011 Daiki Ueno --# 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 , 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 , 2017. -+.\" Copyright (C) Takao Fujiwara , 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 -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 -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? total_emojis = -- lookup_emojis_from_annotation(annotation); -+ GLib.SList? 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 -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 -- * Copyright (C) 2008-2015 Red Hat, Inc. -+ * Copyright (C) 2011-2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -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 -