diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch index 0b56af7..05c3c97 100644 --- a/ibus-HEAD.patch +++ b/ibus-HEAD.patch @@ -1,6204 +1,3 @@ -From 214b60a3af67b6e8dafdb8edba666a369f18be12 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 26 Mar 2021 22:48:08 +0900 -Subject: [PATCH] src/tests: Run gnome-session with no-overview mode - -gnome-shell 40 now shows the overview mode by login and -gnome-desktop-testing-runner cannot get the input focus. -Running gnome-session with no-overview shell extension can -get the input focus or mutter is another option. -The default may be changed to twm if mutter also will be changed -not to accept the application focus in the future. - -Disable Tour dialog which prevent test application from getting the -input focus. - -Don't output FAIL if the actual failure is 0 for Fedora CI. - -BUG=https://discourse.gnome.org/t/focus-on-autostart-application-by-login/5863 ---- - src/tests/ibus-desktop-testing-runner.in | 69 ++++++++++++++++++++---- - 1 file changed, 60 insertions(+), 9 deletions(-) - -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index 4232c549..15b2369d 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -4,7 +4,7 @@ - # - # ibus - The Input Bus - # --# Copyright (c) 2018-2020 Takao Fujiwara -+# Copyright (c) 2018-2021 Takao Fujiwara - # Copyright (c) 2018 Red Hat, Inc. - # - # This program is free software; you can redistribute it and/or modify -@@ -36,7 +36,7 @@ - - - PROGNAME=`basename $0` --VERSION=0.1 -+VERSION=0.2 - DISPLAY=:99.0 - BUILDDIR="." - SRCDIR="." -@@ -80,7 +80,9 @@ usage() - "-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" \ -+"-d, --desktop=DESKTOP Run DESTKTOP. The default is gnome-session.\n" \ -+" Suffix '-with-dbus' can run DESKTOP with dbus session." \ -+" E.g. --desktop=mutter-with-dbus" \ - "-t, --tests=\"TESTS...\" Run TESTS programs which is separated by space\n" \ - "-r, --runner=RUNNER Run TESTS programs with a test RUNNER.\n" \ - " RUNNDER = gnome or default.\n" \ -@@ -115,6 +117,13 @@ parse_args() - * ) usage; exit 1;; - esac - done -+ DL='$' -+ echo "$DESKTOP_COMMAND" | grep "\-with\-dbus$DL" > /dev/null -+ HAS_DBUS_SUFFIX=$? -+ if [ $HAS_DBUS_SUFFIX -eq 0 ] ; then -+ DESKTOP_COMMAND=`echo "$DESKTOP_COMMAND" | sed -e 's/-with-dbus$//'` -+ DESKTOP_COMMAND="dbus-launch --exit-with-session $DESKTOP_COMMAND" -+ fi - } - - init_desktop() -@@ -124,8 +133,9 @@ init_desktop() - rm $RESULT_LOG - fi - fi -- HAS_STDOUT=`echo "$TEST_LOG" | grep ':stdout'` -- if [ x"$HAS_STDOUT" != x ] ; then -+ echo "$TEST_LOG" | grep ':stdout' > /dev/null -+ HAS_STDOUT=$? -+ if [ $HAS_STDOUT -eq 0 ] ; then - TEST_LOG=`echo "$TEST_LOG" | sed -e 's|:stdout||'` - TEST_LOG_STDOUT=1 - fi -@@ -203,6 +213,39 @@ run_dbus_daemon() - export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$UID/bus" - } - -+init_gnome() -+{ -+ # Disable Tour dialog to get focus -+ V=`gsettings get org.gnome.shell welcome-dialog-last-shown-version` -+ if [ x"$V" = x ] ; then -+ gsettings set org.gnome.shell welcome-dialog-last-shown-version '100' -+ fi -+ # gnome-shell now starts overview mode by login. -+ # https://extensions.gnome.org/extension/4099/no-overview/ -+ NO_SYS_DIR=/usr/share/gnome-shell/extensions/no-overview@fthx -+ NO_USER_DIR=$HOME/.local/share/gnome-shell/extensions/no-overview@fthx -+ if [ ! -d $NO_SYS_DIR ] && [ ! -d $NO_USER_DIR ] ; then -+ mkdir -p `dirname $NO_USER_DIR` -+ cp -R no-overview@fthx `dirname $NO_USER_DIR` -+ fi -+ V=`gsettings get org.gnome.shell disable-user-extensions` -+ if [ x"$V" = x"true" ] ; then -+ gsettings set org.gnome.shell disable-user-extensions false -+ fi -+ V=`gsettings get org.gnome.shell enabled-extensions` -+ echo "$V" | grep "no-overview" > /dev/null -+ V2=$? -+ if [ $V2 -ne 0 ] ; then -+ V3=`echo "$V" | sed -e 's/\[//' -e 's/\]//'` -+ if [ x"$V3" = x ] ; then -+ V4="['no-overview@fthx']" -+ else -+ V4="[$V3, 'no-overview@fthx']" -+ fi -+ gsettings set org.gnome.shell enabled-extensions "$V4" -+ fi -+} -+ - run_desktop() - { - if test $HAVE_GRAPHICS -eq 1 ; then -@@ -217,8 +260,11 @@ run_desktop() - $DESKTOP_COMMAND & - PID_GNOME_SESSION=$! - sleep 30 -- HAS_GNOME=`echo $DESKTOP_COMMAND | grep gnome-session` -- if [ x"$HAS_GNOME" = x ] ; then -+ echo "$DESKTOP_COMMAND" | grep gnome-session > /dev/null -+ HAS_GNOME=$? -+ if [ $HAS_GNOME -eq 0 ] ; then -+ init_gnome -+ else - ibus-daemon --daemonize --verbose - sleep 3 - fi -@@ -360,8 +406,13 @@ EOF_RUNNER - ;; - esac - echo "" -- print_log -e "${GREEN}PASS${NC}: $pass" -- print_log -e "${RED}FAIL${NC}: $fail" -+ # Fedora CI assumes the test is failed even if $fail is 0. -+ if [ $pass -ne 0 ] ; then -+ print_log -e "${GREEN}PASS${NC}: $pass" -+ fi -+ if [ $fail -ne 0 ] ; then -+ print_log -e "${RED}FAIL${NC}: $fail" -+ fi - echo "" - if [ $TEST_LOG_STDOUT -eq 1 ] ; then - cat $TEST_LOG --- -2.28.0 - -From d105a3941aad53b0c7470a1e9c1033987b029fb8 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Wed, 12 May 2021 18:54:30 +0900 -Subject: [PATCH] client/gtk2: Implement - ibus_im_context_set_surrounding_with_selection() - -Selection bounds need to be re-calculated when pre-edit text is -inserted and the selection position is changed. -GTK4 has a new API GtkIMContext.set_surrounding_with_selection() -to fix this issue and now IBus GTK module inherits the API. - -BUG=https://github.com/ibus/ibus/issues/2013 ---- - client/gtk2/ibusimcontext.c | 53 ++++++++++++++++++++++++++++++------- - 1 file changed, 44 insertions(+), 9 deletions(-) - -diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c -index e153081d..61194816 100644 ---- a/client/gtk2/ibusimcontext.c -+++ b/client/gtk2/ibusimcontext.c -@@ -2,8 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2015-2020 Takao Fujiwara -- * Copyright (C) 2008-2020 Red Hat, Inc. -+ * Copyright (C) 2015-2021 Takao Fujiwara -+ * Copyright (C) 2008-2021 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 -@@ -165,11 +165,19 @@ static void ibus_im_context_set_cursor_location - static void ibus_im_context_set_use_preedit - (GtkIMContext *context, - gboolean use_preedit); -+#if !GTK_CHECK_VERSION (4, 1, 2) - static void ibus_im_context_set_surrounding - (GtkIMContext *slave, - const gchar *text, -- gint len, -- gint cursor_index); -+ int len, -+ int cursor_index); -+#endif -+static void ibus_im_context_set_surrounding_with_selection -+ (GtkIMContext *slave, -+ const gchar *text, -+ int len, -+ int cursor_index, -+ int anchor_index); - - /* static methods*/ - static void _ibus_context_update_preedit_text_cb -@@ -724,7 +732,12 @@ ibus_im_context_class_init (IBusIMContextClass *class) - #endif - im_context_class->set_cursor_location = ibus_im_context_set_cursor_location; - im_context_class->set_use_preedit = ibus_im_context_set_use_preedit; -+#if GTK_CHECK_VERSION (4, 1, 2) -+ im_context_class->set_surrounding_with_selection -+ = ibus_im_context_set_surrounding_with_selection; -+#else - im_context_class->set_surrounding = ibus_im_context_set_surrounding; -+#endif - gobject_class->notify = ibus_im_context_notify; - gobject_class->finalize = ibus_im_context_finalize; - -@@ -1624,8 +1637,22 @@ get_selection_anchor_point (IBusIMContext *ibusimcontext, - static void - ibus_im_context_set_surrounding (GtkIMContext *context, - const gchar *text, -- gint len, -- gint cursor_index) -+ int len, -+ int cursor_index) -+{ -+ ibus_im_context_set_surrounding_with_selection (context, -+ text, -+ len, -+ cursor_index, -+ cursor_index); -+} -+ -+static void -+ibus_im_context_set_surrounding_with_selection (GtkIMContext *context, -+ const gchar *text, -+ int len, -+ int cursor_index, -+ int anchor_index) - { - g_return_if_fail (context != NULL); - g_return_if_fail (IBUS_IS_IM_CONTEXT (context)); -@@ -1647,18 +1674,26 @@ ibus_im_context_set_surrounding (GtkIMContext *context, - ibustext = ibus_text_new_from_string (p); - g_free (p); - -- guint anchor_pos = get_selection_anchor_point (ibusimcontext, -- cursor_pos, -- utf8_len); -+ gint anchor_pos = get_selection_anchor_point (ibusimcontext, -+ cursor_pos, -+ utf8_len); - ibus_input_context_set_surrounding_text (ibusimcontext->ibuscontext, - ibustext, - cursor_pos, - anchor_pos); - } -+#if GTK_CHECK_VERSION (4, 1, 2) -+ gtk_im_context_set_surrounding_with_selection (ibusimcontext->slave, -+ text, -+ len, -+ cursor_index, -+ anchor_index); -+#else - gtk_im_context_set_surrounding (ibusimcontext->slave, - text, - len, - cursor_index); -+#endif - } - - static void --- -2.28.0 - -From e9e1642870994abfdbd06b0138524ac231c159b8 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Wed, 16 Jun 2021 18:00:31 +0900 -Subject: [PATCH] Fix code reviews - ---- - bus/ibusimpl.c | 23 ++++-- - bus/server.c | 10 +-- - client/gtk2/ibusimcontext.c | 8 ++ - client/wayland/main.c | 9 ++- - client/x11/main.c | 22 +++-- - conf/dconf/main.c | 7 +- - portal/portal.c | 7 +- - setup/ibus-setup.in | 2 +- - src/emoji-parser.c | 46 ++++++----- - src/ibusaccelgroup.c | 2 +- - src/ibusbus.c | 10 ++- - src/ibuscomposetable.c | 91 ++++++++++++++++++--- - src/ibusemoji.c | 8 +- - src/ibusenginesimple.c | 21 +++-- - src/ibushotkey.c | 4 +- - src/ibusregistry.c | 9 ++- - src/ibusshare.c | 36 +++++---- - src/ibustext.c | 5 +- - src/ibusunicode.c | 17 +++- - src/tests/ibus-compose.c | 6 +- - src/tests/ibus-keypress.c | 3 +- - src/unicode-parser.c | 52 ++++++------ - util/IMdkit/FrameMgr.c | 34 +++++++- - util/IMdkit/i18nIc.c | 41 ++++++++-- - util/IMdkit/i18nMethod.c | 24 +++++- - util/IMdkit/i18nOffsetCache.c | 2 +- - util/IMdkit/i18nPtHdr.c | 148 ++++++++++++++++++++++++++++------ - util/IMdkit/i18nUtil.c | 20 +++++ - util/IMdkit/i18nX.c | 29 ++++--- - 29 files changed, 524 insertions(+), 172 deletions(-) - -diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c -index e432e849..49a138fe 100644 ---- a/bus/ibusimpl.c -+++ b/bus/ibusimpl.c -@@ -2,8 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2011-2020 Takao Fujiwara -- * Copyright (C) 2008-2020 Red Hat, Inc. -+ * Copyright (C) 2011-2021 Takao Fujiwara -+ * Copyright (C) 2008-2021 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 -@@ -624,7 +624,6 @@ bus_ibus_impl_destroy (BusIBusImpl *ibus) - - g_list_foreach (ibus->components, (GFunc) bus_component_stop, NULL); - -- pid = 0; - timeout = 0; - flag = FALSE; - while (1) { -@@ -1190,6 +1189,7 @@ _ibus_get_current_input_context (BusIBusImpl *ibus, - GDBusConnection *connection, - GError **error) - { -+ GVariant *retval = NULL; - if (error) { - *error = NULL; - } -@@ -1204,8 +1204,14 @@ _ibus_get_current_input_context (BusIBusImpl *ibus, - const gchar *path = ibus_service_get_object_path ( - (IBusService *) ibus->focused_context); - /* the format-string 'o' is for a D-Bus object path. */ -- return g_variant_new_object_path (path); -+ retval = g_variant_new_object_path (path); -+ if (!retval) { -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, -+ "Could not get object path from %s", -+ path ? path : "(null)"); -+ } - } -+ return retval; - } - - static void -@@ -1572,6 +1578,7 @@ _ibus_get_global_engine (BusIBusImpl *ibus, - GError **error) - { - IBusEngineDesc *desc = NULL; -+ GVariant *retval = NULL; - - if (error) { - *error = NULL; -@@ -1592,7 +1599,13 @@ _ibus_get_global_engine (BusIBusImpl *ibus, - GVariant *variant = ibus_serializable_serialize ( - (IBusSerializable *) desc); - // Set type "v" for introspection_xml. -- return g_variant_new_variant (variant); -+ retval = g_variant_new_variant (variant); -+ if (!retval) { -+ g_set_error (error, -+ G_DBUS_ERROR, G_DBUS_ERROR_FAILED, -+ "Failed to serialize engine desc."); -+ } -+ return retval; - } while (0); - - g_set_error (error, -diff --git a/bus/server.c b/bus/server.c -index 6c9e2c02..e8d0ce2b 100644 ---- a/bus/server.c -+++ b/bus/server.c -@@ -2,8 +2,8 @@ - /* vim:set et sts=4: */ - /* bus - The Input Bus - * Copyright (C) 2008-2010 Peng Huang -- * Copyright (C) 2011-2019 Takao Fujiwara -- * Copyright (C) 2008-2019 Red Hat, Inc. -+ * Copyright (C) 2011-2021 Takao Fujiwara -+ * Copyright (C) 2008-2021 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,12 +22,11 @@ - */ - #include "server.h" - --#include - #include - #include --#include --#include - #include -+#include -+#include - #include - - #include "dbusimpl.h" -@@ -282,6 +281,7 @@ bus_server_init (void) - * `chmod` runs for the last directory only not to change the modes - * of the parent directories. E.g. "/tmp/ibus". - */ -+ errno = 0; - if (g_mkdir_with_parents (unix_dir, 0700) != 0) { - g_error ("mkdir is failed in: %s: %s", - unix_dir, g_strerror (errno)); -diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c -index 61194816..e7ce5363 100644 ---- a/client/gtk2/ibusimcontext.c -+++ b/client/gtk2/ibusimcontext.c -@@ -385,7 +385,9 @@ _process_key_event_done (GObject *object, - - ProcessKeyEventData *data = (ProcessKeyEventData *)user_data; - GdkEvent *event = data->event; -+#if GTK_CHECK_VERSION (3, 98, 4) - IBusIMContext *ibusimcontext = data->ibusimcontext; -+#endif - GError *error = NULL; - - g_slice_free (ProcessKeyEventData, data); -@@ -1634,6 +1636,7 @@ get_selection_anchor_point (IBusIMContext *ibusimcontext, - return anchor; - } - -+#if !GTK_CHECK_VERSION (4, 1, 2) - static void - ibus_im_context_set_surrounding (GtkIMContext *context, - const gchar *text, -@@ -1646,6 +1649,7 @@ ibus_im_context_set_surrounding (GtkIMContext *context, - cursor_index, - cursor_index); - } -+#endif - - static void - ibus_im_context_set_surrounding_with_selection (GtkIMContext *context, -@@ -1851,7 +1855,11 @@ _create_gdk_event (IBusIMContext *ibusimcontext, - if (event->state & GDK_CONTROL_MASK) { - if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F; - else if (c == '2') { -+#if GLIB_CHECK_VERSION (2, 68, 0) -+ event->string = g_memdup2 ("\0\0", 2); -+#else - event->string = g_memdup ("\0\0", 2); -+#endif - event->length = 1; - buf[0] = '\0'; - goto out; -diff --git a/client/wayland/main.c b/client/wayland/main.c -index d86bab9e..1f99c804 100644 ---- a/client/wayland/main.c -+++ b/client/wayland/main.c -@@ -1,7 +1,7 @@ - /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ - /* vim:set et sts=4: */ - /* ibus - The Input Bus -- * Copyright (C) 2019 Takao Fujiwara -+ * Copyright (C) 2019-2021 Takao Fujiwara - * Copyright (C) 2013 Intel Corporation - * Copyright (C) 2013-2019 Red Hat, Inc. - * -@@ -339,16 +339,19 @@ input_method_keyboard_keymap (void *data, - { - IBusWaylandIM *wlim = data; - GMappedFile *map; -- GError *error; -+ GError *error = NULL; - - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { - close(fd); - return; - } - -- error = NULL; - map = g_mapped_file_new_from_fd (fd, FALSE, &error); - if (map == NULL) { -+ if (error) { -+ g_warning ("Failed to map file fd %s", error->message); -+ g_error_free (error); -+ } - close (fd); - return; - } -diff --git a/client/x11/main.c b/client/x11/main.c -index c9ee174d..ffd776fd 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-2019 Takao Fujiwara -+ * Copyright (C) 2015-2021 Takao Fujiwara - * Copyright (C) 2007-2015 Red Hat, Inc. - * - * main.c: -@@ -229,12 +229,13 @@ _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++) { - if (feedback[i] == 0) { - feedback[i] = XIMUnderline; - } - } -- feedback[len] = 0; -+ if (feedback) -+ feedback[len] = 0; - - pcb.major_code = XIM_PREEDIT_DRAW; - pcb.connect_id = x11ic->connect_id; -@@ -736,9 +737,20 @@ xim_get_ic_values (XIMS xims, IMChangeICStruct *call_data) - - for (i = 0; i < (int) call_data->ic_attr_num; ++i, ++ic_attr) { - if (g_strcmp0 (XNFilterEvents, ic_attr->name) == 0) { -+ /* ic_attr->value will be freed in server side and ignore -+ * leak of malloc with -Wanalyzer-malloc-leak flags in gcc 11.0.1 -+ */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" - ic_attr->value = (void *) malloc (sizeof (CARD32)); -- *(CARD32 *) ic_attr->value = KeyPressMask | KeyReleaseMask; -- ic_attr->value_length = sizeof (CARD32); -+ if (ic_attr->value) { -+ *(CARD32 *) ic_attr->value = KeyPressMask | KeyReleaseMask; -+ ic_attr->value_length = sizeof (CARD32); -+ } else { -+ g_warning ("Failed to malloc"); -+ ic_attr->value_length = 0; -+ } -+#pragma GCC diagnostic pop - } - } - -diff --git a/conf/dconf/main.c b/conf/dconf/main.c -index e6878424..c8250f68 100644 ---- a/conf/dconf/main.c -+++ b/conf/dconf/main.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) 2012-2021 Takao Fujiwara -+ * Copyright (C) 2008-2021 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 -@@ -70,7 +71,9 @@ main (gint argc, gchar **argv) - GOptionContext *context; - - setlocale (LC_ALL, ""); -- g_setenv ("DCONF_PROFILE", "ibus", FALSE); -+ errno = 0; -+ if (!g_setenv ("DCONF_PROFILE", "ibus", FALSE)) -+ g_warning ("Failed setenv %s", strerror (errno)); - - context = g_option_context_new ("- ibus dconf component"); - -diff --git a/portal/portal.c b/portal/portal.c -index e78bc92f..c2e4fc7f 100644 ---- a/portal/portal.c -+++ b/portal/portal.c -@@ -1,7 +1,7 @@ - /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ - /* vim:set et sts=4: */ - /* ibus - The Input Bus -- * Copyright (C) 2017-2019 Red Hat, Inc. -+ * Copyright (C) 2017-2021 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 -@@ -508,7 +508,6 @@ create_input_context_done (IBusBus *bus, - if (portal_context == NULL) { - g_dbus_method_invocation_return_gerror (invocation, error); - g_error_free (error); -- g_object_unref (portal_context); - return; - } - -@@ -656,8 +655,10 @@ main (gint argc, gchar **argv) - exit (-1); - } - -+ errno = 0; - /* Avoid even loading gvfs to avoid accidental confusion */ -- g_setenv ("GIO_USE_VFS", "local", TRUE); -+ if (!g_setenv ("GIO_USE_VFS", "local", TRUE)) -+ g_warning ("Failed setenv %s", strerror (errno)); - - ibus_init (); - -diff --git a/setup/ibus-setup.in b/setup/ibus-setup.in -index 4a6830af..474ce8a8 100644 ---- a/setup/ibus-setup.in -+++ b/setup/ibus-setup.in -@@ -27,5 +27,5 @@ export IBUS_PREFIX=@prefix@ - export IBUS_DATAROOTDIR=@datarootdir@ - export IBUS_LOCALEDIR=@localedir@ - export IBUS_LIBEXECDIR=${libexecdir} --exec ${PYTHON:-@PYTHON@} @prefix@/share/ibus/setup/main.py $@ -+exec ${PYTHON:-@PYTHON@} @prefix@/share/ibus/setup/main.py "$@" - -diff --git a/src/emoji-parser.c b/src/emoji-parser.c -index b117b1b4..36d36e05 100644 ---- a/src/emoji-parser.c -+++ b/src/emoji-parser.c -@@ -1,7 +1,7 @@ - /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ - /* vim:set et sts=4: */ - /* ibus - The Input Bus -- * Copyright (C) 2016-2020 Takao Fujiwara -+ * Copyright (C) 2016-2021 Takao Fujiwara - * Copyright (C) 2016 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or -@@ -291,11 +291,9 @@ emoji_data_new_object (EmojiData *data) - "annotations", - data->annotations, - "description", -- data->description ? data->description -- : g_strdup (""), -+ data->description ? data->description : "", - "category", -- data->category ? data->category -- : g_strdup (""), -+ data->category ? data->category : "", - NULL); - data->list = g_slist_append (data->list, emoji); - } -@@ -608,7 +606,7 @@ unicode_emoji_test_parse_line (const gchar *line, - return FALSE; - } - unicode_emoji_test_parse_description (segments[1], data); -- g_strfreev (segments); -+ g_clear_pointer (&segments, g_strfreev); - if (data->annotations == NULL) { - if (data->subcategory) { - int i; -@@ -631,7 +629,7 @@ unicode_emoji_test_parse_line (const gchar *line, - data->annotations = g_slist_append (data->annotations, - g_strdup (segments[i])); - } -- g_strfreev (segments); -+ g_clear_pointer (&segments, g_strfreev); - } else { - g_warning ("No subcategory line\n"); - goto failed_to_parse_unicode_emoji_test_line; -@@ -672,7 +670,7 @@ unicode_emoji_test_parse_file (const gchar *filename, - filename, error ? error->message : ""); - goto failed_to_parse_unicode_emoji_test; - } -- head = end = content; -+ end = content; - while (*end == '\n' && end - content < length) { - end++; - n++; -@@ -1100,10 +1098,12 @@ static void - category_list_dump (const gchar *category, - GString *buff) - { -+ gchar *line; - g_return_if_fail (buff != NULL); - -- const gchar *line = g_strdup_printf (" N_(\"%s\"),\n", category); -+ line = g_strdup_printf (" N_(\"%s\"),\n", category); - g_string_append (buff, line); -+ g_free (line); - } - - static void -@@ -1113,7 +1113,7 @@ category_file_save (const gchar *filename, - gchar *content = NULL; - gsize length = 0; - GError *error = NULL; -- gchar *p; -+ gchar *p, *substr; - GString *buff = NULL; - int i; - GSList *list_categories = NULL; -@@ -1139,24 +1139,28 @@ category_file_save (const gchar *filename, - break; - } - if (p != NULL) { -- g_string_append (buff, g_strndup (content, p - content)); -+ substr = g_strndup (content, p - content); -+ g_string_append (buff, substr); -+ g_free (substr); - g_string_append_c (buff, '\n'); - } - g_clear_pointer (&content, g_free); - -- g_string_append (buff, g_strdup ("\n")); -- g_string_append (buff, g_strdup_printf ("/* This file is generated by %s. */", __FILE__)); -- g_string_append (buff, g_strdup ("\n")); -- g_string_append (buff, g_strdup ("include \n")); -- g_string_append (buff, g_strdup ("\n")); -- g_string_append (buff, g_strdup ("#ifndef __IBUS_EMOJI_GEN_H_\n")); -- g_string_append (buff, g_strdup ("#define __IBUS_EMOJI_GEN_H_\n")); -- g_string_append (buff, g_strdup ("const static char *unicode_emoji_categories[] = {\n")); -+ g_string_append (buff, "\n"); -+ substr = g_strdup_printf ("/* This file is generated by %s. */", __FILE__); -+ g_string_append (buff, substr); -+ g_free (substr); -+ g_string_append (buff, "\n"); -+ g_string_append (buff, "include \n"); -+ g_string_append (buff, "\n"); -+ g_string_append (buff, "#ifndef __IBUS_EMOJI_GEN_H_\n"); -+ g_string_append (buff, "#define __IBUS_EMOJI_GEN_H_\n"); -+ g_string_append (buff, "const static char *unicode_emoji_categories[] = {\n"); - list_categories = g_slist_sort (list_categories, (GCompareFunc)g_strcmp0); - g_slist_foreach (list_categories, (GFunc)category_list_dump, buff); - g_slist_free (list_categories); -- g_string_append (buff, g_strdup ("};\n")); -- g_string_append (buff, g_strdup ("#endif\n")); -+ g_string_append (buff, "};\n"); -+ g_string_append (buff, "#endif\n"); - - if (!g_file_set_contents (filename, buff->str, -1, &error)) { - g_warning ("Failed to save emoji category file %s: %s", filename, error->message); -diff --git a/src/ibusaccelgroup.c b/src/ibusaccelgroup.c -index 8a81597e..ef2d3976 100644 ---- a/src/ibusaccelgroup.c -+++ b/src/ibusaccelgroup.c -@@ -468,7 +468,7 @@ ibus_accelerator_name (guint accelerator_key, - if (accelerator_mods & IBUS_SUPER_MASK) - l += sizeof (text_super) - 1; - -- accelerator = g_new (gchar, l + 1); -+ g_return_val_if_fail ((accelerator = g_new (gchar, l + 1)), NULL); - - accelerator_mods = saved_mods; - l = 0; -diff --git a/src/ibusbus.c b/src/ibusbus.c -index b7ffbb47..e9b0bcbb 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-2019 Takao Fujiwara -+ * Copyright (C) 2015-2021 Takao Fujiwara - * Copyright (C) 2008-2016 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or -@@ -555,12 +555,18 @@ ibus_bus_init (IBusBus *bus) - - path = g_path_get_dirname (ibus_get_socket_path ()); - -- g_mkdir_with_parents (path, 0700); -+ errno = 0; -+ if (g_mkdir_with_parents (path, 0700)) { -+ g_warning ("Failed to mkdir %s: %s", path, g_strerror (errno)); -+ g_free (path); -+ return; -+ } - - if (stat (path, &buf) == 0) { - if (buf.st_uid != getuid ()) { - g_warning ("The owner of %s is not %s!", - path, ibus_get_user_name ()); -+ g_free (path); - return; - } - if (buf.st_mode != (S_IFDIR | S_IRWXU)) { -diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c -index ef20469c..685ac717 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-2019 Takao Fujiwara -+ * Copyright (C) 2013-2021 Takao Fujiwara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -108,6 +108,7 @@ parse_compose_value (IBusComposeData *compose_data, - } - ++head; - p = head; -+ end = NULL; - while ((*p != '\0') && (end = strchr (p, '\"'))) { - if (*(end - 1) == '\\' && *(end - 2) == '\\') - break; -@@ -516,10 +517,10 @@ ibus_compose_hash_get_cache_path (guint32 hash) - "ibus", "compose", NULL); - } - path = g_build_filename (dir, basename, NULL); -- if (g_mkdir_with_parents (dir, 0755) != 0) { -- g_warning ("Failed to mkdir %s", dir); -- g_free (path); -- path = NULL; -+ errno = 0; -+ if (g_mkdir_with_parents (dir, 0755)) { -+ g_warning ("Failed to mkdir %s: %s", dir, g_strerror (errno)); -+ g_clear_pointer (&path, g_free); - } - - g_free (dir); -@@ -812,10 +813,14 @@ ibus_compose_table_deserialize (const gchar *contents, - } - } - if (data_length) { -- retval->priv->data_second = g_new (guint32, data_length); -- memcpy (retval->priv->data_second, -- data_32bit_second, data_length * sizeof (guint32)); -- retval->priv->second_size = second_size; -+ if ((retval->priv->data_second = g_new (guint32, data_length))) { -+ memcpy (retval->priv->data_second, -+ data_32bit_second, data_length * sizeof (guint32)); -+ retval->priv->second_size = second_size; -+ } else { -+ g_warning ("Failed g_new"); -+ retval->priv->second_size = 0; -+ } - } - - -@@ -910,6 +915,43 @@ ibus_compose_table_new_with_list (GList *compose_list, - int n_index_stride, - guint32 hash) - { -+ /* @ibus_compose_seqs: Include both compose sequence and the value(compose -+ * output) as the tradition GTK. The value is one character only -+ * and within 16bit. I.e. All compose sequences and the values -+ * are 16bit. -+ * @ibus_compose_seqs_32bit_second: Include the compose values only. -+ * The length of values by compose sequence is more than one characster -+ * or one of the values is outside 16bit but within 32bit. -+ * Some values could be more than one character and Emoji character -+ * could be outside 16bit. -+ * See also ibus/src/tests/ibus-compose.emoji file for e.g. -+ * @ibus_compose_seqs_32bit_first: Include the compose sequence only in -+ * case the value is included in @ibus_compose_seqs_32bit_second. -+ * @s_size_total: The number of compose sequences. -+ * @s_size_16bit: The number of compose sequences whose value is one -+ * character only and within 16bit. I.e. the number of the compose -+ * sequence in @ibus_compose_seqs is @@s_size_16bit. And -+ * @s_size_total - @s_size_16bit is the number of the compose sequence -+ * in @ibus_compose_seqs_32bit_first. -+ * @v_size_32bit: The total number of compose values. Each length of the -+ * values is more than one character or one of the value is -+ * outside 16bit but within 32bit. I.e. The size of -+ * @ibus_compose_seqs_32bit_second is @v_size_32bit. -+ * @v_index_32bit: Each index of the compose values in -+ * @ibus_compose_seqs_32bit_second and this is not a fixed value in -+ * this API. If a compose sequence is found in -+ * @ibus_compose_seqs_32bit_first and the next value is 0, 0 is lined -+ * in @ibus_compose_seqs_32bit_first until @max_compose_len after -+ * the found compose sequence. And the next value is the length of -+ * the compose values and the next value is the @v_index_32bit, i.e. -+ * the index of @ibus_compose_seqs_32bit_second. -+ * E.g. the following line could be found in -+ * @ibus_compose_seqs_32bit_first: -+ * ..., "U17ff", "0", "0", "0", "0", 2, 100, ... -+ * @ibus_compose_seqs_32bit_second[100] is "ាំ" and the character -+ * length is 2. -+ * @max_compose_len is 5 and @n_index_stride is 7. -+ */ - gsize s_size_total, s_size_16bit, v_size_32bit, v_index_32bit; - guint n = 0, m = 0; - int i, j; -@@ -935,13 +977,25 @@ ibus_compose_table_new_with_list (GList *compose_list, - } - } - -- if (s_size_16bit) -+ if (s_size_16bit) { - ibus_compose_seqs = g_new (guint16, s_size_16bit * n_index_stride); -+ if (!ibus_compose_seqs) { -+ g_warning ("Failed g_new"); -+ return NULL; -+ } -+ } - if (s_size_total > s_size_16bit) { - ibus_compose_seqs_32bit_first = - g_new (guint16, - (s_size_total - s_size_16bit) * n_index_stride); - ibus_compose_seqs_32bit_second = g_new (guint32, v_size_32bit); -+ if (!ibus_compose_seqs_32bit_first || !ibus_compose_seqs_32bit_second) { -+ g_warning ("Failed g_new"); -+ g_free (ibus_compose_seqs); -+ g_free (ibus_compose_seqs_32bit_first); -+ g_free (ibus_compose_seqs_32bit_second); -+ return NULL; -+ } - } - - v_index_32bit = 0; -@@ -951,32 +1005,45 @@ ibus_compose_table_new_with_list (GList *compose_list, - - is_32bit = unichar_length (compose_data->values) > 1 ? TRUE : - compose_data->values[0] >= 0xFFFF ? TRUE : FALSE; -+ if (is_32bit) { -+ g_assert (ibus_compose_seqs_32bit_first); -+ g_assert (ibus_compose_seqs_32bit_second); -+ } - for (i = 0; i < max_compose_len; i++) { - if (compose_data->sequence[i] == 0) { - for (j = i; j < max_compose_len; j++) { -- if (is_32bit) -+ if (is_32bit) { -+ g_assert (m < (s_size_total - s_size_16bit) -+ * n_index_stride); - ibus_compose_seqs_32bit_first[m++] = 0; -- else -+ } else { -+ g_assert (n < s_size_16bit * n_index_stride); - ibus_compose_seqs[n++] = 0; -+ } - } - break; - } - if (is_32bit) { -+ g_assert (m < (s_size_total - s_size_16bit) * n_index_stride); - ibus_compose_seqs_32bit_first[m++] = - (guint16) compose_data->sequence[i]; - } else { -+ g_assert (n < s_size_16bit * n_index_stride); - ibus_compose_seqs[n++] = (guint16) compose_data->sequence[i]; - } - } - if (is_32bit) { - for (j = 0; compose_data->values[j]; j++) { -+ g_assert (v_index_32bit + j < v_size_32bit); - ibus_compose_seqs_32bit_second[v_index_32bit + j] = - compose_data->values[j]; - } -+ g_assert (m + 1 < (s_size_total - s_size_16bit) * n_index_stride); - ibus_compose_seqs_32bit_first[m++] = j; - ibus_compose_seqs_32bit_first[m++] = v_index_32bit; - v_index_32bit += j; - } else { -+ g_assert (n + 1 < s_size_16bit * n_index_stride); - ibus_compose_seqs[n++] = (guint16) compose_data->values[0]; - ibus_compose_seqs[n++] = 0; - } -diff --git a/src/ibusemoji.c b/src/ibusemoji.c -index ae8907a2..df97264b 100644 ---- a/src/ibusemoji.c -+++ b/src/ibusemoji.c -@@ -1,7 +1,7 @@ - /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ - /* vim:set et sts=4: */ - /* bus - The Input Bus -- * Copyright (C) 2017-2019 Takao Fujiwara -+ * Copyright (C) 2017-2021 Takao Fujiwara - * Copyright (C) 2017-2019 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or -@@ -497,7 +497,11 @@ ibus_emoji_data_save (const gchar *path, - - dir = g_path_get_dirname (path); - if (g_strcmp0 (dir, ".") != 0 && g_stat (dir, &buf) != 0) { -- g_mkdir_with_parents (dir, 0777); -+ errno = 0; -+ if (g_mkdir_with_parents (dir, 0777)) { -+ g_warning ("Failed mkdir %s: %s", dir, g_strerror (errno)); -+ return; -+ } - } - g_free (dir); - if (!g_file_set_contents (path, contents, length, &error)) { -diff --git a/src/ibusenginesimple.c b/src/ibusenginesimple.c -index 43bd5283..6dbc39c7 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-2019 Takao Fujiwara -+ * Copyright (C) 2015-2021 Takao Fujiwara - * Copyright (C) 2014-2017 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or -@@ -466,11 +466,15 @@ check_hex (IBusEngineSimple *simple, - - ch = ibus_keyval_to_unicode (priv->compose_buffer[i]); - -- if (ch == 0) -+ if (ch == 0) { -+ g_string_free (str, TRUE); - return FALSE; -+ } - -- if (!g_unichar_isxdigit (ch)) -+ if (!g_unichar_isxdigit (ch)) { -+ g_string_free (str, TRUE); - return FALSE; -+ } - - buf[g_unichar_to_utf8 (ch, buf)] = '\0'; - -@@ -487,8 +491,9 @@ check_hex (IBusEngineSimple *simple, - if (nptr - str->str < str->len) { - g_string_free (str, TRUE); - return FALSE; -- } else -+ } else { - g_string_free (str, TRUE); -+ } - - if (g_unichar_validate (n)) { - priv->tentative_match = n; -@@ -559,11 +564,15 @@ check_emoji_table (IBusEngineSimple *simple, - - ch = ibus_keyval_to_unicode (priv->compose_buffer[i]); - -- if (ch == 0) -+ if (ch == 0) { -+ g_string_free (str, TRUE); - return FALSE; -+ } - -- if (!g_unichar_isprint (ch)) -+ if (!g_unichar_isprint (ch)) { -+ g_string_free (str, TRUE); - return FALSE; -+ } - - buf[g_unichar_to_utf8 (ch, buf)] = '\0'; - -diff --git a/src/ibushotkey.c b/src/ibushotkey.c -index d4ab7c23..e72b8305 100644 ---- a/src/ibushotkey.c -+++ b/src/ibushotkey.c -@@ -2,7 +2,7 @@ - /* vim:set et sts=4: */ - /* IBus - The Input Bus - * Copyright (C) 2008-2010 Peng Huang -- * Copyright (C) 2018-2019 Takao Fujiwara -+ * Copyright (C) 2018-2021 Takao Fujiwara - * Copyright (C) 2008-2019 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or -@@ -373,6 +373,8 @@ ibus_hotkey_profile_add_hotkey (IBusHotkeyProfile *profile, - p->event = event; - } - -+ if (!p) -+ return FALSE; - p->hotkeys = g_list_append (p->hotkeys, hotkey); - - return TRUE; -diff --git a/src/ibusregistry.c b/src/ibusregistry.c -index 3386a5d1..23c5ca1b 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-2020 Takao Fujiwara -+ * Copyright (C) 2015-2021 Takao Fujiwara - * Copyright (C) 2015-2020 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or -@@ -438,7 +438,12 @@ ibus_registry_save_cache_file (IBusRegistry *registry, - g_assert (filename != NULL); - - cachedir = g_path_get_dirname (filename); -- g_mkdir_with_parents (cachedir, 0775); -+ errno = 0; -+ if (g_mkdir_with_parents (cachedir, 0775)) { -+ g_warning ("Failed to mkdir %s: %s", cachedir, g_strerror (errno)); -+ g_free (cachedir); -+ return FALSE; -+ } - g_free (cachedir); - - variant = ibus_serializable_serialize (IBUS_SERIALIZABLE (registry)); -diff --git a/src/ibusshare.c b/src/ibusshare.c -index e0ef2ce0..8974511a 100644 ---- a/src/ibusshare.c -+++ b/src/ibusshare.c -@@ -2,7 +2,7 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2010 Peng Huang -- * Copyright (C) 2015-2018 Takao Fujiwara -+ * Copyright (C) 2015-2021 Takao Fujiwara - * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or -@@ -197,22 +197,17 @@ ibus_get_address (void) - FILE *pf; - - /* free address */ -- if (address != NULL) { -- g_free (address); -- address = NULL; -- } -+ g_clear_pointer (&address, g_free); - - /* get address from env variable */ - address = g_strdup (g_getenv ("IBUS_ADDRESS")); -- if (address) { -+ if (address) - return address; -- } - - /* read address from ~/.config/ibus/bus/soketfile */ - pf = fopen (ibus_get_socket_path (), "r"); -- if (pf == NULL) { -+ if (pf == NULL) - return NULL; -- } - - while (!feof (pf)) { - gchar *p = buffer; -@@ -224,11 +219,12 @@ ibus_get_address (void) - continue; - /* parse IBUS_ADDRESS */ - if (strncmp (p, "IBUS_ADDRESS=", sizeof ("IBUS_ADDRESS=") - 1) == 0) { -- address = p + sizeof ("IBUS_ADDRESS=") - 1; -- for (p = (gchar *)address; *p != '\n' && *p != '\0'; p++); -+ gchar *head = p + sizeof ("IBUS_ADDRESS=") - 1; -+ for (p = head; *p != '\n' && *p != '\0'; p++); - if (*p == '\n') - *p = '\0'; -- address = g_strdup (address); -+ g_free (address); -+ address = g_strdup (head); - continue; - } - -@@ -241,9 +237,8 @@ ibus_get_address (void) - } - fclose (pf); - -- if (pid == -1 || kill (pid, 0) != 0) { -+ if (pid == -1 || kill (pid, 0) != 0) - return NULL; -- } - - return address; - } -@@ -256,10 +251,19 @@ ibus_write_address (const gchar *address) - g_return_if_fail (address != NULL); - - path = g_path_get_dirname (ibus_get_socket_path ()); -- g_mkdir_with_parents (path, 0700); -+ errno = 0; -+ if (g_mkdir_with_parents (path, 0700)) { -+ g_warning ("Failed to mkdir %s: %s", path, g_strerror (errno)); -+ g_free (path); -+ return; -+ } - g_free (path); - -- g_unlink (ibus_get_socket_path ()); -+ errno = 0; -+ if (g_unlink (ibus_get_socket_path ())) { -+ g_warning ("Failed to unlink %s: %s", -+ ibus_get_socket_path (), g_strerror (errno)); -+ } - pf = fopen (ibus_get_socket_path (), "w"); - g_return_if_fail (pf != NULL); - -diff --git a/src/ibustext.c b/src/ibustext.c -index a5e3c43b..ed0fe666 100644 ---- a/src/ibustext.c -+++ b/src/ibustext.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) 2011-2021 Takao Fujiwara -+ * Copyright (C) 2008-2021 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 -@@ -220,7 +221,7 @@ ibus_text_new_from_unichar (gunichar c) - text= g_object_new (IBUS_TYPE_TEXT, NULL); - - text->is_static = FALSE; -- text->text = (gchar *)g_malloc (12); -+ g_return_val_if_fail ((text->text = (gchar *)g_malloc (12)), NULL); - len = g_unichar_to_utf8 (c, text->text); - text->text[len] = 0; - -diff --git a/src/ibusunicode.c b/src/ibusunicode.c -index 9e6f6b2b..f7a897d1 100644 ---- a/src/ibusunicode.c -+++ b/src/ibusunicode.c -@@ -1,8 +1,8 @@ - /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ - /* vim:set et sts=4: */ - /* bus - The Input Bus -- * Copyright (C) 2018-2019 Takao Fujiwara -- * Copyright (C) 2018-2019 Red Hat, Inc. -+ * Copyright (C) 2018-2021 Takao Fujiwara -+ * Copyright (C) 2018-2021 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 -@@ -472,7 +472,12 @@ ibus_unicode_data_save (const gchar *path, - - dir = g_path_get_dirname (path); - if (g_strcmp0 (dir, ".") != 0 && g_stat (dir, &buf) != 0) { -- g_mkdir_with_parents (dir, 0777); -+ errno = 0; -+ if (g_mkdir_with_parents (dir, 0777)) { -+ g_warning ("Failed to mkdir %s: %s", dir, g_strerror (errno)); -+ return; -+ } -+ - } - g_free (dir); - if (!g_file_set_contents (path, contents, length, &error)) { -@@ -967,7 +972,11 @@ ibus_unicode_block_save (const gchar *path, - - dir = g_path_get_dirname (path); - if (g_strcmp0 (dir, ".") != 0 && g_stat (dir, &buf) != 0) { -- g_mkdir_with_parents (dir, 0777); -+ errno = 0; -+ if (g_mkdir_with_parents (dir, 0777)) { -+ g_warning ("Failed to mkdir %s: %s", dir, g_strerror (errno)); -+ return; -+ } - } - g_free (dir); - if (!g_file_set_contents (path, contents, length, &error)) { -diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c -index 4b4c56e7..81bfc69b 100644 ---- a/src/tests/ibus-compose.c -+++ b/src/tests/ibus-compose.c -@@ -360,11 +360,13 @@ main (int argc, char *argv[]) - /* Avoid a warning of "AT-SPI: Could not obtain desktop path or name" - * with gtk_main(). - */ -- g_setenv ("NO_AT_BRIDGE", "1", TRUE); -+ if (!g_setenv ("NO_AT_BRIDGE", "1", TRUE)) -+ g_message ("Failed setenv NO_AT_BRIDGE\n"); - g_test_init (&argc, &argv, NULL); - gtk_init (&argc, &argv); - -- m_srcdir = argc > 1 ? g_strdup (argv[1]) : g_strdup ("."); -+ m_srcdir = (argc > 1 && strlen (argv[1]) < FILENAME_MAX) -+ ? g_strdup (argv[1]) : g_strdup ("."); - m_compose_file = g_strdup (g_getenv ("COMPOSE_FILE")); - #if GLIB_CHECK_VERSION (2, 58, 0) - test_name = g_get_language_names_with_category ("LC_CTYPE")[0]; -diff --git a/src/tests/ibus-keypress.c b/src/tests/ibus-keypress.c -index dd1b0042..bab05398 100644 ---- a/src/tests/ibus-keypress.c -+++ b/src/tests/ibus-keypress.c -@@ -291,7 +291,8 @@ main (int argc, char *argv[]) - /* Avoid a warning of "AT-SPI: Could not obtain desktop path or name" - * with gtk_main(). - */ -- g_setenv ("NO_AT_BRIDGE", "1", TRUE); -+ if (!g_setenv ("NO_AT_BRIDGE", "1", TRUE)) -+ g_message ("Failed setenv NO_AT_BRIDGE\n"); - g_test_init (&argc, &argv, NULL); - gtk_init (&argc, &argv); - -diff --git a/src/unicode-parser.c b/src/unicode-parser.c -index b4303ea8..2c4eb677 100644 ---- a/src/unicode-parser.c -+++ b/src/unicode-parser.c -@@ -1,8 +1,8 @@ - /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ - /* vim:set et sts=4: */ - /* ibus - The Input Bus -- * Copyright (C) 2018 Takao Fujiwara -- * Copyright (C) 2018 Red Hat, Inc. -+ * Copyright (C) 2018-2021 Takao Fujiwara -+ * Copyright (C) 2018-2021 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 -@@ -76,11 +76,9 @@ unicode_data_new_object (UnicodeData *data) - ibus_unicode_data_new ("code", - data->code, - "name", -- data->name ? g_strdup (data->name) -- : g_strdup (""), -+ data->name ? data->name : "", - "alias", -- data->alias ? g_strdup (data->alias) -- : g_strdup (""), -+ data->alias ? data->alias : "", - NULL); - data->list = g_slist_append (data->list, unicode); - } -@@ -98,8 +96,7 @@ unicode_block_new_object (UnicodeData *data) - "end", - data->end, - "name", -- data->name ? g_strdup (data->name) -- : g_strdup (""), -+ data->name ? data->name : "", - NULL); - data->list = g_slist_append (data->list, block); - } -@@ -285,7 +282,7 @@ ucd_parse_file (const gchar *filename, - filename, error ? error->message : ""); - goto failed_to_parse_ucd_names_list; - } -- head = end = content; -+ end = content; - while (*end == '\n' && end - content < length) { - end++; - n++; -@@ -352,6 +349,7 @@ static void - block_list_dump (IBusUnicodeBlock *block, - GString *buff) - { -+ gchar *line; - g_return_if_fail (buff != NULL); - - g_string_append (buff, " /* TRANSLATORS: You might refer the " \ -@@ -359,9 +357,10 @@ block_list_dump (IBusUnicodeBlock *block, - " the following command:\n" \ - " msgmerge -C gucharmap.po ibus.po " \ - "ibus.pot */\n"); -- gchar *line = g_strdup_printf (" N_(\"%s\"),\n", -- ibus_unicode_block_get_name (block)); -+ line = g_strdup_printf (" N_(\"%s\"),\n", -+ ibus_unicode_block_get_name (block)); - g_string_append (buff, line); -+ g_free (line); - } - - static void -@@ -371,7 +370,7 @@ ucd_block_translatable_save (const gchar *filename, - gchar *content = NULL; - gsize length = 0; - GError *error = NULL; -- gchar *p; -+ gchar *p, *substr; - GString *buff = NULL; - int i; - GSList *list = blocks_list; -@@ -392,25 +391,30 @@ ucd_block_translatable_save (const gchar *filename, - break; - } - if (p != NULL) { -- g_string_append (buff, g_strndup (content, p - content)); -+ substr = g_strndup (content, p - content); -+ g_string_append (buff, substr); -+ g_free (substr); - g_string_append_c (buff, '\n'); - } - g_clear_pointer (&content, g_free); - -- g_string_append (buff, g_strdup ("\n")); -- g_string_append (buff, g_strdup_printf ("/* This file is generated by %s. */", __FILE__)); -- g_string_append (buff, g_strdup ("\n")); -- g_string_append (buff, g_strdup ("include \n")); -- g_string_append (buff, g_strdup ("\n")); -- g_string_append (buff, g_strdup ("#ifndef __IBUS_UNICODE_GEN_H_\n")); -- g_string_append (buff, g_strdup ("#define __IBUS_UNICODE_GEN_H_\n")); -- g_string_append (buff, g_strdup ("const static char *unicode_blocks[] = {\n")); -+ g_string_append (buff, "\n"); -+ substr = g_strdup_printf ("/* This file is generated by %s. */", __FILE__); -+ g_string_append (buff, substr); -+ g_free (substr); -+ g_string_append (buff, "\n"); -+ g_string_append (buff, "include \n"); -+ g_string_append (buff, "\n"); -+ g_string_append (buff, "#ifndef __IBUS_UNICODE_GEN_H_\n"); -+ g_string_append (buff, "#define __IBUS_UNICODE_GEN_H_\n"); -+ g_string_append (buff, "const static char *unicode_blocks[] = {\n"); - g_slist_foreach (list, (GFunc)block_list_dump, buff); -- g_string_append (buff, g_strdup ("};\n")); -- g_string_append (buff, g_strdup ("#endif\n")); -+ g_string_append (buff, "};\n"); -+ g_string_append (buff, "#endif\n"); - - if (!g_file_set_contents (filename, buff->str, -1, &error)) { -- g_warning ("Failed to save emoji category file %s: %s", filename, error->message); -+ g_warning ("Failed to save emoji category file %s: %s", -+ filename, error->message); - g_error_free (error); - } - -diff --git a/util/IMdkit/FrameMgr.c b/util/IMdkit/FrameMgr.c -index 0e91b78e..80d019a0 100644 ---- a/util/IMdkit/FrameMgr.c -+++ b/util/IMdkit/FrameMgr.c -@@ -851,7 +851,7 @@ static Bool _FrameMgrProcessPadding (FrameMgr fm, FmStatus* status) - return True; - } - /*endif*/ -- next_type = FrameInstGetNextType (fm->fi, &info); -+ FrameInstGetNextType (fm->fi, &info); - fm->idx += info.num; - if ((fitr = _FrameIterCounterIncr (fm->iters, info.num))) - _FrameMgrRemoveIter (fm, fitr); -@@ -1525,6 +1525,11 @@ static Iter IterInit (XimFrame frame, int count) - register XimFrameType type; - - it = (Iter) Xmalloc (sizeof (IterRec)); -+ if (!it) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ return NULL; -+ } - it->template = frame; - it->max_count = (count == NO_VALUE) ? 0 : count; - it->allow_expansion = (count == NO_VALUE); -@@ -1669,8 +1674,15 @@ static Bool IterIsLoopEnd (Iter it, Bool *myself) - - static XimFrameType IterGetNextType (Iter it, XimFrameTypeInfo info) - { -- XimFrameType type = it->template->type; -+ XimFrameType type; -+ -+ if (!it || !it->template) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ return (XimFrameType) NULL; -+ } - -+ type = it->template->type; - if (it->start_counter) - { - (*it->start_watch_proc) (it, it->client_data); -@@ -1766,7 +1778,15 @@ static XimFrameType IterGetNextType (Iter it, XimFrameTypeInfo info) - - static XimFrameType IterPeekNextType (Iter it, XimFrameTypeInfo info) - { -- XimFrameType type = it->template->type; -+ XimFrameType type; -+ -+ if (!it->template) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: dereference pointer %s:%d.\n", -+ __FILE__, __LINE__); -+ return (XimFrameType) NULL; -+ } -+ -+ type = it->template->type; - - if (!it->allow_expansion && it->cur_no >= it->max_count) - return (EOL); -@@ -1866,6 +1886,9 @@ static FmStatus IterSetSize (Iter it, int num) - dr.num = NO_VALUE; - d = ChainMgrSetData (&it->cm, i, dr); - } -+ if (!d) { -+ return FmNoMoreData; -+ } - /*endif*/ - if (d->num == NO_VALUE) - { -@@ -2254,6 +2277,11 @@ static ExtraData ChainMgrSetData (ChainMgr cm, - ExtraDataRec data) - { - Chain cur = (Chain) Xmalloc (sizeof (ChainRec)); -+ if (!cur) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ return NULL; -+ } - - cur->frame_no = frame_no; - cur->d = data; -diff --git a/util/IMdkit/i18nIc.c b/util/IMdkit/i18nIc.c -index 289837a6..14a3dc51 100644 ---- a/util/IMdkit/i18nIc.c -+++ b/util/IMdkit/i18nIc.c -@@ -470,13 +470,16 @@ static XICAttribute *CreateNestedList (CARD16 attr_id, - /*endfor*/ - - nest_list = (XICAttribute *) malloc (sizeof (XICAttribute)); -- if (nest_list == NULL) -+ if (nest_list == NULL) { -+ XFree (values); - return NULL; -+ } - /*endif*/ - memset (nest_list, 0, sizeof (XICAttribute)); - nest_list->value = (void *) malloc (value_length); - if (nest_list->value == NULL) { - XFree (nest_list); -+ XFree (values); - return NULL; - } - /*endif*/ -@@ -539,7 +542,13 @@ static int GetICValue (Xi18n i18n_core, - attr_ret[n].attribute_id = xic_attr[j].attribute_id; - attr_ret[n].name_length = xic_attr[j].length; - attr_ret[n].name = malloc (xic_attr[j].length + 1); -- strcpy(attr_ret[n].name, xic_attr[j].name); -+ if (!attr_ret[n].name) { -+ fprintf (stderr, -+ "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ } else { -+ strcpy(attr_ret[n].name, xic_attr[j].name); -+ } - attr_ret[n].type = xic_attr[j].type; - n++; - i++; -@@ -560,7 +569,13 @@ static int GetICValue (Xi18n i18n_core, - attr_ret[n].attribute_id = xic_attr[j].attribute_id; - attr_ret[n].name_length = xic_attr[j].length; - attr_ret[n].name = malloc (xic_attr[j].length + 1); -- strcpy(attr_ret[n].name, xic_attr[j].name); -+ if (!attr_ret[n].name) { -+ fprintf (stderr, -+ "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ } else { -+ strcpy(attr_ret[n].name, xic_attr[j].name); -+ } - attr_ret[n].type = xic_attr[j].type; - n++; - break; -@@ -700,10 +715,15 @@ void _Xi18nChangeIC (XIMS ims, - attrib_list[attrib_num].value_length = value_length; - FrameMgrGetToken (fm, value); - attrib_list[attrib_num].value = (void *) malloc (value_length + 1); -- memmove (attrib_list[attrib_num].value, value, value_length); -- ((char *)attrib_list[attrib_num].value)[value_length] = '\0'; -+ if (!attrib_list[attrib_num].value) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ } else { -+ memmove (attrib_list[attrib_num].value, value, value_length); -+ ((char *)attrib_list[attrib_num].value)[value_length] = '\0'; -+ total_value_length += (value_length + 1); -+ } - attrib_num++; -- total_value_length += (value_length + 1); - } - /*endwhile*/ - -@@ -917,6 +937,12 @@ void _Xi18nGetIC (XIMS ims, IMProtocol *call_data, unsigned char *p) - FrameMgrGetToken (fm, byte_length); - - attrID_list = (CARD16 *) malloc (sizeof (CARD16)*IC_SIZE); /* bogus */ -+ if (!attrID_list) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ FrameMgrFree (fm); -+ return; -+ } - memset (attrID_list, 0, sizeof (CARD16)*IC_SIZE); - - number = 0; -@@ -1026,7 +1052,7 @@ void _Xi18nGetIC (XIMS ims, IMProtocol *call_data, unsigned char *p) - { - _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0); - XFree (attrID_list); -- FrameMgrFree (fm); -+ goto _Xi18nGetIC_finit; - return; - } - /*endif*/ -@@ -1097,6 +1123,7 @@ void _Xi18nGetIC (XIMS ims, IMProtocol *call_data, unsigned char *p) - } - /*endfor*/ - -+_Xi18nGetIC_finit: - if (preedit_ret) - { - XFree (preedit_ret->value); -diff --git a/util/IMdkit/i18nMethod.c b/util/IMdkit/i18nMethod.c -index 36dd28ac..9c44e7fe 100644 ---- a/util/IMdkit/i18nMethod.c -+++ b/util/IMdkit/i18nMethod.c -@@ -166,8 +166,14 @@ static Bool GetEncodings(Xi18n i18n_core, XIMEncodings **p_encoding) - { - (*p_encoding)->supported_encodings[i] - = (char *) malloc (strlen (p->supported_encodings[i]) + 1); -- strcpy ((*p_encoding)->supported_encodings[i], -- p->supported_encodings[i]); -+ if (!((*p_encoding)->supported_encodings[i])) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ -+ } else { -+ strcpy ((*p_encoding)->supported_encodings[i], -+ p->supported_encodings[i]); -+ } - } - /*endif*/ - return True; -@@ -187,11 +193,17 @@ static char *ParseArgs (Xi18n i18n_core, int mode, XIMArg *args) - if (address->imvalue_mask & I18N_IM_LOCALE) - return IMLocale; - /*endif*/ -+ /* address->im_locale will be released later and don't need -+ * -Wanalyzer-malloc-leak flag in gcc 11.0.1. -+ */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" - address->im_locale = (char *) malloc (strlen (p->value) + 1); - if (!address->im_locale) - return IMLocale; - /*endif*/ - strcpy (address->im_locale, p->value); -+#pragma GCC diagnostic pop - address->imvalue_mask |= I18N_IM_LOCALE; - } - else if (strcmp (p->name, IMServerTransport) == 0) -@@ -199,11 +211,14 @@ static char *ParseArgs (Xi18n i18n_core, int mode, XIMArg *args) - if (address->imvalue_mask & I18N_IM_ADDRESS) - return IMServerTransport; - /*endif*/ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" - address->im_addr = (char *) malloc (strlen (p->value) + 1); - if (!address->im_addr) - return IMServerTransport; - /*endif*/ - strcpy(address->im_addr, p->value); -+#pragma GCC diagnostic pop - address->imvalue_mask |= I18N_IM_ADDRESS; - } - else if (strcmp (p->name, IMServerName) == 0) -@@ -211,11 +226,14 @@ static char *ParseArgs (Xi18n i18n_core, int mode, XIMArg *args) - if (address->imvalue_mask & I18N_IM_NAME) - return IMServerName; - /*endif*/ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" - address->im_name = (char *) malloc (strlen (p->value) + 1); - if (!address->im_name) - return IMServerName; - /*endif*/ - strcpy (address->im_name, p->value); -+#pragma GCC diagnostic pop - address->imvalue_mask |= I18N_IM_NAME; - } - else if (strcmp (p->name, IMServerWindow) == 0) -@@ -698,7 +716,7 @@ static void ReturnSelectionNotify (Xi18n i18n_core, XSelectionRequestEvent *ev) - { - XEvent event; - Display *dpy = i18n_core->address.dpy; -- char buf[4096]; -+ char buf[4096] = { '\0', }; - - event.type = SelectionNotify; - event.xselection.requestor = ev->requestor; -diff --git a/util/IMdkit/i18nOffsetCache.c b/util/IMdkit/i18nOffsetCache.c -index d5379051..e2fe8c6b 100644 ---- a/util/IMdkit/i18nOffsetCache.c -+++ b/util/IMdkit/i18nOffsetCache.c -@@ -94,7 +94,7 @@ void _Xi18nSetPropertyOffset (Xi18nOffsetCache *offset_cache, Atom key, - } - - assert (data != NULL); -- if (offset_cache->size > 0) { -+ if (offset_cache->size > 0 && i < offset_cache->capacity) { - data[i].key = key; - data[i].offset = offset; - } -diff --git a/util/IMdkit/i18nPtHdr.c b/util/IMdkit/i18nPtHdr.c -index eaeeee1c..8dc52714 100644 ---- a/util/IMdkit/i18nPtHdr.c -+++ b/util/IMdkit/i18nPtHdr.c -@@ -181,8 +181,13 @@ static void OpenMessageProc(XIMS ims, IMProtocol *call_data, unsigned char *p) - FrameMgrGetToken (fm, name); - imopen->lang.length = str_length; - imopen->lang.name = malloc (str_length + 1); -- strncpy (imopen->lang.name, name, str_length); -- imopen->lang.name[str_length] = (char) 0; -+ if (!imopen->lang.name) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ } else { -+ strncpy (imopen->lang.name, name, str_length); -+ imopen->lang.name[str_length] = (char) 0; -+ } - - FrameMgrFree (fm); - -@@ -339,7 +344,7 @@ static XIMExt *MakeExtensionList (Xi18n i18n_core, - int number, - int *reply_number) - { -- XIMExt *ext_list; -+ XIMExt *ext_list = NULL; - XIMExt *im_ext = (XIMExt *) i18n_core->address.extension; - int im_ext_len = i18n_core->address.ext_num; - int i; -@@ -358,7 +363,8 @@ static XIMExt *MakeExtensionList (Xi18n i18n_core, - { - for (j = 0; j < (int) number; j++) - { -- if (strcmp (lib_extension[j].name, im_ext[i].name) == 0) -+ if (lib_extension[j].name -+ && strcmp (lib_extension[j].name, im_ext[i].name) == 0) - { - (*reply_number)++; - break; -@@ -389,7 +395,13 @@ static XIMExt *MakeExtensionList (Xi18n i18n_core, - ext_list[i].minor_opcode = im_ext[i].minor_opcode; - ext_list[i].length = im_ext[i].length; - ext_list[i].name = malloc (im_ext[i].length + 1); -- strcpy (ext_list[i].name, im_ext[i].name); -+ if (!ext_list[i].name) { -+ fprintf (stderr, -+ "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ } else { -+ strcpy (ext_list[i].name, im_ext[i].name); -+ } - } - /*endfor*/ - } -@@ -401,13 +413,20 @@ static XIMExt *MakeExtensionList (Xi18n i18n_core, - { - for (j = 0; j < (int)number; j++) - { -- if (strcmp (lib_extension[j].name, im_ext[i].name) == 0) -+ if (lib_extension[j].name -+ && strcmp (lib_extension[j].name, im_ext[i].name) == 0) - { - ext_list[n].major_opcode = im_ext[i].major_opcode; - ext_list[n].minor_opcode = im_ext[i].minor_opcode; - ext_list[n].length = im_ext[i].length; - ext_list[n].name = malloc (im_ext[i].length + 1); -- strcpy (ext_list[n].name, im_ext[i].name); -+ if (!ext_list[n].name) { -+ fprintf (stderr, -+ "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ } else { -+ strcpy (ext_list[n].name, im_ext[i].name); -+ } - n++; - break; - } -@@ -450,6 +469,11 @@ static void QueryExtensionMessageProc (XIMS ims, - FrameMgrGetToken (fm, input_method_ID); - FrameMgrGetToken (fm, byte_length); - query_ext->extension = (XIMStr *) malloc (sizeof (XIMStr)*10); -+ if (!query_ext->extension) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ return; -+ } - memset (query_ext->extension, 0, sizeof (XIMStr)*10); - number = 0; - while (FrameMgrIsIterLoopEnd (fm, &status) == False) -@@ -461,9 +485,20 @@ static void QueryExtensionMessageProc (XIMS ims, - FrameMgrSetSize (fm, str_length); - query_ext->extension[number].length = str_length; - FrameMgrGetToken (fm, name); -+ /* I don't know why extension[number].name is detected as leak -+ * with -Wanalyzer-malloc-leak option in gcc 11.0.1. -+ */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" - query_ext->extension[number].name = malloc (str_length + 1); -- strncpy (query_ext->extension[number].name, name, str_length); -- query_ext->extension[number].name[str_length] = (char) 0; -+ if (!query_ext->extension[number].name) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ } else { -+ strncpy (query_ext->extension[number].name, name, str_length); -+ query_ext->extension[number].name[str_length] = (char) 0; -+ } -+#pragma GCC diagnostic pop - number++; - } - /*endwhile*/ -@@ -490,6 +525,8 @@ static void QueryExtensionMessageProc (XIMS ims, - XFree (query_ext->extension[i].name); - /*endfor*/ - XFree (query_ext->extension); -+ if (!ext_list) -+ return; - - fm = FrameMgrInit (query_extension_reply_fr, - NULL, -@@ -501,7 +538,10 @@ static void QueryExtensionMessageProc (XIMS ims, - /* set length of BARRAY item in ext_fr */ - for (i = 0; i < reply_number; i++) - { -- str_size = strlen (ext_list[i].name); -+ if (ext_list[i].name) -+ str_size = strlen (ext_list[i].name); -+ else -+ str_size = 0; - FrameMgrSetSize (fm, str_size); - } - /*endfor*/ -@@ -700,7 +740,13 @@ static XIMAttribute *MakeIMAttributeList (Xi18n i18n_core, - &value_length); - attrib_list[list_num].value_length = value_length; - attrib_list[list_num].value = (void *) malloc (value_length); -- memset(attrib_list[list_num].value, 0, value_length); -+ if (attrib_list[list_num].value) { -+ memset(attrib_list[list_num].value, 0, value_length); -+ } else { -+ fprintf (stderr, -+ "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ } - GetIMValueFromName (i18n_core, - connect_id, - attrib_list[list_num].value, -@@ -737,10 +783,10 @@ static void GetIMValuesMessageProc (XIMS ims, - register int i; - register int j; - int number; -- CARD16 *im_attrID_list; -- char **name_list; -+ CARD16 *im_attrID_list = NULL; -+ char **name_list = NULL; - CARD16 name_number; -- XIMAttribute *im_attribute_list; -+ XIMAttribute *im_attribute_list = NULL; - IMGetIMValuesStruct *getim = (IMGetIMValuesStruct *)&call_data->getim; - CARD16 connect_id = call_data->any.connect_id; - CARD16 input_method_ID; -@@ -753,8 +799,18 @@ static void GetIMValuesMessageProc (XIMS ims, - FrameMgrGetToken (fm, input_method_ID); - FrameMgrGetToken (fm, byte_length); - im_attrID_list = (CARD16 *) malloc (sizeof (CARD16)*20); -+ if (!im_attrID_list) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ goto GetIMValuesMessageProc_finit; -+ } - memset (im_attrID_list, 0, sizeof (CARD16)*20); - name_list = (char **)malloc(sizeof(char *) * 20); -+ if (!name_list) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ goto GetIMValuesMessageProc_finit; -+ } - memset(name_list, 0, sizeof(char *) * 20); - number = 0; - while (FrameMgrIsIterLoopEnd (fm, &status) == False) -@@ -792,8 +848,11 @@ static void GetIMValuesMessageProc (XIMS ims, - im_attrID_list, - &number, - &list_len); -- if (im_attrID_list) -- XFree (im_attrID_list); -+ if (!im_attribute_list) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ goto GetIMValuesMessageProc_finit2; -+ } - /*endif*/ - - fm = FrameMgrInit (get_im_values_reply_fr, -@@ -815,11 +874,7 @@ 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; -+ goto GetIMValuesMessageProc_finit; - } - /*endif*/ - memset (reply, 0, total_size); -@@ -840,12 +895,18 @@ static void GetIMValuesMessageProc (XIMS ims, - 0, - reply, - total_size); -- FrameMgrFree (fm); - XFree (reply); - -- for (i = 0; i < iter_count; i++) -- XFree(im_attribute_list[i].value); -- XFree (im_attribute_list); -+GetIMValuesMessageProc_finit: -+ FrameMgrFree (fm); -+GetIMValuesMessageProc_finit2: -+ if (im_attrID_list) -+ XFree (im_attrID_list); -+ if (im_attribute_list) { -+ for (i = 0; i < iter_count; i++) -+ XFree(im_attribute_list[i].value); -+ XFree (im_attribute_list); -+ } - } - - static void CreateICMessageProc (XIMS ims, -@@ -1435,6 +1496,11 @@ static void EncodingNegotiatonMessageProc (XIMS ims, - if (byte_length > 0) - { - enc_nego->encoding = (XIMStr *) malloc (sizeof (XIMStr)*10); -+ if (!enc_nego->encoding) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ goto EncodingNegotiatonMessageProc_finit; -+ } - memset (enc_nego->encoding, 0, sizeof (XIMStr)*10); - i = 0; - while (FrameMgrIsIterLoopEnd (fm, &status) == False) -@@ -1446,9 +1512,21 @@ static void EncodingNegotiatonMessageProc (XIMS ims, - FrameMgrSetSize (fm, str_length); - enc_nego->encoding[i].length = str_length; - FrameMgrGetToken (fm, name); -+ /* I don't know why encoding[i].name is detected as leak -+ * with -Wanalyzer-malloc-leak option in gcc 11.0.1. -+ */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" - enc_nego->encoding[i].name = malloc (str_length + 1); -+ if (!(enc_nego->encoding[i].name)) { -+ fprintf (stderr, -+ "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ goto EncodingNegotiatonMessageProc_finit; -+ } - strncpy (enc_nego->encoding[i].name, name, str_length); - enc_nego->encoding[i].name[str_length] = '\0'; -+#pragma GCC diagnostic pop - i++; - } - /*endwhile*/ -@@ -1460,20 +1538,37 @@ static void EncodingNegotiatonMessageProc (XIMS ims, - if (byte_length > 0) - { - enc_nego->encodinginfo = (XIMStr *) malloc (sizeof (XIMStr)*10); -+ if (!enc_nego->encodinginfo) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ goto EncodingNegotiatonMessageProc_finit; -+ } - memset (enc_nego->encodinginfo, 0, sizeof (XIMStr)*10); - i = 0; - while (FrameMgrIsIterLoopEnd (fm, &status) == False) - { - char *name; - int str_length; -- -+ - FrameMgrGetToken (fm, str_length); - FrameMgrSetSize (fm, str_length); - enc_nego->encodinginfo[i].length = str_length; - FrameMgrGetToken (fm, name); -+ /* I don't know why encodinginfo[i].name is detected as leak -+ * with -Wanalyzer-malloc-leak option in gcc 11.0.1. -+ */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" - enc_nego->encodinginfo[i].name = malloc (str_length + 1); -+ if (!enc_nego->encodinginfo[i].name) { -+ fprintf (stderr, -+ "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ goto EncodingNegotiatonMessageProc_finit; -+ } - strncpy (enc_nego->encodinginfo[i].name, name, str_length); - enc_nego->encodinginfo[i].name[str_length] = '\0'; -+#pragma GCC diagnostic pop - i++; - } - /*endwhile*/ -@@ -1524,6 +1619,7 @@ static void EncodingNegotiatonMessageProc (XIMS ims, - total_size); - XFree (reply); - -+EncodingNegotiatonMessageProc_finit: - /* free data for encoding list */ - if (enc_nego->encoding) - { -diff --git a/util/IMdkit/i18nUtil.c b/util/IMdkit/i18nUtil.c -index 109dcdf9..c62154e7 100644 ---- a/util/IMdkit/i18nUtil.c -+++ b/util/IMdkit/i18nUtil.c -@@ -46,6 +46,8 @@ _Xi18nNeedSwap (Xi18n i18n_core, CARD16 connect_id) - CARD8 im_byteOrder = i18n_core->address.im_byteOrder; - Xi18nClient *client = _Xi18nFindClient (i18n_core, connect_id); - -+ if (!client) -+ return True; - return (client->byte_order != im_byteOrder); - } - -@@ -67,6 +69,11 @@ Xi18nClient *_Xi18nNewClient(Xi18n i18n_core) - new_connect_id = ++connect_id; - } - /*endif*/ -+ if (!client) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ return NULL; -+ } - memset (client, 0, sizeof (Xi18nClient)); - client->connect_id = new_connect_id; - client->pending = (XIMPending *) NULL; -@@ -113,7 +120,14 @@ void _Xi18nDeleteClient (Xi18n i18n_core, CARD16 connect_id) - ccp0->next = ccp->next; - /*endif*/ - /* put it back to free list */ -+ /* gcc 11.0.1 warns dereference of NULL with -+ * -Wanalyzer-null-dereference option -+ * but target should not be NULL. -+ */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wanalyzer-null-dereference" - target->next = i18n_core->address.free_clients; -+#pragma GCC diagnostic pop - i18n_core->address.free_clients = target; - return; - } -@@ -161,6 +175,12 @@ void _Xi18nSendMessage (XIMS ims, - - reply_length = header_size + length; - reply = (unsigned char *) malloc (reply_length); -+ if (!reply) { -+ _Xi18nSendMessage (ims, connect_id, XIM_ERROR, 0, 0, 0); -+ XFree (reply_hdr); -+ FrameMgrFree (fm); -+ return; -+ } - replyp = reply; - memmove (reply, reply_hdr, header_size); - replyp += header_size; -diff --git a/util/IMdkit/i18nX.c b/util/IMdkit/i18nX.c -index 5e5c15fa..152fc4e8 100644 ---- a/util/IMdkit/i18nX.c -+++ b/util/IMdkit/i18nX.c -@@ -58,16 +58,21 @@ static XClient *NewXClient (Xi18n i18n_core, Window new_client) - XClient *x_client; - - x_client = (XClient *) malloc (sizeof (XClient)); -- x_client->client_win = new_client; -- x_client->accept_win = XCreateSimpleWindow (dpy, -- DefaultRootWindow(dpy), -- 0, -- 0, -- 1, -- 1, -- 1, -- 0, -- 0); -+ if (!x_client) { -+ fprintf (stderr, "(XIM-IMdkit) WARNING: malloc failed in %s:%d.\n", -+ __FILE__, __LINE__); -+ } else { -+ x_client->client_win = new_client; -+ x_client->accept_win = XCreateSimpleWindow (dpy, -+ DefaultRootWindow(dpy), -+ 0, -+ 0, -+ 1, -+ 1, -+ 1, -+ 0, -+ 0); -+ } - client->trans_rec = x_client; - return ((XClient *) x_client); - } -@@ -219,7 +224,7 @@ static void ReadXConnectMessage (XIMS ims, XClientMessageEvent *ev) - } - /*endif*/ - _XRegisterFilterByType (dpy, -- x_client->accept_win, -+ x_client ? x_client->accept_win : 0, - ClientMessage, - ClientMessage, - WaitXIMProtocol, -@@ -229,7 +234,7 @@ static void ReadXConnectMessage (XIMS ims, XClientMessageEvent *ev) - event.xclient.window = new_client; - event.xclient.message_type = spec->connect_request; - event.xclient.format = 32; -- event.xclient.data.l[0] = x_client->accept_win; -+ event.xclient.data.l[0] = x_client ? x_client->accept_win : 0; - event.xclient.data.l[1] = major_version; - event.xclient.data.l[2] = minor_version; - event.xclient.data.l[3] = XCM_DATA_LIMIT; --- -2.28.0 - -From bc7811c6247b7bb8eba2f9f80c4f9f1510cd6b65 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Wed, 16 Jun 2021 20:39:35 +0900 -Subject: [PATCH] src/tests: Fix ibus-desktop-testing-runner to get gsettings result - -gsettings null string is '' and the quote mark needs to be parsed. -Also no-overview gsetting should be changed before run gnome-session. ---- - src/tests/ibus-desktop-testing-runner.in | 18 +++++++++++------- - 1 file changed, 11 insertions(+), 7 deletions(-) - -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index 15b2369d..54b7e0d7 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -215,9 +215,11 @@ run_dbus_daemon() - - init_gnome() - { -+ # gsettings set command needs dconf-service with the same $DISPLAY -+ pkill dconf-service - # Disable Tour dialog to get focus - V=`gsettings get org.gnome.shell welcome-dialog-last-shown-version` -- if [ x"$V" = x ] ; then -+ if [ x"$V" = x"''" ] ; then - gsettings set org.gnome.shell welcome-dialog-last-shown-version '100' - fi - # gnome-shell now starts overview mode by login. -@@ -237,7 +239,7 @@ init_gnome() - V2=$? - if [ $V2 -ne 0 ] ; then - V3=`echo "$V" | sed -e 's/\[//' -e 's/\]//'` -- if [ x"$V3" = x ] ; then -+ if [ x"$V3" = x"''" ] ; then - V4="['no-overview@fthx']" - else - V4="[$V3, 'no-overview@fthx']" -@@ -248,6 +250,8 @@ init_gnome() - - run_desktop() - { -+ echo "$DESKTOP_COMMAND" | grep gnome-session > /dev/null -+ HAS_GNOME=$? - 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 -@@ -256,15 +260,15 @@ run_desktop() - PID_XORG=$! - sleep 1 - export DISPLAY=$DISPLAY -+ # init_gnome need to be called with $DISPLAY before gnome-session is called -+ if [ $HAS_GNOME -eq 0 ] ; then -+ init_gnome -+ fi - echo "Running $DESKTOP_COMMAND with $USER in `tty`" - $DESKTOP_COMMAND & - PID_GNOME_SESSION=$! - sleep 30 -- echo "$DESKTOP_COMMAND" | grep gnome-session > /dev/null -- HAS_GNOME=$? -- if [ $HAS_GNOME -eq 0 ] ; then -- init_gnome -- else -+ if [ $HAS_GNOME -ne 0 ] ; then - ibus-daemon --daemonize --verbose - sleep 3 - fi --- -2.28.0 - -From 9f9c88be46436b0a7aa8e09e044a2223356b46dc Mon Sep 17 00:00:00 2001 -From: lf- -Date: Fri, 18 Jun 2021 15:39:19 +0900 -Subject: [PATCH] src/ibuscomposetable: Add support for the include - directive - -We also fix an issue with excess space at the start of lines stopping -comments being recognized. - -BUG=https://github.com/ibus/ibus/pull/2296 ---- - src/ibuscomposetable.c | 100 ++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 95 insertions(+), 5 deletions(-) - -diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c -index 685ac717..66a5dfa7 100644 ---- a/src/ibuscomposetable.c -+++ b/src/ibuscomposetable.c -@@ -21,7 +21,6 @@ - - #include - #include --#include - #include - #include - -@@ -36,6 +35,7 @@ - - #define IBUS_COMPOSE_TABLE_MAGIC "IBusComposeTable" - #define IBUS_COMPOSE_TABLE_VERSION (3) -+#define PATHLEN_MAX 256 - - typedef struct { - gunichar *sequence; -@@ -181,7 +181,8 @@ parse_compose_sequence (IBusComposeData *compose_data, - int n = 0; - - if (g_strv_length (words) < 2) { -- g_warning ("key sequence format is ...: %s", line); -+ g_warning ("too few words; key sequence format is ...: %s", -+ line); - goto fail; - } - -@@ -244,10 +245,68 @@ fail: - } - - -+static gchar * -+expand_include_path (const gchar *include_path) { -+ gchar *out = g_malloc0 (PATHLEN_MAX); -+ gchar *out_lastchar = out + PATHLEN_MAX - 2; -+ const gchar *i = include_path; -+ gchar *o = out; -+ -+ while (*i && o < out_lastchar) { -+ // expand sequence -+ if (*i == '%') { -+ switch (*(i+1)) { -+ // $HOME -+ case 'H': { -+ const gchar *home = getenv ("HOME"); -+ if (!home) { -+ g_warning ("while parsing XCompose include target %s, " -+ "%%H replacement failed because HOME is not " -+ "defined; the include has been ignored", -+ include_path); -+ goto fail; -+ } -+ o = out + g_strlcat (out, home, PATHLEN_MAX); -+ break; -+ } -+ // locale compose file -+ case 'L': -+ g_warning ("while handling XCompose include target %s, found " -+ "redundant %%L include; the include has been " -+ "ignored", include_path); -+ goto fail; -+ // system compose dir -+ case 'S': -+ o = out + g_strlcat (out, "/usr/share/X11/locale", -+ PATHLEN_MAX); -+ break; -+ // escaped % -+ case '%': -+ *o++ = '%'; -+ break; -+ default: -+ g_warning ("while parsing XCompose include target %s, found " -+ "unknown substitution character '%c'; the include " -+ "has been ignored", include_path, *(i+1)); -+ goto fail; -+ } -+ i += 2; -+ } else { -+ *o++ = *i++; -+ } -+ } -+ return out; -+fail: -+ g_free (out); -+ return NULL; -+} -+ -+ - static void - parse_compose_line (GList **compose_list, - const gchar *line, -- int *compose_len) -+ int *compose_len, -+ gchar **include) - { - gchar **components = NULL; - IBusComposeData *compose_data = NULL; -@@ -256,11 +315,32 @@ parse_compose_line (GList **compose_list, - g_assert (compose_len); - *compose_len = 0; - -+ // eat spaces at the start of the line -+ while (*line && (*line == ' ' || *line == '\t')) line++; -+ - if (line[0] == '\0' || line[0] == '#') - return; - -- if (g_str_has_prefix (line, "include ")) -+ if (g_str_has_prefix (line, "include ")) { -+ const char *rest = line + sizeof ("include ") - 1; -+ while (*rest && *rest == ' ') rest++; -+ -+ // grabbed the path part of the line -+ char *rest2; -+ if (*rest == '"') { -+ rest++; -+ rest2 = g_strdup (rest); -+ // eat the closing quote -+ char *i = rest2; -+ while (*i && *i != '"') i++; -+ *i = '\0'; -+ } else { -+ rest2 = g_strdup (rest); -+ } -+ *include = expand_include_path (rest2); -+ g_free (rest2); - return; -+ } - - components = g_strsplit (line, ":", 2); - -@@ -316,8 +396,18 @@ ibus_compose_list_parse_file (const gchar *compose_file, - - lines = g_strsplit (contents, "\n", -1); - g_free (contents); -+ gchar *include = NULL; - for (i = 0; lines[i] != NULL; i++) { -- parse_compose_line (&compose_list, lines[i], &compose_len); -+ parse_compose_line (&compose_list, lines[i], &compose_len, &include); -+ if (include && *include) { -+ GList *rest = ibus_compose_list_parse_file (include, -+ max_compose_len); -+ if (rest) { -+ compose_list = g_list_concat (compose_list, rest); -+ } -+ } -+ -+ g_clear_pointer (&include, g_free); - if (*max_compose_len < compose_len) - *max_compose_len = compose_len; - } --- -2.28.0 - -From a755d1601a730b5fa0d463e7820311c12b1f1661 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 18 Jun 2021 15:39:50 +0900 -Subject: [PATCH] src/ibuscomposetable: Do not include the same compose - file - -BUG=https://github.com/ibus/ibus/pull/2296 ---- - src/ibuscomposetable.c | 130 +++++++++++++++++++++++++++++++---------- - 1 file changed, 100 insertions(+), 30 deletions(-) - -diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c -index 66a5dfa7..916fcae3 100644 ---- a/src/ibuscomposetable.c -+++ b/src/ibuscomposetable.c -@@ -34,8 +34,8 @@ - #include "ibusenginesimpleprivate.h" - - #define IBUS_COMPOSE_TABLE_MAGIC "IBusComposeTable" --#define IBUS_COMPOSE_TABLE_VERSION (3) --#define PATHLEN_MAX 256 -+#define IBUS_COMPOSE_TABLE_VERSION (4) -+#define X11_DATADIR X11_DATA_PREFIX "/share/X11/locale" - - typedef struct { - gunichar *sequence; -@@ -247,17 +247,15 @@ fail: - - static gchar * - expand_include_path (const gchar *include_path) { -- gchar *out = g_malloc0 (PATHLEN_MAX); -- gchar *out_lastchar = out + PATHLEN_MAX - 2; -- const gchar *i = include_path; -- gchar *o = out; -+ gchar *out = strdup (""); -+ const gchar *head, *i; -+ gchar *former, *o; - -- while (*i && o < out_lastchar) { -- // expand sequence -+ for (head = i = include_path; *i; ++i) { -+ /* expand sequence */ - if (*i == '%') { -- switch (*(i+1)) { -- // $HOME -- case 'H': { -+ switch (*(i + 1)) { -+ case 'H': { /* $HOME */ - const gchar *home = getenv ("HOME"); - if (!home) { - g_warning ("while parsing XCompose include target %s, " -@@ -266,23 +264,34 @@ expand_include_path (const gchar *include_path) { - include_path); - goto fail; - } -- o = out + g_strlcat (out, home, PATHLEN_MAX); -+ o = out; -+ former = g_strndup (head, i - head); -+ out = g_strdup_printf ("%s%s%s", o, former, home); -+ head = i + 2; -+ g_free (o); -+ g_free (former); - break; - } -- // locale compose file -- case 'L': -+ case 'L': /* locale compose file */ - g_warning ("while handling XCompose include target %s, found " - "redundant %%L include; the include has been " - "ignored", include_path); - goto fail; -- // system compose dir -- case 'S': -- o = out + g_strlcat (out, "/usr/share/X11/locale", -- PATHLEN_MAX); -+ case 'S': /* system compose dir */ -+ o = out; -+ former = g_strndup (head, i - head); -+ out = g_strdup_printf ("%s%s%s", o, former, X11_DATADIR); -+ head = i + 2; -+ g_free (o); -+ g_free (former); - break; -- // escaped % -- case '%': -- *o++ = '%'; -+ case '%': /* escaped % */ -+ o = out; -+ former = g_strndup (head, i - head); -+ out = g_strdup_printf ("%s%s%s", o, former, "%"); -+ head = i + 2; -+ g_free (o); -+ g_free (former); - break; - default: - g_warning ("while parsing XCompose include target %s, found " -@@ -290,11 +299,12 @@ expand_include_path (const gchar *include_path) { - "has been ignored", include_path, *(i+1)); - goto fail; - } -- i += 2; -- } else { -- *o++ = *i++; -+ ++i; - } - } -+ o = out; -+ out = g_strdup_printf ("%s%s", o, head); -+ g_free (o); - return out; - fail: - g_free (out); -@@ -315,7 +325,7 @@ parse_compose_line (GList **compose_list, - g_assert (compose_len); - *compose_len = 0; - -- // eat spaces at the start of the line -+ /* eat spaces at the start of the line */ - while (*line && (*line == ' ' || *line == '\t')) line++; - - if (line[0] == '\0' || line[0] == '#') -@@ -325,12 +335,12 @@ parse_compose_line (GList **compose_list, - const char *rest = line + sizeof ("include ") - 1; - while (*rest && *rest == ' ') rest++; - -- // grabbed the path part of the line -+ /* grabbed the path part of the line */ - char *rest2; - if (*rest == '"') { - rest++; - rest2 = g_strdup (rest); -- // eat the closing quote -+ /* eat the closing quote */ - char *i = rest2; - while (*i && *i != '"') i++; - *i = '\0'; -@@ -374,6 +384,23 @@ fail: - } - - -+static gchar * -+get_en_compose_file (void) -+{ -+ gchar * const sys_langs[] = { "en_US.UTF-8", "en_US", "en.UTF-8", -+ "en", NULL }; -+ gchar * const *sys_lang = NULL; -+ gchar *path = NULL; -+ for (sys_lang = sys_langs; *sys_lang; sys_lang++) { -+ path = g_build_filename (X11_DATADIR, *sys_lang, "Compose", NULL); -+ if (g_file_test (path, G_FILE_TEST_EXISTS)) -+ break; -+ g_free (path); -+ } -+ return path; -+} -+ -+ - static GList * - ibus_compose_list_parse_file (const gchar *compose_file, - int *max_compose_len) -@@ -399,6 +426,52 @@ ibus_compose_list_parse_file (const gchar *compose_file, - gchar *include = NULL; - for (i = 0; lines[i] != NULL; i++) { - parse_compose_line (&compose_list, lines[i], &compose_len, &include); -+ if (*max_compose_len < compose_len) -+ *max_compose_len = compose_len; -+ if (include && *include) { -+ GStatBuf buf_include = { 0, }; -+ GStatBuf buf_parent = { 0, }; -+ gchar *en_compose; -+ errno = 0; -+ if (g_stat (include, &buf_include)) { -+ g_warning ("Cannot access %s: %s", -+ include, -+ g_strerror (errno)); -+ g_clear_pointer (&include, g_free); -+ continue; -+ } -+ errno = 0; -+ if (g_stat (compose_file, &buf_parent)) { -+ g_warning ("Cannot access %s: %s", -+ compose_file, -+ g_strerror (errno)); -+ g_clear_pointer (&include, g_free); -+ continue; -+ } -+ if (buf_include.st_ino == buf_parent.st_ino) { -+ g_warning ("Found recursive nest same file %s", include); -+ g_clear_pointer (&include, g_free); -+ continue; -+ } -+ en_compose = get_en_compose_file (); -+ if (en_compose) { -+ errno = 0; -+ if (g_stat (en_compose, &buf_parent)) { -+ g_warning ("Cannot access %s: %s", -+ compose_file, -+ g_strerror (errno)); -+ g_clear_pointer (&include, g_free); -+ g_free (en_compose); -+ continue; -+ } -+ } -+ g_free (en_compose); -+ if (buf_include.st_ino == buf_parent.st_ino) { -+ g_log ("System en_US Compose is already loaded %s\n", include); -+ g_clear_pointer (&include, g_free); -+ continue; -+ } -+ } - if (include && *include) { - GList *rest = ibus_compose_list_parse_file (include, - max_compose_len); -@@ -406,10 +479,7 @@ ibus_compose_list_parse_file (const gchar *compose_file, - compose_list = g_list_concat (compose_list, rest); - } - } -- - g_clear_pointer (&include, g_free); -- if (*max_compose_len < compose_len) -- *max_compose_len = compose_len; - } - g_strfreev (lines); - --- -2.28.0 - -From 7f09379b3cb69c7de6d8d667ce398dcfc0000433 Mon Sep 17 00:00:00 2001 -From: lf- -Date: Thu, 24 Jun 2021 16:10:12 +0900 -Subject: [PATCH] src/ibuscomposetable: Fix a buffer overflow in compose - handling -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -I believe this has no security impact but it is making my Valgrind sad. - -Thanks to Omni for the help in finding the root cause of this. - -~/.XCompose is: -``` - : "η" - : "ϑ" - : "ɣ" -``` - -BUG=https://github.com/ibus/ibus/pull/2297 ---- - src/ibuscomposetable.c | 15 ++++++++++++--- - 1 file changed, 12 insertions(+), 3 deletions(-) - -diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c -index 916fcae3..dd7cbf83 100644 ---- a/src/ibuscomposetable.c -+++ b/src/ibuscomposetable.c -@@ -410,7 +410,6 @@ ibus_compose_list_parse_file (const gchar *compose_file, - gsize length = 0; - GError *error = NULL; - GList *compose_list = NULL; -- int compose_len = 0; - int i; - - g_assert (max_compose_len); -@@ -423,8 +422,9 @@ ibus_compose_list_parse_file (const gchar *compose_file, - - lines = g_strsplit (contents, "\n", -1); - g_free (contents); -- gchar *include = NULL; - for (i = 0; lines[i] != NULL; i++) { -+ int compose_len = 0; -+ gchar *include = NULL; - parse_compose_line (&compose_list, lines[i], &compose_len, &include); - if (*max_compose_len < compose_len) - *max_compose_len = compose_len; -@@ -467,7 +467,8 @@ ibus_compose_list_parse_file (const gchar *compose_file, - } - g_free (en_compose); - if (buf_include.st_ino == buf_parent.st_ino) { -- g_log ("System en_US Compose is already loaded %s\n", include); -+ g_message ("System en_US Compose is already loaded %s\n", -+ include); - g_clear_pointer (&include, g_free); - continue; - } -@@ -583,12 +584,20 @@ ibus_compose_data_compare (gpointer a, - IBusComposeData *compose_data_b = b; - int max_compose_len = GPOINTER_TO_INT (data); - int i; -+ /* The allocation length of compose_data_a->sequence[] is different from -+ * one of compose_data_b->sequence[] and max_compose_len indicates -+ * the sequence length only but not include the compose value length. -+ * So max_compose_len is greater than any allocation lengths of sequence[] -+ * and this API should return if code_a or code_b is 0. -+ */ - for (i = 0; i < max_compose_len; i++) { - gunichar code_a = compose_data_a->sequence[i]; - gunichar code_b = compose_data_b->sequence[i]; - - if (code_a != code_b) - return code_a - code_b; -+ if (code_a == 0 && code_b == 0) -+ return 0; - } - return 0; - } --- -2.28.0 - -From ab6b9587a497e9662a2936df3dabed4582eeabdb Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 29 Jun 2021 12:40:20 +0900 -Subject: [PATCH] src/tests: Delete G_MESSAGES_DEBUG in desktop-testing for - gsettings - -G_MESSAGES_DEBUG message could be appended to the output of gsettings -command and it's not useful to check the output. ---- - src/tests/ibus-desktop-testing-runner.in | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index 54b7e0d7..0ef72c03 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -217,6 +217,10 @@ init_gnome() - { - # gsettings set command needs dconf-service with the same $DISPLAY - pkill dconf-service -+ # G_MESSAGES_DEBUG=all or G_MESSAGES_DEBUG=GLib-GIO-DEBUG would append -+ # debug messages to gsettings output and could not get the result correctly. -+ backup_G_MESSAGES_DEBUG="$G_MESSAGES_DEBUG" -+ export -n G_MESSAGES_DEBUG='' - # Disable Tour dialog to get focus - V=`gsettings get org.gnome.shell welcome-dialog-last-shown-version` - if [ x"$V" = x"''" ] ; then -@@ -238,14 +242,17 @@ init_gnome() - echo "$V" | grep "no-overview" > /dev/null - V2=$? - if [ $V2 -ne 0 ] ; then -- V3=`echo "$V" | sed -e 's/\[//' -e 's/\]//'` -- if [ x"$V3" = x"''" ] ; then -+ V3=`echo "$V" | sed -e 's/@as //' -e 's/\[//' -e 's/\]//'` -+ if [ x"$V3" = x"''" ] || [ x"$V3" = x"" ]; then - V4="['no-overview@fthx']" - else - V4="[$V3, 'no-overview@fthx']" - fi - gsettings set org.gnome.shell enabled-extensions "$V4" - fi -+ if [ x"$backup_G_MESSAGES_DEBUG" != x ] ; then -+ export G_MESSAGES_DEBUG="$backup_G_MESSAGES_DEBUG" -+ fi - } - - run_desktop() --- -2.28.0 - -From b952d30a1b7c741052c168fe1081ecb4d4b1c034 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Wed, 14 Jul 2021 22:31:47 +0900 -Subject: [PATCH] Change default Emoji shortcut key - -The shortcut key was Ctrl-Shit-e to follow Unicode code point -shortcut key but now the shorcut key is changed to Ctrl-period -to follow GTK. - -BUG=https://github.com/ibus/ibus/issues/2325 ---- - data/dconf/org.freedesktop.ibus.gschema.xml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/data/dconf/org.freedesktop.ibus.gschema.xml b/data/dconf/org.freedesktop.ibus.gschema.xml -index a79e9296..099b9c60 100644 ---- a/data/dconf/org.freedesktop.ibus.gschema.xml -+++ b/data/dconf/org.freedesktop.ibus.gschema.xml -@@ -183,7 +183,7 @@ - The shortcut keys for turning Unicode typing on or off - - -- [ '<Control><Shift>e' ] -+ [ '<Control>period' ] - Emoji shortcut keys for gtk_accelerator_parse - The shortcut keys for turning emoji typing on or off - --- -2.28.0 - -From a4939f67f9de8275219e2cfcd3873e0fbe59058f Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 16 Jul 2021 13:08:02 +0900 -Subject: [PATCH] setup: Enhance engine search function - -ibus-setup can search both the language names and input method names -in the top language list but when you search a language keyword -in the language list and move to the input method list after click -the hit language name, any input methods could not be shown because -the language didn't hit in any input method names. - -In this enhancement, ibus-setup can show the input methods to hit -the language names. ---- - setup/enginedialog.py | 26 ++++++++++++++++++++------ - 1 file changed, 20 insertions(+), 6 deletions(-) - -diff --git a/setup/enginedialog.py b/setup/enginedialog.py -index e1c322bf..470f801c 100644 ---- a/setup/enginedialog.py -+++ b/setup/enginedialog.py -@@ -120,12 +120,26 @@ class EngineDialog(Gtk.Dialog): - return True - if word in row.untrans.lower(): - return True -- if row.lang_info and row.name in self.__engines_for_lang: -- for row_e in self.__engines_for_lang[row.name]: -- if word in row_e.name.lower(): -- return True -- if word in row_e.untrans.lower(): -- return True -+ # Search engine name in language list -+ if row.lang_info: -+ if row.name in self.__engines_for_lang.keys(): -+ for row_l in self.__engines_for_lang[row.name]: -+ if word in row_l.name.lower(): -+ return True -+ if word in row_l.untrans.lower(): -+ return True -+ # Search language name in engine list -+ if not row.lang_info: -+ for l in self.__engines_for_lang.keys(): -+ if word in l.lower(): -+ for row_l in self.__engines_for_lang[l]: -+ if row.name == row_l.name: -+ return True -+ for (trans, untrans) in self.__untrans_for_lang.items(): -+ if word in untrans.lower(): -+ for row_l in self.__engines_for_lang[trans]: -+ if row.name == row_l.name: -+ return True - return False - - --- -2.28.0 - -From 7e12d589ee4979fdd0f0b08f1bac9049741ec628 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Mon, 26 Jul 2021 22:52:12 +0900 -Subject: [PATCH 1/6] src/ibuscomposetable: Move ibus_compose_table_check - -- Move ibus_compose_table_check and ibus_compose_table_compact_check - from ibusenginesimple.c to ibuscomposetable.c -- Fix src/tests/ibus-compose.c to read compose sequences correctly. ---- - src/ibuscomposetable.c | 519 +++++++++++++++++++++++++++++- - src/ibusenginesimple.c | 583 ++++------------------------------ - src/ibusenginesimpleprivate.h | 17 +- - src/tests/Makefile.am | 3 +- - src/tests/ibus-compose.c | 7 +- - 5 files changed, 601 insertions(+), 528 deletions(-) - -diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c -index dd7cbf83..f85177a6 100644 ---- a/src/ibuscomposetable.c -+++ b/src/ibuscomposetable.c -@@ -33,6 +33,13 @@ - - #include "ibusenginesimpleprivate.h" - -+/* This file contains the table of the compose sequences, -+ * static const guint16 gtk_compose_seqs_compact[] = {} -+ * It is generated from the compose-parse.py script. -+ */ -+#include "gtkimcontextsimpleseqs.h" -+ -+ - #define IBUS_COMPOSE_TABLE_MAGIC "IBusComposeTable" - #define IBUS_COMPOSE_TABLE_VERSION (4) - #define X11_DATADIR X11_DATA_PREFIX "/share/X11/locale" -@@ -44,6 +51,10 @@ typedef struct { - } IBusComposeData; - - -+extern const IBusComposeTableCompactEx ibus_compose_table_compact; -+extern const IBusComposeTableCompactEx ibus_compose_table_compact_32bit; -+ -+ - static void - ibus_compose_data_free (IBusComposeData *compose_data) - { -@@ -527,20 +538,22 @@ ibus_compose_list_check_duplicated (GList *compose_list, - is_32bit = (n_outputs > 1) ? TRUE : - (compose_data->values[0] >= 0xFFFF) ? TRUE : FALSE; - if (!is_32bit && -- ibus_check_compact_table (&ibus_compose_table_compact, -- keysyms, -- n_compose, -- &compose_finish, -- &output_chars) && compose_finish) { -+ ibus_compose_table_compact_check (&ibus_compose_table_compact, -+ keysyms, -+ n_compose, -+ &compose_finish, -+ &output_chars) && -+ compose_finish) { - if (compose_data->values[0] == *output_chars) - removed_list = g_list_append (removed_list, compose_data); - g_free (output_chars); - } else if (is_32bit && -- ibus_check_compact_table (&ibus_compose_table_compact_32bit, -- keysyms, -- n_compose, -- &compose_finish, -- &output_chars) && compose_finish) { -+ ibus_compose_table_compact_check ( -+ &ibus_compose_table_compact_32bit, -+ keysyms, -+ n_compose, -+ &compose_finish, -+ &output_chars) && compose_finish) { - - if (n_outputs == unichar_length (output_chars)) { - int j = 0; -@@ -1354,3 +1367,489 @@ ibus_compose_table_list_add_file (GSList *compose_tables, - ibus_compose_table_save_cache (compose_table); - return g_slist_prepend (compose_tables, compose_table); - } -+ -+ -+static int -+compare_seq (const void *key, const void *value) -+{ -+ int i = 0; -+ const guint16 *keysyms = key; -+ const guint16 *seq = value; -+ -+ while (keysyms[i]) { -+ if (keysyms[i] < seq[i]) -+ return -1; -+ else if (keysyms[i] > seq[i]) -+ return 1; -+ -+ i++; -+ } -+ -+ return 0; -+} -+ -+ -+gboolean -+ibus_compose_table_check (const IBusComposeTableEx *table, -+ guint16 *compose_buffer, -+ gint n_compose, -+ gboolean *compose_finish, -+ gboolean *compose_match, -+ GString *output, -+ gboolean is_32bit) -+{ -+ gint row_stride = table->max_seq_len + 2; -+ guint16 *data_first; -+ int n_seqs; -+ guint16 *seq; -+ -+ if (compose_finish) -+ *compose_finish = FALSE; -+ if (compose_match) -+ *compose_match = FALSE; -+ if (output) -+ g_string_set_size (output, 0); -+ -+ if (n_compose > table->max_seq_len) -+ return FALSE; -+ -+ if (is_32bit) { -+ if (!table->priv) -+ return FALSE; -+ data_first = table->priv->data_first; -+ n_seqs = table->priv->first_n_seqs; -+ } else { -+ data_first = table->data; -+ n_seqs = table->n_seqs; -+ } -+ seq = bsearch (compose_buffer, -+ data_first, n_seqs, -+ sizeof (guint16) * row_stride, -+ compare_seq); -+ -+ if (seq == NULL) -+ return FALSE; -+ -+ guint16 *prev_seq; -+ -+ /* Back up to the first sequence that matches to make sure -+ * we find the exact match if their is one. -+ */ -+ while (seq > data_first) { -+ prev_seq = seq - row_stride; -+ if (compare_seq (compose_buffer, prev_seq) != 0) -+ break; -+ seq = prev_seq; -+ } -+ -+ /* complete sequence */ -+ if (n_compose == table->max_seq_len || seq[n_compose] == 0) { -+ guint16 *next_seq; -+ gunichar value = 0; -+ int num = 0; -+ int index = 0; -+ gchar *output_str = NULL; -+ GError *error = NULL; -+ -+ if (is_32bit) { -+ num = seq[table->max_seq_len]; -+ index = seq[table->max_seq_len + 1]; -+ value = table->priv->data_second[index]; -+ } else { -+ value = seq[table->max_seq_len]; -+ } -+ -+ if (is_32bit) { -+ output_str = g_ucs4_to_utf8 (table->priv->data_second + index, -+ num, NULL, NULL, &error); -+ if (output_str) { -+ if (output) -+ g_string_append (output, output_str); -+ g_free (output_str); -+ if (compose_match) -+ *compose_match = TRUE; -+ } else { -+ g_warning ("Failed to output multiple characters: %s", -+ error->message); -+ g_error_free (error); -+ } -+ } else { -+ if (output) -+ g_string_append_unichar (output, value); -+ if (compose_match) -+ *compose_match = TRUE; -+ } -+ -+ /* We found a tentative match. See if there are any longer -+ * sequences containing this subsequence -+ */ -+ next_seq = seq + row_stride; -+ if (next_seq < data_first + row_stride * n_seqs) { -+ if (compare_seq (compose_buffer, next_seq) == 0) -+ return TRUE; -+ } -+ -+ if (compose_finish) -+ *compose_finish = TRUE; -+ compose_buffer[0] = 0; -+ } -+ return TRUE; -+} -+ -+ -+static int -+compare_seq_index (const void *key, const void *value) -+{ -+ const guint16 *keysyms = key; -+ const guint16 *seq = value; -+ -+ if (keysyms[0] < seq[0]) -+ return -1; -+ else if (keysyms[0] > seq[0]) -+ return 1; -+ return 0; -+} -+ -+ -+/** -+ * ibus_compose_table_compact_check: -+ * @table: A const `IBusComposeTableCompactEx` -+ * @compose_buffer: Typed compose sequence buffer -+ * @n_compose: The length of `compose_buffer` -+ * @compose_finish: If %TRUE, `output_chars` should be committed -+ * @output_chars: An array of gunichar of output compose characters -+ * -+ * output_chars is better to use gunichar instead of GString because -+ * IBusComposeData->values[] is the gunichar array. -+ */ -+gboolean -+ibus_compose_table_compact_check (const IBusComposeTableCompactEx *table, -+ guint16 -+ *compose_buffer, -+ gint n_compose, -+ gboolean -+ *compose_finish, -+ gunichar **output_chars) -+{ -+ gint row_stride; -+ guint16 *seq_index; -+ guint16 *seq; -+ gint i; -+ -+ if (compose_finish) -+ *compose_finish = FALSE; -+ if (output_chars) -+ *output_chars = NULL; -+ -+ /* Will never match, if the sequence in the compose buffer is longer -+ * than the sequences in the table. Further, compare_seq (key, val) -+ * will overrun val if key is longer than val. */ -+ if (n_compose > table->max_seq_len) -+ return FALSE; -+ -+ seq_index = bsearch (compose_buffer, -+ table->data, -+ table->n_index_size, -+ sizeof (guint16) * table->n_index_stride, -+ compare_seq_index); -+ -+ if (seq_index == NULL) -+ return FALSE; -+ -+ if (n_compose == 1) -+ return TRUE; -+ -+ seq = NULL; -+ -+ if (table->priv) { -+ for (i = n_compose - 1; i < table->max_seq_len; i++) { -+ row_stride = i + 2; -+ -+ if (seq_index[i + 1] - seq_index[i] > 0) { -+ seq = bsearch (compose_buffer + 1, -+ table->data + seq_index[i], -+ (seq_index[i + 1] - seq_index[i]) / row_stride, -+ sizeof (guint16) * row_stride, -+ compare_seq); -+ if (seq) { -+ if (i == n_compose - 1) -+ break; -+ else -+ return TRUE; -+ } -+ } -+ } -+ if (!seq) { -+ return FALSE; -+ } else { -+ int index = seq[row_stride - 2]; -+ int length = seq[row_stride - 1]; -+ int j; -+ if (compose_finish) -+ *compose_finish = TRUE; -+ if (output_chars) { -+ *output_chars = g_new (gunichar, length + 1); -+ for (j = 0; j < length; j++) { -+ (*output_chars)[j] = table->priv->data2[index + j]; -+ } -+ (*output_chars)[length] = 0; -+ } -+ -+ return TRUE; -+ } -+ } else { -+ for (i = n_compose - 1; i < table->max_seq_len; i++) { -+ row_stride = i + 1; -+ -+ if (seq_index[i + 1] - seq_index[i] > 0) { -+ seq = bsearch (compose_buffer + 1, -+ table->data + seq_index[i], -+ (seq_index[i + 1] - seq_index[i]) / row_stride, -+ sizeof (guint16) * row_stride, -+ compare_seq); -+ -+ if (seq) { -+ if (i == n_compose - 1) -+ break; -+ else -+ return TRUE; -+ } -+ } -+ } -+ if (!seq) { -+ return FALSE; -+ } else { -+ if (compose_finish) -+ *compose_finish = TRUE; -+ if (output_chars) { -+ *output_chars = g_new (gunichar, 2); -+ (*output_chars)[0] = seq[row_stride - 1]; -+ (*output_chars)[1] = 0; -+ } -+ -+ return TRUE; -+ } -+ } -+ -+ g_assert_not_reached (); -+} -+ -+ -+/* Checks if a keysym is a dead key. Dead key keysym values are defined in -+ * ../gdk/gdkkeysyms.h and the first is GDK_KEY_dead_grave. As X.Org is updated, -+ * more dead keys are added and we need to update the upper limit. -+ * Currently, the upper limit is GDK_KEY_dead_dasia+1. The +1 has to do with -+ * a temporary issue in the X.Org header files. -+ * In future versions it will be just the keysym (no +1). -+ */ -+#define IS_DEAD_KEY(k) \ -+ ((k) >= IBUS_KEY_dead_grave && (k) <= IBUS_KEY_dead_greek) -+ -+/* This function receives a sequence of Unicode characters and tries to -+ * normalize it (NFC). We check for the case the the resulting string -+ * has length 1 (single character). -+ * NFC normalisation normally rearranges diacritic marks, unless these -+ * belong to the same Canonical Combining Class. -+ * If they belong to the same canonical combining class, we produce all -+ * permutations of the diacritic marks, then attempt to normalize. -+ */ -+static gboolean -+check_normalize_nfc (gunichar* combination_buffer, gint n_compose) -+{ -+ gunichar combination_buffer_temp[IBUS_MAX_COMPOSE_LEN]; -+ gchar *combination_utf8_temp = NULL; -+ gchar *nfc_temp = NULL; -+ gint n_combinations; -+ gunichar temp_swap; -+ gint i; -+ -+ n_combinations = 1; -+ -+ for (i = 1; i < n_compose; i++ ) -+ n_combinations *= i; -+ -+ /* Xorg reuses dead_tilde for the perispomeni diacritic mark. -+ * We check if base character belongs to Greek Unicode block, -+ * and if so, we replace tilde with perispomeni. */ -+ if (combination_buffer[0] >= 0x390 && combination_buffer[0] <= 0x3FF) { -+ for (i = 1; i < n_compose; i++ ) -+ if (combination_buffer[i] == 0x303) -+ combination_buffer[i] = 0x342; -+ } -+ -+ memcpy (combination_buffer_temp, -+ combination_buffer, -+ IBUS_MAX_COMPOSE_LEN * sizeof (gunichar) ); -+ -+ for (i = 0; i < n_combinations; i++ ) { -+ g_unicode_canonical_ordering (combination_buffer_temp, n_compose); -+ combination_utf8_temp = g_ucs4_to_utf8 (combination_buffer_temp, -1, -+ NULL, NULL, NULL); -+ nfc_temp = g_utf8_normalize (combination_utf8_temp, -1, -+ G_NORMALIZE_NFC); -+ -+ if (g_utf8_strlen (nfc_temp, -1) == 1) { -+ memcpy (combination_buffer, -+ combination_buffer_temp, -+ IBUS_MAX_COMPOSE_LEN * sizeof (gunichar) ); -+ -+ g_free (combination_utf8_temp); -+ g_free (nfc_temp); -+ -+ return TRUE; -+ } -+ -+ g_free (combination_utf8_temp); -+ g_free (nfc_temp); -+ -+ if (n_compose > 2) { -+ 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; -+ } -+ } -+ -+ return FALSE; -+} -+ -+ -+gboolean -+ibus_check_algorithmically (const guint16 *compose_buffer, -+ gint n_compose, -+ gunichar *output_char) -+ -+{ -+ gint i; -+ gunichar combination_buffer[IBUS_MAX_COMPOSE_LEN]; -+ gchar *combination_utf8, *nfc; -+ -+ if (output_char) -+ *output_char = 0; -+ -+ if (n_compose >= IBUS_MAX_COMPOSE_LEN) -+ return FALSE; -+ -+ for (i = 0; i < n_compose && IS_DEAD_KEY (compose_buffer[i]); i++) -+ ; -+ if (i == n_compose) -+ return TRUE; -+ -+ if (i > 0 && i == n_compose - 1) { -+ combination_buffer[0] = ibus_keyval_to_unicode (compose_buffer[i]); -+ combination_buffer[n_compose] = 0; -+ i--; -+ while (i >= 0) { -+ 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--; -+ } -+ -+ /* If the buffer normalizes to a single character, -+ * then modify the order of combination_buffer accordingly, if -+ * necessary, and return TRUE. -+ */ -+ if (check_normalize_nfc (combination_buffer, n_compose)) { -+ combination_utf8 = g_ucs4_to_utf8 (combination_buffer, -1, -+ NULL, NULL, NULL); -+ nfc = g_utf8_normalize (combination_utf8, -1, G_NORMALIZE_NFC); -+ -+ if (output_char) -+ *output_char = g_utf8_get_char (nfc); -+ -+ g_free (combination_utf8); -+ g_free (nfc); -+ -+ return TRUE; -+ } -+ } -+ -+ return FALSE; -+} -+ -+ -+gunichar -+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_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_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_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 -+} -diff --git a/src/ibusenginesimple.c b/src/ibusenginesimple.c -index 6dbc39c7..4644620b 100644 ---- a/src/ibusenginesimple.c -+++ b/src/ibusenginesimple.c -@@ -91,11 +91,6 @@ struct _IBusEngineSimplePrivate { - gboolean lookup_table_visible; - }; - --struct _IBusComposeTableCompactPrivate --{ -- const guint32 *data2; --}; -- - /* From the values below, the value 30 means the number of different first keysyms - * that exist in the Compose file (from Xorg). When running compose-parse.py without - * parameters, you get the count that you can put here. Needed when updating the -@@ -124,6 +119,7 @@ const IBusComposeTableCompactEx ibus_compose_table_compact_32bit = { - }; - - guint COMPOSE_BUFFER_SIZE = 20; -+G_LOCK_DEFINE_STATIC (global_tables); - static GSList *global_tables; - - /* functions prototype */ -@@ -261,74 +257,6 @@ ibus_engine_simple_commit_char (IBusEngineSimple *simple, - ibus_text_new_from_unichar (ch)); - } - --static gunichar --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_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_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_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 - ibus_engine_simple_commit_str (IBusEngineSimple *simple, -@@ -607,415 +535,6 @@ check_emoji_table (IBusEngineSimple *simple, - return FALSE; - } - --static int --compare_seq_index (const void *key, const void *value) --{ -- const guint16 *keysyms = key; -- const guint16 *seq = value; -- -- if (keysyms[0] < seq[0]) -- return -1; -- else if (keysyms[0] > seq[0]) -- return 1; -- return 0; --} -- --static int --compare_seq (const void *key, const void *value) --{ -- int i = 0; -- const guint16 *keysyms = key; -- const guint16 *seq = value; -- -- while (keysyms[i]) { -- if (keysyms[i] < seq[i]) -- return -1; -- else if (keysyms[i] > seq[i]) -- return 1; -- -- i++; -- } -- -- return 0; --} -- -- --static gboolean --check_table (IBusEngineSimple *simple, -- const IBusComposeTableEx *table, -- gint n_compose, -- gboolean is_32bit) --{ -- IBusEngineSimplePrivate *priv = simple->priv; -- gint row_stride = table->max_seq_len + 2; -- guint16 *data_first; -- int n_seqs; -- guint16 *seq; -- -- g_assert (IBUS_IS_ENGINE_SIMPLE (simple)); -- CHECK_COMPOSE_BUFFER_LENGTH (n_compose); -- -- if (n_compose > table->max_seq_len) -- return FALSE; -- -- if (is_32bit) { -- if (!table->priv) -- return FALSE; -- data_first = table->priv->data_first; -- n_seqs = table->priv->first_n_seqs; -- } else { -- data_first = table->data; -- n_seqs = table->n_seqs; -- } -- seq = bsearch (priv->compose_buffer, -- data_first, n_seqs, -- sizeof (guint16) * row_stride, -- compare_seq); -- -- if (seq == NULL) -- return FALSE; -- -- guint16 *prev_seq; -- -- priv->tentative_match = 0; -- priv->tentative_match_len = 0; -- /* Back up to the first sequence that matches to make sure -- * we find the exact match if their is one. -- */ -- while (seq > data_first) { -- prev_seq = seq - row_stride; -- if (compare_seq (priv->compose_buffer, prev_seq) != 0) { -- break; -- } -- seq = prev_seq; -- } -- -- /* complete sequence */ -- if (n_compose == table->max_seq_len || seq[n_compose] == 0) { -- guint16 *next_seq; -- gunichar value = 0; -- int num = 0; -- int index = 0; -- gchar *output_str = NULL; -- GError *error = NULL; -- -- if (is_32bit) { -- num = seq[table->max_seq_len]; -- index = seq[table->max_seq_len + 1]; -- value = table->priv->data_second[index]; -- } else { -- value = seq[table->max_seq_len]; -- } -- -- /* We found a tentative match. See if there are any longer -- * sequences containing this subsequence -- */ -- next_seq = seq + row_stride; -- if (next_seq < data_first + row_stride * n_seqs) { -- if (compare_seq (priv->compose_buffer, next_seq) == 0) { -- priv->tentative_match = value; -- priv->tentative_match_len = n_compose; -- -- ibus_engine_simple_update_preedit_text (simple); -- -- return TRUE; -- } -- } -- -- if (is_32bit) { -- output_str = g_ucs4_to_utf8 (table->priv->data_second + index, -- num, NULL, NULL, &error); -- if (output_str) { -- ibus_engine_simple_commit_str(simple, output_str); -- g_free (output_str); -- } else { -- g_warning ("Failed to output multiple characters: %s", -- error->message); -- g_error_free (error); -- } -- } else { -- ibus_engine_simple_commit_char (simple, value); -- } -- priv->compose_buffer[0] = 0; -- } -- ibus_engine_simple_update_preedit_text (simple); -- return TRUE; --} -- --gboolean --ibus_check_compact_table (const IBusComposeTableCompactEx *table, -- guint16 *compose_buffer, -- gint n_compose, -- gboolean *compose_finish, -- gunichar **output_chars) --{ -- gint row_stride; -- guint16 *seq_index; -- guint16 *seq; -- gint i; -- -- if (compose_finish) -- *compose_finish = FALSE; -- if (output_chars) -- *output_chars = NULL; -- -- CHECK_COMPOSE_BUFFER_LENGTH (n_compose); -- -- /* Will never match, if the sequence in the compose buffer is longer -- * than the sequences in the table. Further, compare_seq (key, val) -- * will overrun val if key is longer than val. */ -- if (n_compose > table->max_seq_len) -- return FALSE; -- -- // g_debug ("check_compact_table(n_compose=%d) [%04x, %04x, %04x, %04x]", -- // n_compose, -- // compose_buffer[0], -- // compose_buffer[1], -- // compose_buffer[2], -- // compose_buffer[3]); -- -- seq_index = bsearch (compose_buffer, -- table->data, -- table->n_index_size, -- sizeof (guint16) * table->n_index_stride, -- compare_seq_index); -- -- if (seq_index == NULL) { -- // g_debug ("compact: no\n"); -- return FALSE; -- } -- -- if (n_compose == 1) { -- // g_debug ("compact: yes\n"); -- return TRUE; -- } -- -- // g_debug ("compact: %04x ", *seq_index); -- seq = NULL; -- -- if (table->priv) { -- for (i = n_compose - 1; i < table->max_seq_len; i++) { -- row_stride = i + 2; -- -- if (seq_index[i + 1] - seq_index[i] > 0) { -- seq = bsearch (compose_buffer + 1, -- table->data + seq_index[i], -- (seq_index[i + 1] - seq_index[i]) / row_stride, -- sizeof (guint16) * row_stride, -- compare_seq); -- if (seq) { -- if (i == n_compose - 1) -- break; -- else -- return TRUE; -- } -- } -- } -- if (!seq) { -- return FALSE; -- } else { -- int index = seq[row_stride - 2]; -- int length = seq[row_stride - 1]; -- int j; -- if (compose_finish) -- *compose_finish = TRUE; -- if (output_chars) { -- *output_chars = g_new (gunichar, length + 1); -- for (j = 0; j < length; j++) -- (*output_chars)[j] = table->priv->data2[index + j]; -- (*output_chars)[length] = 0; -- } -- -- // g_debug ("U+%04X\n", value); -- return TRUE; -- } -- } else { -- for (i = n_compose - 1; i < table->max_seq_len; i++) { -- row_stride = i + 1; -- -- if (seq_index[i + 1] - seq_index[i] > 0) { -- seq = bsearch (compose_buffer + 1, -- table->data + seq_index[i], -- (seq_index[i + 1] - seq_index[i]) / row_stride, -- sizeof (guint16) * row_stride, -- compare_seq); -- -- if (seq) { -- if (i == n_compose - 1) -- break; -- else -- return TRUE; -- } -- } -- } -- if (!seq) { -- return FALSE; -- } else { -- if (compose_finish) -- *compose_finish = TRUE; -- if (output_chars) { -- *output_chars = g_new (gunichar, 2); -- (*output_chars)[0] = seq[row_stride - 1]; -- (*output_chars)[1] = 0; -- } -- -- // g_debug ("U+%04X\n", value); -- return TRUE; -- } -- } -- -- g_assert_not_reached (); --} -- -- --/* Checks if a keysym is a dead key. Dead key keysym values are defined in -- * ../gdk/gdkkeysyms.h and the first is GDK_KEY_dead_grave. As X.Org is updated, -- * more dead keys are added and we need to update the upper limit. -- * Currently, the upper limit is GDK_KEY_dead_dasia+1. The +1 has to do with -- * a temporary issue in the X.Org header files. -- * In future versions it will be just the keysym (no +1). -- */ --#define IS_DEAD_KEY(k) \ -- ((k) >= IBUS_KEY_dead_grave && (k) <= (IBUS_KEY_dead_dasia + 1)) -- --/* This function receives a sequence of Unicode characters and tries to -- * normalize it (NFC). We check for the case the the resulting string -- * has length 1 (single character). -- * NFC normalisation normally rearranges diacritic marks, unless these -- * belong to the same Canonical Combining Class. -- * If they belong to the same canonical combining class, we produce all -- * permutations of the diacritic marks, then attempt to normalize. -- */ --static gboolean --check_normalize_nfc (gunichar* combination_buffer, gint n_compose) --{ -- gunichar combination_buffer_temp[IBUS_MAX_COMPOSE_LEN]; -- gchar *combination_utf8_temp = NULL; -- gchar *nfc_temp = NULL; -- gint n_combinations; -- gunichar temp_swap; -- gint i; -- -- n_combinations = 1; -- -- CHECK_COMPOSE_BUFFER_LENGTH (n_compose); -- -- for (i = 1; i < n_compose; i++ ) -- n_combinations *= i; -- -- /* Xorg reuses dead_tilde for the perispomeni diacritic mark. -- * We check if base character belongs to Greek Unicode block, -- * and if so, we replace tilde with perispomeni. */ -- if (combination_buffer[0] >= 0x390 && combination_buffer[0] <= 0x3FF) { -- for (i = 1; i < n_compose; i++ ) -- if (combination_buffer[i] == 0x303) -- combination_buffer[i] = 0x342; -- } -- -- memcpy (combination_buffer_temp, -- combination_buffer, -- IBUS_MAX_COMPOSE_LEN * sizeof (gunichar) ); -- -- for (i = 0; i < n_combinations; i++ ) { -- g_unicode_canonical_ordering (combination_buffer_temp, n_compose); -- combination_utf8_temp = g_ucs4_to_utf8 (combination_buffer_temp, -1, NULL, NULL, NULL); -- nfc_temp = g_utf8_normalize (combination_utf8_temp, -1, G_NORMALIZE_NFC); -- -- if (g_utf8_strlen (nfc_temp, -1) == 1) { -- memcpy (combination_buffer, -- combination_buffer_temp, -- IBUS_MAX_COMPOSE_LEN * sizeof (gunichar) ); -- -- g_free (combination_utf8_temp); -- g_free (nfc_temp); -- -- return TRUE; -- } -- -- g_free (combination_utf8_temp); -- g_free (nfc_temp); -- -- if (n_compose > 2) { -- 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; -- } -- -- return FALSE; --} -- --gboolean --ibus_check_algorithmically (const guint16 *compose_buffer, -- gint n_compose, -- gunichar *output_char) -- --{ -- gint i; -- gunichar combination_buffer[IBUS_MAX_COMPOSE_LEN]; -- gchar *combination_utf8, *nfc; -- -- if (output_char) -- *output_char = 0; -- -- CHECK_COMPOSE_BUFFER_LENGTH (n_compose); -- -- if (n_compose >= IBUS_MAX_COMPOSE_LEN) -- return FALSE; -- -- for (i = 0; i < n_compose && IS_DEAD_KEY (compose_buffer[i]); i++) -- ; -- if (i == n_compose) -- return TRUE; -- -- if (i > 0 && i == n_compose - 1) { -- combination_buffer[0] = ibus_keyval_to_unicode (compose_buffer[i]); -- combination_buffer[n_compose] = 0; -- i--; -- while (i >= 0) { -- 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--; -- } -- -- /* If the buffer normalizes to a single character, -- * then modify the order of combination_buffer accordingly, if necessary, -- * and return TRUE. -- */ -- if (check_normalize_nfc (combination_buffer, n_compose)) { -- combination_utf8 = g_ucs4_to_utf8 (combination_buffer, -1, NULL, NULL, NULL); -- nfc = g_utf8_normalize (combination_utf8, -1, G_NORMALIZE_NFC); -- -- if (output_char) -- *output_char = g_utf8_get_char (nfc); -- -- g_free (combination_utf8); -- g_free (nfc); -- -- return TRUE; -- } -- } -- -- return FALSE; --} - - static gboolean - no_sequence_matches (IBusEngineSimple *simple, -@@ -1184,34 +703,71 @@ ibus_engine_simple_check_all_compose_table (IBusEngineSimple *simple, - gint n_compose) - { - IBusEngineSimplePrivate *priv = simple->priv; -- gboolean compose_finish; -- gunichar output_char; -+ gboolean compose_finish = FALSE; -+ gboolean compose_match = FALSE; -+ GString *output = g_string_new (""); -+ gboolean does_hit = FALSE; -+ gboolean is_32bit = FALSE; -+ GSList *tmp_list; - gunichar *output_chars = NULL; -- gchar *output_str = NULL; -- GError *error = NULL; -- GSList *list = global_tables; -+ gunichar output_char; - -- while (list) { -- if (check_table (simple, -- (IBusComposeTableEx *)list->data, -+ G_LOCK (global_tables); -+ tmp_list = global_tables; -+ while (tmp_list) { -+ is_32bit = FALSE; -+ if (ibus_compose_table_check ( -+ (IBusComposeTableEx *)tmp_list->data, -+ priv->compose_buffer, - n_compose, -- FALSE)) { -- return TRUE; -+ &compose_finish, -+ &compose_match, -+ output, -+ is_32bit)) { -+ does_hit = TRUE; -+ break; - } -- if (check_table (simple, -- (IBusComposeTableEx *)list->data, -+ is_32bit = TRUE; -+ if (ibus_compose_table_check ( -+ (IBusComposeTableEx *)tmp_list->data, -+ priv->compose_buffer, - n_compose, -- TRUE)) { -- return TRUE; -+ &compose_finish, -+ &compose_match, -+ output, -+ is_32bit)) { -+ does_hit = TRUE; -+ break; - } -- list = list->next; -+ tmp_list = tmp_list->next; - } -+ G_UNLOCK (global_tables); - -- if (ibus_check_compact_table (&ibus_compose_table_compact, -- priv->compose_buffer, -- n_compose, -- &compose_finish, -- &output_chars)) { -+ if (does_hit) { -+ if (compose_finish) { -+ if (compose_match) { -+ if (is_32bit) { -+ ibus_engine_simple_commit_str (simple, output->str); -+ } else { -+ ibus_engine_simple_commit_char (simple, -+ g_utf8_get_char (output->str)); -+ } -+ } -+ } else if (compose_match) { -+ priv->tentative_match = g_utf8_get_char (output->str); -+ priv->tentative_match_len = n_compose; -+ } -+ ibus_engine_simple_update_preedit_text (simple); -+ g_string_free (output, TRUE); -+ return TRUE; -+ } -+ g_string_free (output, TRUE); -+ -+ if (ibus_compose_table_compact_check (&ibus_compose_table_compact, -+ priv->compose_buffer, -+ n_compose, -+ &compose_finish, -+ &output_chars)) { - if (compose_finish) { - ibus_engine_simple_commit_char (simple, *output_chars); - g_free (output_chars); -@@ -1220,28 +776,29 @@ ibus_engine_simple_check_all_compose_table (IBusEngineSimple *simple, - ibus_engine_simple_update_preedit_text (simple); - return TRUE; - } -- if (ibus_check_compact_table (&ibus_compose_table_compact_32bit, -- priv->compose_buffer, -- n_compose, -- &compose_finish, -- &output_chars)) { -+ if (ibus_compose_table_compact_check (&ibus_compose_table_compact_32bit, -+ priv->compose_buffer, -+ n_compose, -+ &compose_finish, -+ &output_chars)) { - if (compose_finish) { -- output_str = g_ucs4_to_utf8 (output_chars, -1, NULL, NULL, &error); -- if (output_str) { -- ibus_engine_simple_commit_str (simple, output_str); -- g_free (output_str); -+ GError *error = NULL; -+ char *str = g_ucs4_to_utf8 (output_chars, -1, NULL, NULL, &error); -+ if (str) { -+ ibus_engine_simple_commit_str (simple, str); -+ g_free (str); - } else { - g_warning ("Failed to output multiple characters: %s", - error->message); - g_error_free (error); - } -- g_free (output_chars); - priv->compose_buffer[0] = 0; - } -- -+ g_free (output_chars); - ibus_engine_simple_update_preedit_text (simple); - return TRUE; - } -+ g_assert (!output_chars); - if (ibus_check_algorithmically (priv->compose_buffer, - n_compose, - &output_char)) { -diff --git a/src/ibusenginesimpleprivate.h b/src/ibusenginesimpleprivate.h -index 508d9344..47f2a3d4 100644 ---- a/src/ibusenginesimpleprivate.h -+++ b/src/ibusenginesimpleprivate.h -@@ -37,15 +37,30 @@ struct _IBusComposeTablePrivate - gsize second_size; - }; - -+struct _IBusComposeTableCompactPrivate -+{ -+ const guint32 *data2; -+}; -+ - gboolean ibus_check_algorithmically (const guint16 *compose_buffer, - gint n_compose, - gunichar *output); --gboolean ibus_check_compact_table (const IBusComposeTableCompactEx -+gboolean ibus_compose_table_check (const IBusComposeTableEx *table, -+ guint16 *compose_buffer, -+ gint n_compose, -+ gboolean *compose_finish, -+ gboolean *compose_match, -+ GString *output, -+ gboolean is_32bit); -+gboolean ibus_compose_table_compact_check -+ (const IBusComposeTableCompactEx - *table, - guint16 *compose_buffer, - gint n_compose, - gboolean *compose_finish, - gunichar **output_chars); -+gunichar ibus_keysym_to_unicode (guint16 keysym, -+ gboolean combining); - - G_END_DECLS - -diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am -index 0a2e523c..13c06eb4 100644 ---- a/src/tests/Makefile.am -+++ b/src/tests/Makefile.am -@@ -3,7 +3,7 @@ - # ibus - The Input Bus - # - # Copyright (c) 2007-2015 Peng Huang --# Copyright (c) 2015-2019 Takao Fujiwara -+# Copyright (c) 2015-2021 Takao Fujiwara - # Copyright (c) 2007-2018 Red Hat, Inc. - # - # This library is free software; you can redistribute it and/or -@@ -30,6 +30,7 @@ AM_CPPFLAGS = \ - @GLIB2_CFLAGS@ \ - @GIO2_CFLAGS@ \ - -DIBUS_DISABLE_DEPRECATION_WARNINGS \ -+ -DX11_DATA_PREFIX=\"$(X11_PREFIX)\" \ - -I$(top_srcdir)/src \ - -I$(top_builddir)/src \ - $(NULL) -diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c -index 81bfc69b..0be01d27 100644 ---- a/src/tests/ibus-compose.c -+++ b/src/tests/ibus-compose.c -@@ -6,6 +6,7 @@ - #define GREEN "\033[0;32m" - #define RED "\033[0;31m" - #define NC "\033[0m" -+#define X11_DATADIR X11_DATA_PREFIX "/share/X11/locale" - - IBusBus *m_bus; - gchar *m_compose_file; -@@ -35,7 +36,7 @@ get_compose_path () - break; - if (g_strcmp0 (*l, "C") == 0) - break; -- compose_path = g_build_filename ("/usr/share/X11/locale", -+ compose_path = g_build_filename (X11_DATADIR, - *l, - "Compose", - NULL); -@@ -155,7 +156,7 @@ set_engine_cb (GObject *object, GAsyncResult *res, gpointer data) - for (i = 0; - i < (m_compose_table->n_seqs * index_stride); - i += index_stride) { -- for (j = i; j < i + (index_stride - 1); j++) { -+ for (j = i; j < i + (index_stride - 2); j++) { - guint keyval = m_compose_table->data[j]; - guint keycode = 0; - guint modifiers = 0; -@@ -175,7 +176,7 @@ set_engine_cb (GObject *object, GAsyncResult *res, gpointer data) - for (i = 0; - i < (priv->first_n_seqs * index_stride); - i += index_stride) { -- for (j = i; j < i + (index_stride - 1); j++) { -+ for (j = i; j < i + (index_stride - 2); j++) { - guint keyval = priv->data_first[j]; - guint keycode = 0; - guint modifiers = 0; --- -2.28.0 - -From 2fc1a028aa697f1320d85a76548cde12894bf9ab Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Mon, 26 Jul 2021 22:52:18 +0900 -Subject: [PATCH 2/6] src/ibusenginesimple: Multi_key to 0xB7 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use · instead of ⎄ to display Multi_key in pre-edit. - -BUG=https://gitlab.gnome.org/GNOME/gtk/-/issues/3669 -BUG=https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/3220 ---- - src/ibuscomposetable.c | 8 ++++++- - src/ibusenginesimple.c | 49 ++++++++++++++++++++---------------------- - 2 files changed, 30 insertions(+), 27 deletions(-) - -diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c -index f85177a6..4ebf119b 100644 ---- a/src/ibuscomposetable.c -+++ b/src/ibuscomposetable.c -@@ -1846,7 +1846,13 @@ ibus_keysym_to_unicode (guint16 keysym, - CASE_COMBINE (tilde, 0x0303, 0x007E); - CASE_COMBINE (voiced_sound, 0x3099, 0x309B); - case IBUS_KEY_Multi_key: -- return 0x2384; -+ /* We only show the Compose key visibly when it is the -+ * only glyph in the preedit, or when it occurs in the -+ * middle of the sequence. Sadly, the official character, -+ * U+2384, COMPOSITION SYMBOL, is bit too distracting, so -+ * we use U+00B7, MIDDLE DOT. -+ */ -+ return 0x00B7; - default:; - } - return 0x0; -diff --git a/src/ibusenginesimple.c b/src/ibusenginesimple.c -index 4644620b..57ca10c4 100644 ---- a/src/ibusenginesimple.c -+++ b/src/ibusenginesimple.c -@@ -289,32 +289,27 @@ ibus_engine_simple_update_preedit_text (IBusEngineSimple *simple) - { - IBusEngineSimplePrivate *priv = simple->priv; - -- gunichar outbuf[COMPOSE_BUFFER_SIZE + 1]; -- int len = 0; -+ GString *s = g_string_new (""); - - if (priv->in_hex_sequence || priv->in_emoji_sequence) { - int hexchars = 0; - - if (priv->in_hex_sequence) -- outbuf[0] = L'u'; -+ g_string_append_c (s, 'u'); - else -- outbuf[0] = L'@'; -- -- len = 1; -+ g_string_append_c (s, '@'); - - while (priv->compose_buffer[hexchars] != 0) { -- outbuf[len] = ibus_keyval_to_unicode ( -- priv->compose_buffer[hexchars]); -- ++len; -- ++hexchars; -+ g_string_append_unichar( -+ s, -+ ibus_keyval_to_unicode (priv->compose_buffer[hexchars++]) -+ ); - } -- -- g_assert (len <= COMPOSE_BUFFER_SIZE); - } else if (priv->tentative_match) { -- outbuf[len++] = priv->tentative_match; -+ g_string_append_unichar(s, priv->tentative_match); - } else if (priv->tentative_emoji && *priv->tentative_emoji) { - IBusText *text = ibus_text_new_from_string (priv->tentative_emoji); -- len = strlen (priv->tentative_emoji); -+ int len = strlen (priv->tentative_emoji); - ibus_text_append_attribute (text, - IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, len); - ibus_engine_update_preedit_text ((IBusEngine *)simple, text, len, TRUE); -@@ -324,31 +319,33 @@ ibus_engine_simple_update_preedit_text (IBusEngineSimple *simple) - while (priv->compose_buffer[hexchars] != 0) { - guint16 keysym = priv->compose_buffer[hexchars]; - gunichar unichar = ibus_keysym_to_unicode (keysym, FALSE); -- if (unichar > 0) -- outbuf[len] = unichar; -- else -- outbuf[len] = ibus_keyval_to_unicode (keysym); -- if (!outbuf[len]) { -+ if (unichar > 0) { -+ g_string_append_unichar(s, unichar); -+ } else { -+ unichar = ibus_keyval_to_unicode (keysym); -+ g_string_append_unichar(s, unichar); -+ } -+ if (!unichar) { - g_warning ( - "Not found alternative character of compose key 0x%X", - priv->compose_buffer[hexchars]); - } -- ++len; - ++hexchars; - } -- g_assert (len <= IBUS_MAX_COMPOSE_LEN); - } - -- outbuf[len] = L'\0'; -- if (len == 0) { -+ if (s->len == 0) { - ibus_engine_hide_preedit_text ((IBusEngine *)simple); -- } -- else { -- IBusText *text = ibus_text_new_from_ucs4 (outbuf); -+ } else if (s->len >= G_MAXINT) { -+ g_warning ("%s is too long compose length: %lu", s->str, s->len); -+ } else { -+ int len = (int)s->len; -+ IBusText *text = ibus_text_new_from_string (s->str); - ibus_text_append_attribute (text, - IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, len); - ibus_engine_update_preedit_text ((IBusEngine *)simple, text, len, TRUE); - } -+ g_string_free (s, TRUE); - } - - --- -2.28.0 - -From 3e2609e68c9107ce7c65e2d5876bfdc9f0f8c854 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Mon, 26 Jul 2021 22:52:21 +0900 -Subject: [PATCH 3/6] src: Update ibuskeysyms.h for latest dead keys - ---- - src/ibuskeysyms.h | 186 +++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 185 insertions(+), 1 deletion(-) - -diff --git a/src/ibuskeysyms.h b/src/ibuskeysyms.h -index d35eb4a7..2fb2ea19 100644 ---- a/src/ibuskeysyms.h -+++ b/src/ibuskeysyms.h -@@ -274,6 +274,10 @@ - #define IBUS_KEY_dead_invertedbreve 0xfe6d - #define IBUS_KEY_dead_belowcomma 0xfe6e - #define IBUS_KEY_dead_currency 0xfe6f -+#define IBUS_KEY_dead_lowline 0xfe90 -+#define IBUS_KEY_dead_aboveverticalline 0xfe91 -+#define IBUS_KEY_dead_belowverticalline 0xfe92 -+#define IBUS_KEY_dead_longsolidusoverlay 0xfe93 - #define IBUS_KEY_dead_a 0xfe80 - #define IBUS_KEY_dead_A 0xfe81 - #define IBUS_KEY_dead_e 0xfe82 -@@ -1201,6 +1205,7 @@ - #define IBUS_KEY_leftdoublequotemark 0xad2 - #define IBUS_KEY_rightdoublequotemark 0xad3 - #define IBUS_KEY_prescription 0xad4 -+#define IBUS_KEY_permille 0xad5 - #define IBUS_KEY_minutes 0xad6 - #define IBUS_KEY_seconds 0xad7 - #define IBUS_KEY_latincross 0xad9 -@@ -1633,8 +1638,8 @@ - #define IBUS_KEY_ocaron 0x10001d2 - #define IBUS_KEY_obarred 0x1000275 - #define IBUS_KEY_SCHWA 0x100018f --#define IBUS_KEY_EZH 0x10001b7 - #define IBUS_KEY_schwa 0x1000259 -+#define IBUS_KEY_EZH 0x10001b7 - #define IBUS_KEY_ezh 0x1000292 - #define IBUS_KEY_Lbelowdot 0x1001e36 - #define IBUS_KEY_lbelowdot 0x1001e37 -@@ -2121,5 +2126,184 @@ - #define IBUS_KEY_Sinh_ruu2 0x1000df2 - #define IBUS_KEY_Sinh_luu2 0x1000df3 - #define IBUS_KEY_Sinh_kunddaliya 0x1000df4 -+#define IBUS_KEY_ModeLock 0x1008ff01 -+#define IBUS_KEY_MonBrightnessUp 0x1008ff02 -+#define IBUS_KEY_MonBrightnessDown 0x1008ff03 -+#define IBUS_KEY_KbdLightOnOff 0x1008ff04 -+#define IBUS_KEY_KbdBrightnessUp 0x1008ff05 -+#define IBUS_KEY_KbdBrightnessDown 0x1008ff06 -+#define IBUS_KEY_Standby 0x1008ff10 -+#define IBUS_KEY_AudioLowerVolume 0x1008ff11 -+#define IBUS_KEY_AudioMute 0x1008ff12 -+#define IBUS_KEY_AudioRaiseVolume 0x1008ff13 -+#define IBUS_KEY_AudioPlay 0x1008ff14 -+#define IBUS_KEY_AudioStop 0x1008ff15 -+#define IBUS_KEY_AudioPrev 0x1008ff16 -+#define IBUS_KEY_AudioNext 0x1008ff17 -+#define IBUS_KEY_HomePage 0x1008ff18 -+#define IBUS_KEY_Mail 0x1008ff19 -+#define IBUS_KEY_Start 0x1008ff1a -+#define IBUS_KEY_Search 0x1008ff1b -+#define IBUS_KEY_AudioRecord 0x1008ff1c -+#define IBUS_KEY_Calculator 0x1008ff1d -+#define IBUS_KEY_Memo 0x1008ff1e -+#define IBUS_KEY_ToDoList 0x1008ff1f -+#define IBUS_KEY_Calendar 0x1008ff20 -+#define IBUS_KEY_PowerDown 0x1008ff21 -+#define IBUS_KEY_ContrastAdjust 0x1008ff22 -+#define IBUS_KEY_RockerUp 0x1008ff23 -+#define IBUS_KEY_RockerDown 0x1008ff24 -+#define IBUS_KEY_RockerEnter 0x1008ff25 -+#define IBUS_KEY_Back 0x1008ff26 -+#define IBUS_KEY_Forward 0x1008ff27 -+#define IBUS_KEY_Stop 0x1008ff28 -+#define IBUS_KEY_Refresh 0x1008ff29 -+#define IBUS_KEY_PowerOff 0x1008ff2a -+#define IBUS_KEY_WakeUp 0x1008ff2b -+#define IBUS_KEY_Eject 0x1008ff2c -+#define IBUS_KEY_ScreenSaver 0x1008ff2d -+#define IBUS_KEY_WWW 0x1008ff2e -+#define IBUS_KEY_Sleep 0x1008ff2f -+#define IBUS_KEY_Favorites 0x1008ff30 -+#define IBUS_KEY_AudioPause 0x1008ff31 -+#define IBUS_KEY_AudioMedia 0x1008ff32 -+#define IBUS_KEY_MyComputer 0x1008ff33 -+#define IBUS_KEY_VendorHome 0x1008ff34 -+#define IBUS_KEY_LightBulb 0x1008ff35 -+#define IBUS_KEY_Shop 0x1008ff36 -+#define IBUS_KEY_History 0x1008ff37 -+#define IBUS_KEY_OpenURL 0x1008ff38 -+#define IBUS_KEY_AddFavorite 0x1008ff39 -+#define IBUS_KEY_HotLinks 0x1008ff3a -+#define IBUS_KEY_BrightnessAdjust 0x1008ff3b -+#define IBUS_KEY_Finance 0x1008ff3c -+#define IBUS_KEY_Community 0x1008ff3d -+#define IBUS_KEY_AudioRewind 0x1008ff3e -+#define IBUS_KEY_BackForward 0x1008ff3f -+#define IBUS_KEY_Launch0 0x1008ff40 -+#define IBUS_KEY_Launch1 0x1008ff41 -+#define IBUS_KEY_Launch2 0x1008ff42 -+#define IBUS_KEY_Launch3 0x1008ff43 -+#define IBUS_KEY_Launch4 0x1008ff44 -+#define IBUS_KEY_Launch5 0x1008ff45 -+#define IBUS_KEY_Launch6 0x1008ff46 -+#define IBUS_KEY_Launch7 0x1008ff47 -+#define IBUS_KEY_Launch8 0x1008ff48 -+#define IBUS_KEY_Launch9 0x1008ff49 -+#define IBUS_KEY_LaunchA 0x1008ff4a -+#define IBUS_KEY_LaunchB 0x1008ff4b -+#define IBUS_KEY_LaunchC 0x1008ff4c -+#define IBUS_KEY_LaunchD 0x1008ff4d -+#define IBUS_KEY_LaunchE 0x1008ff4e -+#define IBUS_KEY_LaunchF 0x1008ff4f -+#define IBUS_KEY_ApplicationLeft 0x1008ff50 -+#define IBUS_KEY_ApplicationRight 0x1008ff51 -+#define IBUS_KEY_Book 0x1008ff52 -+#define IBUS_KEY_CD 0x1008ff53 -+#define IBUS_KEY_WindowClear 0x1008ff55 -+#define IBUS_KEY_Close 0x1008ff56 -+#define IBUS_KEY_Copy 0x1008ff57 -+#define IBUS_KEY_Cut 0x1008ff58 -+#define IBUS_KEY_Display 0x1008ff59 -+#define IBUS_KEY_DOS 0x1008ff5a -+#define IBUS_KEY_Documents 0x1008ff5b -+#define IBUS_KEY_Excel 0x1008ff5c -+#define IBUS_KEY_Explorer 0x1008ff5d -+#define IBUS_KEY_Game 0x1008ff5e -+#define IBUS_KEY_Go 0x1008ff5f -+#define IBUS_KEY_iTouch 0x1008ff60 -+#define IBUS_KEY_LogOff 0x1008ff61 -+#define IBUS_KEY_Market 0x1008ff62 -+#define IBUS_KEY_Meeting 0x1008ff63 -+#define IBUS_KEY_MenuKB 0x1008ff65 -+#define IBUS_KEY_MenuPB 0x1008ff66 -+#define IBUS_KEY_MySites 0x1008ff67 -+#define IBUS_KEY_New 0x1008ff68 -+#define IBUS_KEY_News 0x1008ff69 -+#define IBUS_KEY_OfficeHome 0x1008ff6a -+#define IBUS_KEY_Open 0x1008ff6b -+#define IBUS_KEY_Option 0x1008ff6c -+#define IBUS_KEY_Paste 0x1008ff6d -+#define IBUS_KEY_Phone 0x1008ff6e -+#define IBUS_KEY_Reply 0x1008ff72 -+#define IBUS_KEY_Reload 0x1008ff73 -+#define IBUS_KEY_RotateWindows 0x1008ff74 -+#define IBUS_KEY_RotationPB 0x1008ff75 -+#define IBUS_KEY_RotationKB 0x1008ff76 -+#define IBUS_KEY_Save 0x1008ff77 -+#define IBUS_KEY_ScrollUp 0x1008ff78 -+#define IBUS_KEY_ScrollDown 0x1008ff79 -+#define IBUS_KEY_ScrollClick 0x1008ff7a -+#define IBUS_KEY_Send 0x1008ff7b -+#define IBUS_KEY_Spell 0x1008ff7c -+#define IBUS_KEY_SplitScreen 0x1008ff7d -+#define IBUS_KEY_Support 0x1008ff7e -+#define IBUS_KEY_TaskPane 0x1008ff7f -+#define IBUS_KEY_Terminal 0x1008ff80 -+#define IBUS_KEY_Tools 0x1008ff81 -+#define IBUS_KEY_Travel 0x1008ff82 -+#define IBUS_KEY_UserPB 0x1008ff84 -+#define IBUS_KEY_User1KB 0x1008ff85 -+#define IBUS_KEY_User2KB 0x1008ff86 -+#define IBUS_KEY_Video 0x1008ff87 -+#define IBUS_KEY_WheelButton 0x1008ff88 -+#define IBUS_KEY_Word 0x1008ff89 -+#define IBUS_KEY_Xfer 0x1008ff8a -+#define IBUS_KEY_ZoomIn 0x1008ff8b -+#define IBUS_KEY_ZoomOut 0x1008ff8c -+#define IBUS_KEY_Away 0x1008ff8d -+#define IBUS_KEY_Messenger 0x1008ff8e -+#define IBUS_KEY_WebCam 0x1008ff8f -+#define IBUS_KEY_MailForward 0x1008ff90 -+#define IBUS_KEY_Pictures 0x1008ff91 -+#define IBUS_KEY_Music 0x1008ff92 -+#define IBUS_KEY_Battery 0x1008ff93 -+#define IBUS_KEY_Bluetooth 0x1008ff94 -+#define IBUS_KEY_WLAN 0x1008ff95 -+#define IBUS_KEY_UWB 0x1008ff96 -+#define IBUS_KEY_AudioForward 0x1008ff97 -+#define IBUS_KEY_AudioRepeat 0x1008ff98 -+#define IBUS_KEY_AudioRandomPlay 0x1008ff99 -+#define IBUS_KEY_Subtitle 0x1008ff9a -+#define IBUS_KEY_AudioCycleTrack 0x1008ff9b -+#define IBUS_KEY_CycleAngle 0x1008ff9c -+#define IBUS_KEY_FrameBack 0x1008ff9d -+#define IBUS_KEY_FrameForward 0x1008ff9e -+#define IBUS_KEY_Time 0x1008ff9f -+#define IBUS_KEY_SelectButton 0x1008ffa0 -+#define IBUS_KEY_View 0x1008ffa1 -+#define IBUS_KEY_TopMenu 0x1008ffa2 -+#define IBUS_KEY_Red 0x1008ffa3 -+#define IBUS_KEY_Green 0x1008ffa4 -+#define IBUS_KEY_Yellow 0x1008ffa5 -+#define IBUS_KEY_Blue 0x1008ffa6 -+#define IBUS_KEY_Suspend 0x1008ffa7 -+#define IBUS_KEY_Hibernate 0x1008ffa8 -+#define IBUS_KEY_TouchpadToggle 0x1008ffa9 -+#define IBUS_KEY_TouchpadOn 0x1008ffb0 -+#define IBUS_KEY_TouchpadOff 0x1008ffb1 -+#define IBUS_KEY_AudioMicMute 0x1008ffb2 -+#define IBUS_KEY_Keyboard 0x1008ffb3 -+#define IBUS_KEY_WWAN 0x1008ffb4 -+#define IBUS_KEY_RFKill 0x1008ffb5 -+#define IBUS_KEY_AudioPreset 0x1008ffb6 -+#define IBUS_KEY_Switch_VT_1 0x1008fe01 -+#define IBUS_KEY_Switch_VT_2 0x1008fe02 -+#define IBUS_KEY_Switch_VT_3 0x1008fe03 -+#define IBUS_KEY_Switch_VT_4 0x1008fe04 -+#define IBUS_KEY_Switch_VT_5 0x1008fe05 -+#define IBUS_KEY_Switch_VT_6 0x1008fe06 -+#define IBUS_KEY_Switch_VT_7 0x1008fe07 -+#define IBUS_KEY_Switch_VT_8 0x1008fe08 -+#define IBUS_KEY_Switch_VT_9 0x1008fe09 -+#define IBUS_KEY_Switch_VT_10 0x1008fe0a -+#define IBUS_KEY_Switch_VT_11 0x1008fe0b -+#define IBUS_KEY_Switch_VT_12 0x1008fe0c -+#define IBUS_KEY_Ungrab 0x1008fe20 -+#define IBUS_KEY_ClearGrab 0x1008fe21 -+#define IBUS_KEY_Next_VMode 0x1008fe22 -+#define IBUS_KEY_Prev_VMode 0x1008fe23 -+#define IBUS_KEY_LogWindowTree 0x1008fe24 -+#define IBUS_KEY_LogGrabInfo 0x1008fe25 - - #endif /* __IBUS_KEYSYMS_H__ */ --- -2.28.0 - -From df495660a6da492fe0cac8f7fe748f25a1c3217c Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Mon, 26 Jul 2021 22:52:23 +0900 -Subject: [PATCH 4/6] src/ibusenginesimple: Change gint to int - ---- - src/ibuscomposetable.c | 128 +++++++++++++++++----------------- - src/ibusenginesimple.c | 58 +++++++-------- - src/ibusenginesimpleprivate.h | 6 +- - 3 files changed, 96 insertions(+), 96 deletions(-) - -diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c -index 4ebf119b..aa58f136 100644 ---- a/src/ibuscomposetable.c -+++ b/src/ibuscomposetable.c -@@ -47,7 +47,7 @@ - typedef struct { - gunichar *sequence; - gunichar *values; -- gchar *comment; -+ char *comment; - } IBusComposeData; - - -@@ -85,7 +85,7 @@ unichar_length (gunichar *uni_array) - - - static gboolean --is_codepoint (const gchar *str) -+is_codepoint (const char *str) - { - int i; - -@@ -104,11 +104,11 @@ is_codepoint (const gchar *str) - - static gboolean - parse_compose_value (IBusComposeData *compose_data, -- const gchar *val, -- const gchar *line) -+ const char *val, -+ const char *line) - { -- gchar *head, *end, *p; -- gchar *ustr = NULL; -+ char *head, *end, *p; -+ char *ustr = NULL; - gunichar *uchars = NULL, *up; - GError *error = NULL; - int n_uchars = 0; -@@ -184,10 +184,10 @@ fail: - - static int - parse_compose_sequence (IBusComposeData *compose_data, -- const gchar *seq, -- const gchar *line) -+ const char *seq, -+ const char *line) - { -- gchar **words = g_strsplit (seq, "<", -1); -+ char **words = g_strsplit (seq, "<", -1); - int i; - int n = 0; - -@@ -198,9 +198,9 @@ parse_compose_sequence (IBusComposeData *compose_data, - } - - for (i = 1; words[i] != NULL; i++) { -- gchar *start = words[i]; -- gchar *end = index (words[i], '>'); -- gchar *match; -+ char *start = words[i]; -+ char *end = index (words[i], '>'); -+ char *match; - gunichar codepoint; - - if (words[i][0] == '\0') -@@ -256,18 +256,18 @@ fail: - } - - --static gchar * --expand_include_path (const gchar *include_path) { -- gchar *out = strdup (""); -- const gchar *head, *i; -- gchar *former, *o; -+static char * -+expand_include_path (const char *include_path) { -+ char *out = strdup (""); -+ const char *head, *i; -+ char *former, *o; - - for (head = i = include_path; *i; ++i) { - /* expand sequence */ - if (*i == '%') { - switch (*(i + 1)) { - case 'H': { /* $HOME */ -- const gchar *home = getenv ("HOME"); -+ const char *home = getenv ("HOME"); - if (!home) { - g_warning ("while parsing XCompose include target %s, " - "%%H replacement failed because HOME is not " -@@ -325,11 +325,11 @@ fail: - - static void - parse_compose_line (GList **compose_list, -- const gchar *line, -+ const char *line, - int *compose_len, -- gchar **include) -+ char **include) - { -- gchar **components = NULL; -+ char **components = NULL; - IBusComposeData *compose_data = NULL; - int l; - -@@ -395,13 +395,13 @@ fail: - } - - --static gchar * -+static char * - get_en_compose_file (void) - { -- gchar * const sys_langs[] = { "en_US.UTF-8", "en_US", "en.UTF-8", -- "en", NULL }; -- gchar * const *sys_lang = NULL; -- gchar *path = NULL; -+ char * const sys_langs[] = { "en_US.UTF-8", "en_US", "en.UTF-8", -+ "en", NULL }; -+ char * const *sys_lang = NULL; -+ char *path = NULL; - for (sys_lang = sys_langs; *sys_lang; sys_lang++) { - path = g_build_filename (X11_DATADIR, *sys_lang, "Compose", NULL); - if (g_file_test (path, G_FILE_TEST_EXISTS)) -@@ -413,11 +413,11 @@ get_en_compose_file (void) - - - static GList * --ibus_compose_list_parse_file (const gchar *compose_file, -- int *max_compose_len) -+ibus_compose_list_parse_file (const char *compose_file, -+ int *max_compose_len) - { -- gchar *contents = NULL; -- gchar **lines = NULL; -+ char *contents = NULL; -+ char **lines = NULL; - gsize length = 0; - GError *error = NULL; - GList *compose_list = NULL; -@@ -435,14 +435,14 @@ ibus_compose_list_parse_file (const gchar *compose_file, - g_free (contents); - for (i = 0; lines[i] != NULL; i++) { - int compose_len = 0; -- gchar *include = NULL; -+ char *include = NULL; - parse_compose_line (&compose_list, lines[i], &compose_len, &include); - if (*max_compose_len < compose_len) - *max_compose_len = compose_len; - if (include && *include) { - GStatBuf buf_include = { 0, }; - GStatBuf buf_parent = { 0, }; -- gchar *en_compose; -+ char *en_compose; - errno = 0; - if (g_stat (include, &buf_include)) { - g_warning ("Cannot access %s: %s", -@@ -588,7 +588,7 @@ ibus_compose_list_check_duplicated (GList *compose_list, - } - - --static gint -+static int - ibus_compose_data_compare (gpointer a, - gpointer b, - gpointer data) -@@ -625,7 +625,7 @@ ibus_compose_list_print (GList *compose_list, - int i, j; - IBusComposeData *compose_data; - int total_size = 0; -- const gchar *keyval; -+ const char *keyval; - - for (list = compose_list; list != NULL; list = list->next) { - compose_data = list->data; -@@ -682,13 +682,13 @@ ibus_compose_table_data_hash (gconstpointer v, - } - - --static gchar * -+static char * - ibus_compose_hash_get_cache_path (guint32 hash) - { -- gchar *basename = NULL; -- const gchar *cache_dir; -- gchar *dir = NULL; -- gchar *path = NULL; -+ char *basename = NULL; -+ const char *cache_dir; -+ char *dir = NULL; -+ char *path = NULL; - - basename = g_strdup_printf ("%08x.cache", hash); - -@@ -715,7 +715,7 @@ ibus_compose_hash_get_cache_path (guint32 hash) - static GVariant * - ibus_compose_table_serialize (IBusComposeTableEx *compose_table) - { -- const gchar *header = IBUS_COMPOSE_TABLE_MAGIC; -+ const char *header = IBUS_COMPOSE_TABLE_MAGIC; - const guint16 version = IBUS_COMPOSE_TABLE_VERSION; - guint16 max_seq_len; - guint16 index_stride; -@@ -825,7 +825,7 @@ out_serialize: - } - - --static gint -+static int - ibus_compose_table_find (gconstpointer data1, - gconstpointer data2) - { -@@ -837,8 +837,8 @@ ibus_compose_table_find (gconstpointer data1, - - - static IBusComposeTableEx * --ibus_compose_table_deserialize (const gchar *contents, -- gsize length) -+ibus_compose_table_deserialize (const char *contents, -+ gsize length) - { - IBusComposeTableEx *retval = NULL; - GVariantType *type; -@@ -846,7 +846,7 @@ ibus_compose_table_deserialize (const gchar *contents, - GVariant *variant_data_32bit_first = NULL; - GVariant *variant_data_32bit_second = NULL; - GVariant *variant_table = NULL; -- const gchar *header = NULL; -+ const char *header = NULL; - guint16 version = 0; - guint16 max_seq_len = 0; - guint16 n_seqs = 0; -@@ -1020,8 +1020,8 @@ ibus_compose_table_load_cache (const gchar *compose_file) - { - IBusComposeTableEx *retval = NULL; - guint32 hash; -- gchar *path = NULL; -- gchar *contents = NULL; -+ char *path = NULL; -+ char *contents = NULL; - GStatBuf original_buf; - GStatBuf cache_buf; - gsize length = 0; -@@ -1063,9 +1063,9 @@ ibus_compose_table_load_cache (const gchar *compose_file) - void - ibus_compose_table_save_cache (IBusComposeTableEx *compose_table) - { -- gchar *path = NULL; -+ char *path = NULL; - GVariant *variant_table = NULL; -- const gchar *contents = NULL; -+ const char *contents = NULL; - GError *error = NULL; - gsize length = 0; - -@@ -1392,13 +1392,13 @@ compare_seq (const void *key, const void *value) - gboolean - ibus_compose_table_check (const IBusComposeTableEx *table, - guint16 *compose_buffer, -- gint n_compose, -+ int n_compose, - gboolean *compose_finish, - gboolean *compose_match, - GString *output, - gboolean is_32bit) - { -- gint row_stride = table->max_seq_len + 2; -+ int row_stride = table->max_seq_len + 2; - guint16 *data_first; - int n_seqs; - guint16 *seq; -@@ -1448,7 +1448,7 @@ ibus_compose_table_check (const IBusComposeTableEx *table, - gunichar value = 0; - int num = 0; - int index = 0; -- gchar *output_str = NULL; -+ char *output_str = NULL; - GError *error = NULL; - - if (is_32bit) { -@@ -1526,15 +1526,15 @@ gboolean - ibus_compose_table_compact_check (const IBusComposeTableCompactEx *table, - guint16 - *compose_buffer, -- gint n_compose, -+ int n_compose, - gboolean - *compose_finish, - gunichar **output_chars) - { -- gint row_stride; -+ int row_stride; - guint16 *seq_index; - guint16 *seq; -- gint i; -+ int i; - - if (compose_finish) - *compose_finish = FALSE; -@@ -1654,14 +1654,14 @@ ibus_compose_table_compact_check (const IBusComposeTableCompactEx *table, - * permutations of the diacritic marks, then attempt to normalize. - */ - static gboolean --check_normalize_nfc (gunichar* combination_buffer, gint n_compose) -+check_normalize_nfc (gunichar* combination_buffer, int n_compose) - { - gunichar combination_buffer_temp[IBUS_MAX_COMPOSE_LEN]; -- gchar *combination_utf8_temp = NULL; -- gchar *nfc_temp = NULL; -- gint n_combinations; -+ char *combination_utf8_temp = NULL; -+ char *nfc_temp = NULL; -+ int n_combinations; - gunichar temp_swap; -- gint i; -+ int i; - - n_combinations = 1; - -@@ -1703,8 +1703,8 @@ check_normalize_nfc (gunichar* combination_buffer, gint n_compose) - g_free (nfc_temp); - - if (n_compose > 2) { -- gint j = i % (n_compose - 1) + 1; -- gint k = (i+1) % (n_compose - 1) + 1; -+ int j = i % (n_compose - 1) + 1; -+ int k = (i+1) % (n_compose - 1) + 1; - if (j >= IBUS_MAX_COMPOSE_LEN) { - g_warning ("j >= IBUS_MAX_COMPOSE_LEN for " \ - "combination_buffer_temp"); -@@ -1729,13 +1729,13 @@ check_normalize_nfc (gunichar* combination_buffer, gint n_compose) - - gboolean - ibus_check_algorithmically (const guint16 *compose_buffer, -- gint n_compose, -+ int n_compose, - gunichar *output_char) - - { -- gint i; -+ int i; - gunichar combination_buffer[IBUS_MAX_COMPOSE_LEN]; -- gchar *combination_utf8, *nfc; -+ char *combination_utf8, *nfc; - - if (output_char) - *output_char = 0; -diff --git a/src/ibusenginesimple.c b/src/ibusenginesimple.c -index 57ca10c4..699cf0d4 100644 ---- a/src/ibusenginesimple.c -+++ b/src/ibusenginesimple.c -@@ -79,8 +79,8 @@ typedef struct { - struct _IBusEngineSimplePrivate { - guint16 *compose_buffer; - gunichar tentative_match; -- gchar *tentative_emoji; -- gint tentative_match_len; -+ char *tentative_emoji; -+ int tentative_match_len; - - guint hex_mode_enabled : 1; - guint in_hex_sequence : 1; -@@ -142,7 +142,7 @@ static void ibus_engine_simple_candidate_clicked - static void ibus_engine_simple_commit_char (IBusEngineSimple *simple, - gunichar ch); - static void ibus_engine_simple_commit_str (IBusEngineSimple *simple, -- const gchar *str); -+ const char *str); - static void ibus_engine_simple_update_preedit_text - (IBusEngineSimple *simple); - -@@ -260,10 +260,10 @@ ibus_engine_simple_commit_char (IBusEngineSimple *simple, - - static void - ibus_engine_simple_commit_str (IBusEngineSimple *simple, -- const gchar *str) -+ const char *str) - { - IBusEngineSimplePrivate *priv = simple->priv; -- gchar *backup_str; -+ char *backup_str; - - g_return_if_fail (str && *str); - -@@ -368,15 +368,15 @@ ibus_engine_simple_update_preedit_text (IBusEngineSimple *simple) - - static gboolean - check_hex (IBusEngineSimple *simple, -- gint n_compose) -+ int n_compose) - { - IBusEngineSimplePrivate *priv = simple->priv; - -- gint i; -+ int i; - GString *str; - gulong n; -- gchar *nptr = NULL; -- gchar buf[7]; -+ char *nptr = NULL; -+ char buf[7]; - - CHECK_COMPOSE_BUFFER_LENGTH (n_compose); - -@@ -453,14 +453,14 @@ load_emoji_dict () - - static gboolean - check_emoji_table (IBusEngineSimple *simple, -- gint n_compose, -- gint index) -+ int n_compose, -+ int index) - { - IBusEngineSimplePrivate *priv = simple->priv; - IBusEngineDict *emoji_dict = priv->emoji_dict; - GString *str = NULL; -- gint i; -- gchar buf[7]; -+ int i; -+ char buf[7]; - GSList *words = NULL; - - g_assert (IBUS_IS_ENGINE_SIMPLE (simple)); -@@ -535,7 +535,7 @@ check_emoji_table (IBusEngineSimple *simple, - - static gboolean - no_sequence_matches (IBusEngineSimple *simple, -- gint n_compose, -+ int n_compose, - guint keyval, - guint keycode, - guint modifiers) -@@ -550,7 +550,7 @@ no_sequence_matches (IBusEngineSimple *simple, - * match pending. - */ - if (priv->tentative_match) { -- gint len = priv->tentative_match_len; -+ int len = priv->tentative_match_len; - int i; - - ibus_engine_simple_commit_char (simple, priv->tentative_match); -@@ -615,7 +615,7 @@ ibus_engine_simple_update_lookup_and_aux_table (IBusEngineSimple *simple) - { - IBusEngineSimplePrivate *priv; - guint index, candidates; -- gchar *aux_label = NULL; -+ char *aux_label = NULL; - IBusText *text = NULL; - - g_return_if_fail (IBUS_IS_ENGINE_SIMPLE (simple)); -@@ -697,7 +697,7 @@ ibus_engine_simple_set_number_on_lookup_table (IBusEngineSimple *simple, - - static gboolean - ibus_engine_simple_check_all_compose_table (IBusEngineSimple *simple, -- gint n_compose) -+ int n_compose) - { - IBusEngineSimplePrivate *priv = simple->priv; - gboolean compose_finish = FALSE; -@@ -818,7 +818,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - { - IBusEngineSimple *simple = (IBusEngineSimple *)engine; - IBusEngineSimplePrivate *priv = simple->priv; -- gint n_compose = 0; -+ int n_compose = 0; - gboolean have_hex_mods; - gboolean is_hex_start = FALSE; - gboolean is_emoji_start = FALSE; -@@ -828,7 +828,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - gboolean is_escape; - guint hex_keyval; - guint printable_keyval; -- gint i; -+ int i; - - while (n_compose <= COMPOSE_BUFFER_SIZE && priv->compose_buffer[n_compose] != 0) - n_compose++; -@@ -1274,7 +1274,7 @@ ibus_engine_simple_candidate_clicked (IBusEngine *engine, - IBusEngineSimple *simple = (IBusEngineSimple *)engine; - IBusEngineSimplePrivate *priv = simple->priv; - guint keyval; -- gint n_compose = 0; -+ int n_compose = 0; - - if (priv->lookup_table == NULL || !priv->lookup_table_visible) - return; -@@ -1308,18 +1308,18 @@ ibus_engine_simple_add_table_by_locale (IBusEngineSimple *simple, - { - /* Now ibus_engine_simple_add_compose_file() always returns TRUE. */ - gboolean retval = TRUE; -- gchar *path = NULL; -- const gchar *home; -+ char *path = NULL; -+ const char *home; - #if GLIB_CHECK_VERSION (2, 58, 0) -- const gchar * const *langs; -- const gchar * const *lang = NULL; -+ const char * const *langs; -+ const char * const *lang = NULL; - #else -- const gchar *_locale; -- gchar **langs = NULL; -- gchar **lang = NULL; -+ const char *_locale; -+ char **langs = NULL; -+ char **lang = NULL; - #endif -- gchar * const sys_langs[] = { "el_gr", "fi_fi", "pt_br", NULL }; -- gchar * const *sys_lang = NULL; -+ char * const sys_langs[] = { "el_gr", "fi_fi", "pt_br", NULL }; -+ char * const *sys_lang = NULL; - - if (locale == NULL) { - path = g_build_filename (g_get_user_config_dir (), -diff --git a/src/ibusenginesimpleprivate.h b/src/ibusenginesimpleprivate.h -index 47f2a3d4..5479e553 100644 ---- a/src/ibusenginesimpleprivate.h -+++ b/src/ibusenginesimpleprivate.h -@@ -43,11 +43,11 @@ struct _IBusComposeTableCompactPrivate - }; - - gboolean ibus_check_algorithmically (const guint16 *compose_buffer, -- gint n_compose, -+ int n_compose, - gunichar *output); - gboolean ibus_compose_table_check (const IBusComposeTableEx *table, - guint16 *compose_buffer, -- gint n_compose, -+ int n_compose, - gboolean *compose_finish, - gboolean *compose_match, - GString *output, -@@ -56,7 +56,7 @@ gboolean ibus_compose_table_compact_check - (const IBusComposeTableCompactEx - *table, - guint16 *compose_buffer, -- gint n_compose, -+ int n_compose, - gboolean *compose_finish, - gunichar **output_chars); - gunichar ibus_keysym_to_unicode (guint16 keysym, --- -2.28.0 - -From 4259f16324d578aa2505cf50f2f23923d8d87e76 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Mon, 26 Jul 2021 22:53:19 +0900 -Subject: [PATCH 5/6] src/ibusenginesimple: Make Compose preedit less intrusive - -Tweak the preedit display for Compose sequences to -be not so distracting. We only show the Compose key -when it occurs in the middle of the sequence or is -the only key so far. - -BUG=https://gitlab.gnome.org/GNOME/gtk/-/issues/3669 -BUG=https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/3220 -BUG=https://blog.gtk.org/2021/03/24/input-revisited/ ---- - src/ibuscomposetable.c | 175 +++++++++++--------- - src/ibusenginesimple.c | 301 +++++++++++++++++++++++++--------- - src/ibusenginesimpleprivate.h | 9 +- - 3 files changed, 325 insertions(+), 160 deletions(-) - -diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c -index aa58f136..2ad21551 100644 ---- a/src/ibuscomposetable.c -+++ b/src/ibuscomposetable.c -@@ -1523,23 +1523,22 @@ compare_seq_index (const void *key, const void *value) - * IBusComposeData->values[] is the gunichar array. - */ - gboolean --ibus_compose_table_compact_check (const IBusComposeTableCompactEx *table, -- guint16 -- *compose_buffer, -- int n_compose, -- gboolean -- *compose_finish, -- gunichar **output_chars) -+ibus_compose_table_compact_check (const IBusComposeTableCompactEx -+ *table, -+ guint16 *compose_buffer, -+ int n_compose, -+ gboolean *compose_finish, -+ gunichar **output_chars) - { - int row_stride; - guint16 *seq_index; - guint16 *seq; - int i; - -- if (compose_finish) -- *compose_finish = FALSE; -- if (output_chars) -- *output_chars = NULL; -+ /* compose_finish and output_chars should not be initialized because -+ * ibus_compose_table_check() is called at first and -+ * engine->priv->tentative_match will be preedit after this is called. -+ */ - - /* Will never match, if the sequence in the compose buffer is longer - * than the sequences in the table. Further, compare_seq (key, val) -@@ -1588,7 +1587,8 @@ ibus_compose_table_compact_check (const IBusComposeTableCompactEx *table, - if (compose_finish) - *compose_finish = TRUE; - if (output_chars) { -- *output_chars = g_new (gunichar, length + 1); -+ if (!(*output_chars)) -+ *output_chars = g_new (gunichar, length + 1); - for (j = 0; j < length; j++) { - (*output_chars)[j] = table->priv->data2[index + j]; - } -@@ -1622,7 +1622,8 @@ ibus_compose_table_compact_check (const IBusComposeTableCompactEx *table, - if (compose_finish) - *compose_finish = TRUE; - if (output_chars) { -- *output_chars = g_new (gunichar, 2); -+ if (!(*output_chars)) -+ *output_chars = g_new (gunichar, 2); - (*output_chars)[0] = seq[row_stride - 1]; - (*output_chars)[1] = 0; - } -@@ -1635,16 +1636,6 @@ ibus_compose_table_compact_check (const IBusComposeTableCompactEx *table, - } - - --/* Checks if a keysym is a dead key. Dead key keysym values are defined in -- * ../gdk/gdkkeysyms.h and the first is GDK_KEY_dead_grave. As X.Org is updated, -- * more dead keys are added and we need to update the upper limit. -- * Currently, the upper limit is GDK_KEY_dead_dasia+1. The +1 has to do with -- * a temporary issue in the X.Org header files. -- * In future versions it will be just the keysym (no +1). -- */ --#define IS_DEAD_KEY(k) \ -- ((k) >= IBUS_KEY_dead_grave && (k) <= IBUS_KEY_dead_greek) -- - /* This function receives a sequence of Unicode characters and tries to - * normalize it (NFC). We check for the case the the resulting string - * has length 1 (single character). -@@ -1754,7 +1745,8 @@ ibus_check_algorithmically (const guint16 *compose_buffer, - i--; - while (i >= 0) { - combination_buffer[i+1] = ibus_keysym_to_unicode (compose_buffer[i], -- TRUE); -+ TRUE, -+ NULL); - if (!combination_buffer[i+1]) { - combination_buffer[i+1] = - ibus_keyval_to_unicode (compose_buffer[i]); -@@ -1786,66 +1778,91 @@ ibus_check_algorithmically (const guint16 *compose_buffer, - - - gunichar --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 \ -+ibus_keysym_to_unicode (guint16 keysym, -+ gboolean combining, -+ gboolean *need_space) { -+#define CASE(keysym_suffix, unicode, sp) \ -+ case IBUS_KEY_dead_##keysym_suffix: \ -+ if (need_space) \ -+ *need_space = sp; \ -+ return unicode -+#define CASE_COMBINE(keysym_suffix, combined_unicode, isolated_unicode, sp) \ -+ case IBUS_KEY_dead_##keysym_suffix: \ -+ if (need_space) \ -+ *need_space = sp; \ -+ 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_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); -+#ifdef IBUS_ENGLISH_DEAD_KEY -+ CASE (a, 0x0363, 1); -+ CASE (A, 0x0363, 1); -+ CASE (i, 0x0365, 1); -+ CASE (I, 0x0365, 1); -+ CASE (u, 0x0367, 1); -+ CASE (U, 0x0367, 1); -+ CASE (e, 0x0364, 1); -+ CASE (E, 0x0364, 1); -+ CASE (o, 0x0366, 1); -+ CASE (O, 0x0366, 1); -+#else -+ CASE (a, 0x3041, 0); -+ CASE (A, 0x3042, 0); -+ CASE (i, 0x3043, 0); -+ CASE (I, 0x3044, 0); -+ CASE (u, 0x3045, 0); -+ CASE (U, 0x3046, 0); -+ CASE (e, 0x3047, 0); -+ CASE (E, 0x3048, 0); -+ CASE (o, 0x3049, 0); -+ CASE (O, 0x304A, 0); -+#endif -+ CASE_COMBINE (abovecomma, 0x0313, 0x02BC, 0); -+ CASE_COMBINE (abovedot, 0x0307, 0x02D9, 0); -+ CASE_COMBINE (abovereversedcomma, 0x0314, 0x02BD, 0); -+ CASE_COMBINE (abovering, 0x030A, 0x02DA, 0); -+ CASE_COMBINE (aboveverticalline, 0x030D, 0x02C8, 0); -+ CASE_COMBINE (acute, 0x0301, 0x00B4, 0); -+ CASE (belowbreve, 0x032E, 1); -+ CASE_COMBINE (belowcircumflex, 0x032D, 0xA788, 0); -+ CASE_COMBINE (belowcomma, 0x0326, 0x002C, 0); -+ CASE (belowdiaeresis, 0x0324, 1); -+ CASE_COMBINE (belowdot, 0x0323, 0x002E, 0); -+ CASE_COMBINE (belowmacron, 0x0331, 0x02CD, 0); -+ CASE_COMBINE (belowring, 0x030A, 0x02F3, 0); -+ CASE_COMBINE (belowtilde, 0x0330, 0x02F7, 0); -+ CASE_COMBINE (belowverticalline, 0x0329, 0x02CC, 0); -+ CASE_COMBINE (breve, 0x0306, 0x02D8, 0); -+ CASE_COMBINE (capital_schwa, 0x1DEA, 0x1D4A, 0); -+ CASE_COMBINE (caron, 0x030C, 0x02C7, 0); -+ CASE_COMBINE (cedilla, 0x0327, 0x00B8, 0); -+ CASE_COMBINE (circumflex, 0x0302, 0x005E, 0); -+ CASE (currency, 0x00A4, 0); - // IBUS_KEY_dead_dasia == IBUS_KEY_dead_abovereversedcomma -- 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); -+ CASE_COMBINE (diaeresis, 0x0308, 0x00A8, 0); -+ CASE_COMBINE (doubleacute, 0x030B, 0x02DD, 0); -+ CASE_COMBINE (doublegrave, 0x030F, 0x02F5, 0); -+ CASE_COMBINE (grave, 0x0300, 0x0060, 0); -+ CASE (greek, 0x03BC, 0); -+ CASE_COMBINE (hook, 0x0309, 0x02C0, 0); -+ CASE (horn, 0x031B, 1); -+ CASE (invertedbreve, 0x032F, 1); -+ CASE_COMBINE (iota, 0x0345, 0x037A, 0); -+ CASE (longsolidusoverlay, 0x0338, 1); -+ CASE_COMBINE (lowline, 0x0332, 0x005F, 0); -+ CASE_COMBINE (macron, 0x0304, 0x00AF, 0); -+ CASE_COMBINE (ogonek, 0x0328, 0x02DB, 0); - // IBUS_KEY_dead_perispomeni == IBUS_KEY_dead_tilde - // IBUS_KEY_dead_psili == IBUS_KEY_dead_abovecomma -- 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_COMBINE (semivoiced_sound, 0x309A, 0x309C, 0); -+ CASE_COMBINE (small_schwa, 0x1DEA, 0x1D4A, 0); -+ CASE (stroke, 0x0335, 1); -+ CASE_COMBINE (tilde, 0x0303, 0x007E, 0); -+ CASE_COMBINE (voiced_sound, 0x3099, 0x309B, 0); - case IBUS_KEY_Multi_key: -+ if (need_space) -+ *need_space = FALSE; - /* We only show the Compose key visibly when it is the - * only glyph in the preedit, or when it occurs in the - * middle of the sequence. Sadly, the official character, -@@ -1854,6 +1871,8 @@ ibus_keysym_to_unicode (guint16 keysym, - */ - return 0x00B7; - default:; -+ if (need_space) -+ *need_space = FALSE; - } - return 0x0; - #undef CASE -diff --git a/src/ibusenginesimple.c b/src/ibusenginesimple.c -index 699cf0d4..acfc0264 100644 ---- a/src/ibusenginesimple.c -+++ b/src/ibusenginesimple.c -@@ -78,13 +78,14 @@ typedef struct { - - struct _IBusEngineSimplePrivate { - guint16 *compose_buffer; -- gunichar tentative_match; -- char *tentative_emoji; -+ GString *tentative_match; - int tentative_match_len; -+ char *tentative_emoji; - - guint hex_mode_enabled : 1; - guint in_hex_sequence : 1; - guint in_emoji_sequence : 1; -+ guint in_compose_sequence : 1; - guint modifiers_dropped : 1; - IBusEngineDict *emoji_dict; - IBusLookupTable *lookup_table; -@@ -178,6 +179,8 @@ ibus_engine_simple_init (IBusEngineSimple *simple) - simple->priv->hex_mode_enabled = - g_getenv("IBUS_ENABLE_CTRL_SHIFT_U") != NULL || - g_getenv("IBUS_ENABLE_CONTROL_SHIFT_U") != NULL; -+ simple->priv->tentative_match = g_string_new (""); -+ simple->priv->tentative_match_len = 0; - } - - -@@ -196,6 +199,9 @@ ibus_engine_simple_destroy (IBusEngineSimple *simple) - g_clear_object (&priv->lookup_table); - g_clear_pointer (&priv->compose_buffer, g_free); - g_clear_pointer (&priv->tentative_emoji, g_free); -+ g_string_free (priv->tentative_match, TRUE); -+ priv->tentative_match = NULL; -+ priv->tentative_match_len = 0; - - IBUS_OBJECT_CLASS(ibus_engine_simple_parent_class)->destroy ( - IBUS_OBJECT (simple)); -@@ -222,15 +228,15 @@ ibus_engine_simple_reset (IBusEngine *engine) - - priv->compose_buffer[0] = 0; - -- if (priv->tentative_match || priv->in_hex_sequence) { -+ if (priv->tentative_match->len > 0 || priv->in_hex_sequence) { - priv->in_hex_sequence = FALSE; -- priv->tentative_match = 0; -+ g_string_set_size (priv->tentative_match, 0); - priv->tentative_match_len = 0; - } else if (priv->tentative_emoji || priv->in_emoji_sequence) { - priv->in_emoji_sequence = FALSE; - g_clear_pointer (&priv->tentative_emoji, g_free); - } else if (!priv->in_hex_sequence && !priv->in_emoji_sequence) { -- priv->tentative_match = 0; -+ g_string_set_size (priv->tentative_match, 0); - priv->tentative_match_len = 0; - } - ibus_engine_hide_preedit_text ((IBusEngine *)simple); -@@ -244,10 +250,17 @@ ibus_engine_simple_commit_char (IBusEngineSimple *simple, - - IBusEngineSimplePrivate *priv = simple->priv; - -- if (priv->tentative_match || priv->in_hex_sequence) { -- priv->in_hex_sequence = FALSE; -- priv->tentative_match = 0; -+ if (priv->in_hex_sequence || -+ priv->tentative_match_len > 0 || -+ priv->compose_buffer[0] != 0) { -+ g_string_set_size (priv->tentative_match, 0); - priv->tentative_match_len = 0; -+ priv->in_hex_sequence = FALSE; -+ priv->in_compose_sequence = FALSE; -+ priv->compose_buffer[0] = 0; -+ /* Don't call ibus_engine_simple_update_preedit_text() inside -+ * not to call it as duplilcated. -+ */ - } - if (priv->tentative_emoji || priv->in_emoji_sequence) { - priv->in_emoji_sequence = FALSE; -@@ -269,10 +282,17 @@ ibus_engine_simple_commit_str (IBusEngineSimple *simple, - - backup_str = g_strdup (str); - -- if (priv->tentative_match || priv->in_hex_sequence) { -- priv->in_hex_sequence = FALSE; -- priv->tentative_match = 0; -+ if (priv->in_hex_sequence || -+ priv->tentative_match_len > 0 || -+ priv->compose_buffer[0] != 0) { -+ g_string_set_size (priv->tentative_match, 0); - priv->tentative_match_len = 0; -+ priv->in_hex_sequence = FALSE; -+ priv->in_compose_sequence = FALSE; -+ priv->compose_buffer[0] = 0; -+ /* Don't call ibus_engine_simple_update_preedit_text() inside -+ * not to call it as duplilcated. -+ */ - } - if (priv->tentative_emoji || priv->in_emoji_sequence) { - priv->in_emoji_sequence = FALSE; -@@ -288,8 +308,8 @@ static void - ibus_engine_simple_update_preedit_text (IBusEngineSimple *simple) - { - IBusEngineSimplePrivate *priv = simple->priv; -- - GString *s = g_string_new (""); -+ int i, j; - - if (priv->in_hex_sequence || priv->in_emoji_sequence) { - int hexchars = 0; -@@ -305,32 +325,59 @@ ibus_engine_simple_update_preedit_text (IBusEngineSimple *simple) - ibus_keyval_to_unicode (priv->compose_buffer[hexchars++]) - ); - } -- } else if (priv->tentative_match) { -- g_string_append_unichar(s, priv->tentative_match); - } else if (priv->tentative_emoji && *priv->tentative_emoji) { - IBusText *text = ibus_text_new_from_string (priv->tentative_emoji); - int len = strlen (priv->tentative_emoji); - ibus_text_append_attribute (text, - IBUS_ATTR_TYPE_UNDERLINE, IBUS_ATTR_UNDERLINE_SINGLE, 0, len); - ibus_engine_update_preedit_text ((IBusEngine *)simple, text, len, TRUE); -+ g_string_free (s, 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, FALSE); -- if (unichar > 0) { -- g_string_append_unichar(s, unichar); -- } else { -- unichar = ibus_keyval_to_unicode (keysym); -- g_string_append_unichar(s, unichar); -- } -- if (!unichar) { -- g_warning ( -+ } else if (priv->in_compose_sequence) { -+ if (priv->tentative_match->len > 0 && priv->compose_buffer[0] != 0) { -+ g_string_append (s, priv->tentative_match->str); -+ } else { -+ for (i = 0; priv->compose_buffer[i]; ++i) { -+ guint16 keysym = priv->compose_buffer[i]; -+ gboolean show_keysym = TRUE; -+ gboolean need_space = FALSE; -+ gunichar ch; -+ -+ if (keysym == IBUS_KEY_Multi_key) { -+ /* We only show the Compose key visibly when it is the -+ * only glyph in the preedit, or when it occurs in the -+ * middle of the sequence. Sadly, the official character, -+ * U+2384, COMPOSITION SYMBOL, is bit too distracting, so -+ * we use U+00B7, MIDDLE DOT. -+ */ -+ for (j = i + 1; priv->compose_buffer[j]; j++) { -+ if (priv->compose_buffer[j] != IBUS_KEY_Multi_key) { -+ show_keysym = FALSE; -+ break; -+ } -+ } -+ if (!show_keysym) -+ continue; -+ ch = ibus_keysym_to_unicode (keysym, FALSE, NULL); -+ g_string_append_unichar (s, ch); -+ } else if (IS_DEAD_KEY (keysym)) { -+ ch = ibus_keysym_to_unicode (keysym, FALSE, &need_space); -+ if (ch) { -+ if (need_space) -+ g_string_append_c (s, ' '); -+ g_string_append_unichar (s, ch); -+ } -+ } else { -+ ch = ibus_keyval_to_unicode (keysym); -+ if (ch) -+ g_string_append_unichar(s, ch); -+ } -+ if (!ch) { -+ g_warning ( - "Not found alternative character of compose key 0x%X", -- priv->compose_buffer[hexchars]); -+ priv->compose_buffer[i]); -+ } - } -- ++hexchars; - } - } - -@@ -380,7 +427,7 @@ check_hex (IBusEngineSimple *simple, - - CHECK_COMPOSE_BUFFER_LENGTH (n_compose); - -- priv->tentative_match = 0; -+ g_string_set_size (priv->tentative_match, 0); - priv->tentative_match_len = 0; - - str = g_string_new (NULL); -@@ -421,7 +468,8 @@ check_hex (IBusEngineSimple *simple, - } - - if (g_unichar_validate (n)) { -- priv->tentative_match = n; -+ g_string_set_size (priv->tentative_match, 0); -+ g_string_append_unichar (priv->tentative_match, n); - priv->tentative_match_len = n_compose; - } - -@@ -546,21 +594,31 @@ no_sequence_matches (IBusEngineSimple *simple, - - CHECK_COMPOSE_BUFFER_LENGTH (n_compose); - -+ priv->in_compose_sequence = FALSE; -+ - /* No compose sequences found, check first if we have a partial - * match pending. - */ -- if (priv->tentative_match) { -+ if (priv->tentative_match_len > 0) { -+ guint16 *compose_buffer; - int len = priv->tentative_match_len; - int i; -+ char *str; - -- ibus_engine_simple_commit_char (simple, priv->tentative_match); -- priv->compose_buffer[0] = 0; -+ compose_buffer = alloca (sizeof (guint16) * COMPOSE_BUFFER_SIZE); -+ memcpy (compose_buffer, -+ priv->compose_buffer, -+ sizeof (guint16) * COMPOSE_BUFFER_SIZE); -+ -+ str = g_strdup (priv->tentative_match->str); -+ ibus_engine_simple_commit_str (simple, str); -+ g_free (str); - ibus_engine_simple_update_preedit_text (simple); - - for (i=0; i < n_compose - len - 1; i++) { - ibus_engine_simple_process_key_event ( - (IBusEngine *)simple, -- priv->compose_buffer[len + i], -+ compose_buffer[len + i], - 0, 0); - } - -@@ -571,6 +629,26 @@ no_sequence_matches (IBusEngineSimple *simple, - priv->compose_buffer[0] = 0; - ibus_engine_simple_update_preedit_text (simple); - } else { -+ if (n_compose == 2 && IS_DEAD_KEY (priv->compose_buffer[0])) { -+ gboolean need_space = FALSE; -+ GString *s = g_string_new (""); -+ /* dead keys are never *really* dead */ -+ ch = ibus_keysym_to_unicode (priv->compose_buffer[0], -+ FALSE, &need_space); -+ if (ch) { -+ if (need_space) -+ g_string_append_c (s, ' '); -+ g_string_append_unichar (s, ch); -+ } -+ ch = ibus_keyval_to_unicode (priv->compose_buffer[1]); -+ if (ch != 0 && !g_unichar_iscntrl (ch)) -+ g_string_append_unichar (s, ch); -+ ibus_engine_simple_commit_str (simple, s->str); -+ g_string_free (s, TRUE); -+ ibus_engine_simple_update_preedit_text (simple); -+ return TRUE; -+ } -+ - priv->compose_buffer[0] = 0; - if (n_compose > 1) { - /* Invalid sequence */ -@@ -695,19 +773,46 @@ ibus_engine_simple_set_number_on_lookup_table (IBusEngineSimple *simple, - ibus_engine_simple_update_preedit_text (simple); - } - -+ - static gboolean - ibus_engine_simple_check_all_compose_table (IBusEngineSimple *simple, - int n_compose) - { - IBusEngineSimplePrivate *priv = simple->priv; -+ GSList *tmp_list; - gboolean compose_finish = FALSE; - gboolean compose_match = FALSE; - GString *output = g_string_new (""); -- gboolean does_hit = FALSE; -+ gboolean success = FALSE; - gboolean is_32bit = FALSE; -- GSList *tmp_list; - gunichar *output_chars = NULL; -- gunichar output_char; -+ gunichar output_char = '\0'; -+ -+ if (n_compose == 2) { -+ /* Special-case deadkey-deadkey sequences. -+ * We are not doing chained deadkeys, so we -+ * want to commit the first key, and contine -+ * preediting with second. -+ */ -+ if (IS_DEAD_KEY (priv->compose_buffer[0]) && -+ IS_DEAD_KEY (priv->compose_buffer[1])) { -+ gboolean need_space = FALSE; -+ gunichar ch = ibus_keysym_to_unicode (priv->compose_buffer[0], -+ FALSE, &need_space); -+ guint16 next = priv->compose_buffer[1]; -+ if (ch) { -+ if (need_space) -+ g_string_append_c (output, ' '); -+ g_string_append_unichar (output, ch); -+ ibus_engine_simple_commit_str (simple, output->str); -+ g_string_set_size (output, 0); -+ -+ priv->compose_buffer[0] = next; -+ priv->compose_buffer[1] = 0; -+ n_compose = 1; -+ } -+ } -+ } - - G_LOCK (global_tables); - tmp_list = global_tables; -@@ -721,7 +826,7 @@ ibus_engine_simple_check_all_compose_table (IBusEngineSimple *simple, - &compose_match, - output, - is_32bit)) { -- does_hit = TRUE; -+ success = TRUE; - break; - } - is_32bit = TRUE; -@@ -733,14 +838,15 @@ ibus_engine_simple_check_all_compose_table (IBusEngineSimple *simple, - &compose_match, - output, - is_32bit)) { -- does_hit = TRUE; -+ success = TRUE; - break; - } - tmp_list = tmp_list->next; - } - G_UNLOCK (global_tables); - -- if (does_hit) { -+ if (success) { -+ priv->in_compose_sequence = TRUE; - if (compose_finish) { - if (compose_match) { - if (is_32bit) { -@@ -750,59 +856,89 @@ ibus_engine_simple_check_all_compose_table (IBusEngineSimple *simple, - g_utf8_get_char (output->str)); - } - } -+ ibus_engine_simple_update_preedit_text (simple); -+ g_string_free (output, TRUE); -+ return TRUE; - } else if (compose_match) { -- priv->tentative_match = g_utf8_get_char (output->str); -+ g_string_assign (priv->tentative_match, output->str); - priv->tentative_match_len = n_compose; -+ ibus_engine_simple_update_preedit_text (simple); -+ g_string_free (output, TRUE); -+ return TRUE; - } -- ibus_engine_simple_update_preedit_text (simple); -- g_string_free (output, TRUE); -- return TRUE; - } - g_string_free (output, TRUE); -+ output = NULL; - - if (ibus_compose_table_compact_check (&ibus_compose_table_compact, - priv->compose_buffer, - n_compose, - &compose_finish, - &output_chars)) { -+ priv->in_compose_sequence = TRUE; - if (compose_finish) { -- ibus_engine_simple_commit_char (simple, *output_chars); -+ if (success) { -+ g_string_append_unichar (priv->tentative_match, *output_chars); -+ priv->tentative_match_len = n_compose; -+ } else { -+ ibus_engine_simple_commit_char (simple, *output_chars); -+ priv->compose_buffer[0] = 0; -+ } - g_free (output_chars); -- priv->compose_buffer[0] = 0; -+ ibus_engine_simple_update_preedit_text (simple); -+ return TRUE; - } -- ibus_engine_simple_update_preedit_text (simple); -- return TRUE; -+ success = TRUE; - } -+ g_free (output_chars); -+ output_chars = NULL; - if (ibus_compose_table_compact_check (&ibus_compose_table_compact_32bit, - priv->compose_buffer, - n_compose, - &compose_finish, - &output_chars)) { -+ priv->in_compose_sequence = TRUE; - if (compose_finish) { - GError *error = NULL; - char *str = g_ucs4_to_utf8 (output_chars, -1, NULL, NULL, &error); -- if (str) { -- ibus_engine_simple_commit_str (simple, str); -- g_free (str); -- } else { -+ if (!str) { - g_warning ("Failed to output multiple characters: %s", - error->message); - g_error_free (error); -+ } else if (success) { -+ g_string_append (priv->tentative_match, str); -+ priv->tentative_match_len = n_compose; -+ } else { -+ ibus_engine_simple_commit_str (simple, str); -+ priv->compose_buffer[0] = 0; - } -- priv->compose_buffer[0] = 0; -+ g_free (str); -+ g_free (output_chars); -+ ibus_engine_simple_update_preedit_text (simple); -+ return TRUE; - } -- g_free (output_chars); -- ibus_engine_simple_update_preedit_text (simple); -- return TRUE; -+ success = TRUE; - } -- g_assert (!output_chars); -+ g_free (output_chars); -+ output_chars = NULL; - if (ibus_check_algorithmically (priv->compose_buffer, - n_compose, - &output_char)) { -+ priv->in_compose_sequence = TRUE; - if (output_char) { -- ibus_engine_simple_commit_char (simple, output_char); -- priv->compose_buffer[0] = 0; -+ if (success) { -+ g_string_append_unichar (priv->tentative_match, output_char); -+ priv->tentative_match_len = n_compose; -+ } else { -+ ibus_engine_simple_commit_char (simple, output_char); -+ priv->compose_buffer[0] = 0; -+ } -+ ibus_engine_simple_update_preedit_text (simple); -+ return TRUE; - } -+ success = TRUE; -+ } -+ if (success) { - ibus_engine_simple_update_preedit_text (simple); - return TRUE; - } -@@ -810,6 +946,7 @@ ibus_engine_simple_check_all_compose_table (IBusEngineSimple *simple, - return FALSE; - } - -+ - static gboolean - ibus_engine_simple_process_key_event (IBusEngine *engine, - guint keyval, -@@ -841,16 +978,17 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - if (priv->in_hex_sequence && - (keyval == IBUS_KEY_Control_L || keyval == IBUS_KEY_Control_R || - keyval == IBUS_KEY_Shift_L || keyval == IBUS_KEY_Shift_R)) { -- if (priv->tentative_match && -- g_unichar_validate (priv->tentative_match)) { -- ibus_engine_simple_commit_char (simple, priv->tentative_match); -+ if (priv->tentative_match->len > 0) { -+ char *str = g_strdup (priv->tentative_match->str); -+ ibus_engine_simple_commit_str (simple, str); -+ g_free (str); - ibus_engine_simple_update_preedit_text (simple); - } else if (n_compose == 0) { - priv->modifiers_dropped = TRUE; - } else { - /* invalid hex sequence */ - /* FIXME beep_window (event->window); */ -- priv->tentative_match = 0; -+ g_string_set_size (priv->tentative_match, 0); - g_clear_pointer (&priv->tentative_emoji, g_free); - priv->in_hex_sequence = FALSE; - priv->in_emoji_sequence = FALSE; -@@ -873,7 +1011,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - } else { - /* invalid hex sequence */ - /* FIXME beep_window (event->window); */ -- priv->tentative_match = 0; -+ g_string_set_size (priv->tentative_match, 0); - g_clear_pointer (&priv->tentative_emoji, g_free); - priv->in_hex_sequence = FALSE; - priv->in_emoji_sequence = FALSE; -@@ -921,7 +1059,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - else if (is_hex_end) { - /* invalid hex sequence */ - // beep_window (event->window); -- priv->tentative_match = 0; -+ g_string_set_size (priv->tentative_match, 0); - g_clear_pointer (&priv->tentative_emoji, g_free); - priv->in_hex_sequence = FALSE; - priv->in_emoji_sequence = FALSE; -@@ -999,7 +1137,8 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - if (n_compose > 0) { - n_compose--; - priv->compose_buffer[n_compose] = 0; -- priv->tentative_match = 0; -+ g_string_set_size (priv->tentative_match, 0); -+ priv->tentative_match_len = 0; - ibus_engine_simple_check_all_compose_table (simple, n_compose); - return TRUE; - } -@@ -1007,16 +1146,17 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - - /* 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); -+ if (priv->tentative_match->len > 0 ) { -+ char *str = g_strdup (priv->tentative_match->str); -+ ibus_engine_simple_commit_str (simple, str); -+ g_free (str); - ibus_engine_simple_update_preedit_text (simple); - } - else { - /* invalid hex sequence */ - if (n_compose > 0) { - // FIXME beep_window (event->window); -- priv->tentative_match = 0; -+ g_string_set_size (priv->tentative_match, 0); - priv->in_hex_sequence = FALSE; - priv->compose_buffer[0] = 0; - } -@@ -1044,7 +1184,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - priv->in_hex_sequence = TRUE; - priv->in_emoji_sequence = FALSE; - priv->modifiers_dropped = FALSE; -- priv->tentative_match = 0; -+ g_string_set_size (priv->tentative_match, 0); - g_clear_pointer (&priv->tentative_emoji, g_free); - - // g_debug ("Start HEX MODE"); -@@ -1058,7 +1198,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - priv->in_hex_sequence = FALSE; - priv->in_emoji_sequence = TRUE; - priv->modifiers_dropped = FALSE; -- priv->tentative_match = 0; -+ g_string_set_size (priv->tentative_match, 0); - g_clear_pointer (&priv->tentative_emoji, g_free); - - // g_debug ("Start HEX MODE"); -@@ -1068,7 +1208,6 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - return TRUE; - } - -- /* Then, check for compose sequences */ - if (priv->in_hex_sequence) { - if (hex_keyval) { - SET_COMPOSE_BUFFER_ELEMENT_NEXT (priv->compose_buffer, -@@ -1133,17 +1272,17 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - if (have_hex_mods) { - /* space or return ends the sequence, and we eat the key */ - if (n_compose > 0 && is_hex_end) { -- if (priv->tentative_match && -- g_unichar_validate (priv->tentative_match)) { -- ibus_engine_simple_commit_char (simple, -- priv->tentative_match); -- priv->compose_buffer[0] = 0; -+ if (priv->tentative_match->len > 0) { -+ char *str = g_strdup (priv->tentative_match->str); -+ ibus_engine_simple_commit_str (simple, str); -+ g_free (str); - ibus_engine_simple_update_preedit_text (simple); -+ return TRUE; - } else { - // FIXME - /* invalid hex sequence */ - // beep_window (event->window); -- priv->tentative_match = 0; -+ g_string_set_size (priv->tentative_match, 0); - priv->in_hex_sequence = FALSE; - priv->compose_buffer[0] = 0; - } -@@ -1234,7 +1373,7 @@ ibus_engine_simple_process_key_event (IBusEngine *engine, - - return TRUE; - } -- } else { -+ } else { /* Then, check for compose sequences */ - if (ibus_engine_simple_check_all_compose_table (simple, n_compose)) - return TRUE; - } -diff --git a/src/ibusenginesimpleprivate.h b/src/ibusenginesimpleprivate.h -index 5479e553..ad93d2d2 100644 ---- a/src/ibusenginesimpleprivate.h -+++ b/src/ibusenginesimpleprivate.h -@@ -26,6 +26,12 @@ - - G_BEGIN_DECLS - -+/* Checks if a keysym is a dead key. Dead key keysym values are defined in -+ * ibuskeysyms.h and the first is GDK_KEY_dead_grave. -+ */ -+#define IS_DEAD_KEY(k) \ -+ ((k) >= IBUS_KEY_dead_grave && (k) <= IBUS_KEY_dead_greek) -+ - extern const IBusComposeTableCompactEx ibus_compose_table_compact; - extern const IBusComposeTableCompactEx ibus_compose_table_compact_32bit; - -@@ -60,7 +66,8 @@ gboolean ibus_compose_table_compact_check - gboolean *compose_finish, - gunichar **output_chars); - gunichar ibus_keysym_to_unicode (guint16 keysym, -- gboolean combining); -+ gboolean combining, -+ gboolean *need_space); - - G_END_DECLS - --- -2.28.0 - -From 17ae266cade41e795534532acefc85716bb309ef Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Mon, 26 Jul 2021 22:53:34 +0900 -Subject: [PATCH 6/6] Code reviews - -- Use fstat() and fchmod() but not stat() and chmod() to - fix race conditions -- Avoid to use after free -- Fix dereference of IBusComposeTable->priv -- Fix to divide by zero ---- - src/ibusbus.c | 23 ++++++++++++++++++----- - src/ibuscomposetable.c | 8 ++++++-- - src/tests/ibus-desktop-testing-runner.in | 6 +++--- - 3 files changed, 27 insertions(+), 10 deletions(-) - -diff --git a/src/ibusbus.c b/src/ibusbus.c -index e9b0bcbb..47400cb8 100644 ---- a/src/ibusbus.c -+++ b/src/ibusbus.c -@@ -21,13 +21,14 @@ - * USA - */ - --#include "ibusbus.h" - #include -+#include - #include - #include - #include - #include - #include -+#include "ibusbus.h" - #include "ibusmarshalers.h" - #include "ibusinternal.h" - #include "ibusshare.h" -@@ -537,7 +538,8 @@ static void - ibus_bus_init (IBusBus *bus) - { - struct stat buf; -- gchar *path; -+ char *path; -+ int fd; - - bus->priv = IBUS_BUS_GET_PRIVATE (bus); - -@@ -562,20 +564,31 @@ ibus_bus_init (IBusBus *bus) - return; - } - -- if (stat (path, &buf) == 0) { -+ errno = 0; -+ if ((fd = open (path, O_RDONLY | O_DIRECTORY, S_IRWXU)) == -1) { -+ g_warning ("open %s failed: %s", path, g_strerror (errno)); -+ g_free (path); -+ return; -+ } -+ /* TOCTOU: Use fstat() and fchmod() but not stat() and chmod(). -+ * because it can cause a time-of-check, time-of-use race condition. -+ */ -+ if (fstat (fd, &buf) == 0) { - if (buf.st_uid != getuid ()) { - g_warning ("The owner of %s is not %s!", - path, ibus_get_user_name ()); -+ close (fd); - g_free (path); - return; - } - if (buf.st_mode != (S_IFDIR | S_IRWXU)) { - errno = 0; -- if (g_chmod (path, 0700)) -- g_warning ("chmod failed: %s", errno ? g_strerror (errno) : ""); -+ if (fchmod (fd, S_IRWXU)) -+ g_warning ("chmod failed: %s", g_strerror (errno)); - } - } - -+ close (fd); - g_free (path); - } - -diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c -index 2ad21551..a0b0befc 100644 ---- a/src/ibuscomposetable.c -+++ b/src/ibuscomposetable.c -@@ -406,7 +406,7 @@ get_en_compose_file (void) - path = g_build_filename (X11_DATADIR, *sys_lang, "Compose", NULL); - if (g_file_test (path, G_FILE_TEST_EXISTS)) - break; -- g_free (path); -+ g_clear_pointer (&path, g_free); - } - return path; - } -@@ -975,7 +975,10 @@ ibus_compose_table_deserialize (const char *contents, - goto out_load_cache; - } - if (data_length) { -- retval->priv = g_new0 (IBusComposeTablePrivate, 1); -+ if (!(retval->priv = g_new0 (IBusComposeTablePrivate, 1))) { -+ g_warning ("Failed g_new"); -+ goto out_load_cache; -+ } - retval->priv->data_first = g_new (guint16, data_length); - memcpy (retval->priv->data_first, - data_32bit_first, data_length * sizeof (guint16)); -@@ -1565,6 +1568,7 @@ ibus_compose_table_compact_check (const IBusComposeTableCompactEx - row_stride = i + 2; - - if (seq_index[i + 1] - seq_index[i] > 0) { -+ g_assert (row_stride); - seq = bsearch (compose_buffer + 1, - table->data + seq_index[i], - (seq_index[i + 1] - seq_index[i]) / row_stride, -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index 0ef72c03..c1016703 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -220,7 +220,7 @@ init_gnome() - # G_MESSAGES_DEBUG=all or G_MESSAGES_DEBUG=GLib-GIO-DEBUG would append - # debug messages to gsettings output and could not get the result correctly. - backup_G_MESSAGES_DEBUG="$G_MESSAGES_DEBUG" -- export -n G_MESSAGES_DEBUG='' -+ unset G_MESSAGES_DEBUG - # Disable Tour dialog to get focus - V=`gsettings get org.gnome.shell welcome-dialog-last-shown-version` - if [ x"$V" = x"''" ] ; then -@@ -231,8 +231,8 @@ init_gnome() - NO_SYS_DIR=/usr/share/gnome-shell/extensions/no-overview@fthx - NO_USER_DIR=$HOME/.local/share/gnome-shell/extensions/no-overview@fthx - if [ ! -d $NO_SYS_DIR ] && [ ! -d $NO_USER_DIR ] ; then -- mkdir -p `dirname $NO_USER_DIR` -- cp -R no-overview@fthx `dirname $NO_USER_DIR` -+ mkdir -p "`dirname $NO_USER_DIR`" -+ cp -R "no-overview@fthx" "`dirname $NO_USER_DIR`" - fi - V=`gsettings get org.gnome.shell disable-user-extensions` - if [ x"$V" = x"true" ] ; then --- -2.28.0 - -From a823161768c8f6916dbdebe73842a9fc04521369 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Mon, 9 Aug 2021 12:36:40 +0900 -Subject: [PATCH] client/gtk2/ibusimcontext: Enable sync process in GTK4 - -gtk_im_context_filter_key() does not forward control keys likes -BackSpace, Return and change the process mode to the synchronization. - -BUG=https://gitlab.gnome.org/GNOME/gtk/-/issues/3465 ---- - client/gtk2/ibusimcontext.c | 65 +++++++++++++++++++++++-------------- - 1 file changed, 41 insertions(+), 24 deletions(-) - -diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c -index e7ce5363..da9a402f 100644 ---- a/client/gtk2/ibusimcontext.c -+++ b/client/gtk2/ibusimcontext.c -@@ -110,13 +110,15 @@ static guint _signal_preedit_end_id = 0; - static guint _signal_delete_surrounding_id = 0; - static guint _signal_retrieve_surrounding_id = 0; - --#if !GTK_CHECK_VERSION (3, 98, 4) -+#if GTK_CHECK_VERSION (3, 98, 4) -+static gboolean _use_sync_mode = TRUE; -+#else - static const gchar *_no_snooper_apps = NO_SNOOPER_APPS; - static gboolean _use_key_snooper = ENABLE_SNOOPER; - static guint _key_snooper_id = 0; --#endif - - static gboolean _use_sync_mode = FALSE; -+#endif - - static const gchar *_discard_password_apps = ""; - static gboolean _use_discard_password = FALSE; -@@ -767,11 +769,13 @@ ibus_im_context_class_init (IBusIMContextClass *class) - g_signal_lookup ("retrieve-surrounding", G_TYPE_FROM_CLASS (class)); - g_assert (_signal_retrieve_surrounding_id != 0); - --#if !GTK_CHECK_VERSION (3, 98, 4) -+#if GTK_CHECK_VERSION (3, 98, 4) -+ _use_sync_mode = _get_boolean_env ("IBUS_ENABLE_SYNC_MODE", TRUE); -+#else - _use_key_snooper = !_get_boolean_env ("IBUS_DISABLE_SNOOPER", - !(ENABLE_SNOOPER)); --#endif - _use_sync_mode = _get_boolean_env ("IBUS_ENABLE_SYNC_MODE", FALSE); -+#endif - _use_discard_password = _get_boolean_env ("IBUS_DISCARD_PASSWORD", FALSE); - - #define CHECK_APP_IN_CSV_ENV_VARIABLES(retval, \ -@@ -1434,6 +1438,9 @@ static gboolean - _set_cursor_location_internal (IBusIMContext *ibusimcontext) - { - GdkRectangle area; -+#if GTK_CHECK_VERSION (3, 98, 4) -+ GtkWidget *root; -+#endif - - if(ibusimcontext->client_window == NULL || - ibusimcontext->ibuscontext == NULL) { -@@ -1442,8 +1449,27 @@ _set_cursor_location_internal (IBusIMContext *ibusimcontext) - - area = ibusimcontext->cursor_area; - --#if !GTK_CHECK_VERSION (3, 98, 4) - #ifdef GDK_WINDOWING_WAYLAND -+#if GTK_CHECK_VERSION (3, 98, 4) -+ root = GTK_WIDGET (gtk_widget_get_root (ibusimcontext->client_window)); -+ /* FIXME: GTK_STYLE_CLASS_TITLEBAR is available in GTK3 but not GTK4. -+ * gtk_css_boxes_get_content_rect() is available in GTK4 but it's an -+ * internal API and calculate the window edge 32 in GTK3. -+ */ -+ area.y += 32; -+ area.width = 50; /* FIXME: Why 50 meets the cursor position? */ -+ area.height = gtk_widget_get_height (root); -+ area.height += 32; -+ if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) { -+ ibus_input_context_set_cursor_location_relative ( -+ ibusimcontext->ibuscontext, -+ area.x, -+ area.y, -+ area.width, -+ area.height); -+ return FALSE; -+ } -+#else - if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) { - gdouble px, py; - GdkWindow *parent; -@@ -1469,23 +1495,20 @@ _set_cursor_location_internal (IBusIMContext *ibusimcontext) - #endif - #endif - -- if (area.x == -1 && area.y == -1 && area.width == 0 && area.height == 0) { - #if GTK_CHECK_VERSION (3, 98, 4) -- area.x = 0; -- area.y += gtk_widget_get_height (ibusimcontext->client_window); - #elif GTK_CHECK_VERSION (2, 91, 0) -- area.x = 0; -- area.y += gdk_window_get_height (ibusimcontext->client_window); -+ area.y += gdk_window_get_height (ibusimcontext->client_window); - #else -+ if (area.x == -1 && area.y == -1 && area.width == 0 && area.height == 0) { - gint w, h; - gdk_drawable_get_size (ibusimcontext->client_window, &w, &h); - area.y += h; - area.x = 0; --#endif - } -+#endif - - #if GTK_CHECK_VERSION (3, 98, 4) --#ifdef GDK_WINDOWING_X11 -+#if defined(GDK_WINDOWING_X11) - GdkDisplay *display = gtk_widget_get_display (ibusimcontext->client_window); - if (GDK_IS_X11_DISPLAY (display)) { - Display *xdisplay = gdk_x11_display_get_xdisplay (display); -@@ -1505,21 +1528,10 @@ _set_cursor_location_internal (IBusIMContext *ibusimcontext) - XGetWindowAttributes (xdisplay, window, &xwa); - area.x = x - xwa.x + area.x; - area.y = y - xwa.y + area.y; -- area.width = xwa.width; -+ area.width = 50; /* FIXME: Why 50 meets the cursor position? */ - area.height = xwa.height; - } - #endif --#elif GTK_CHECK_VERSION (3, 93, 0) -- { -- GtkNative *native = gtk_widget_get_native ( -- ibusimcontext->client_window); -- GdkSurface *surface = gtk_native_get_surface (native); -- int root_x = 0; -- int root_y = 0; -- gdk_surface_get_position (surface, &root_x, &root_y); -- area.x += root_x; -- area.y += root_y; -- } - #else - gdk_window_get_root_coords (ibusimcontext->client_window, - area.x, area.y, -@@ -1541,12 +1553,17 @@ ibus_im_context_set_cursor_location (GtkIMContext *context, GdkRectangle *area) - - IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context); - -+#if !GTK_CHECK_VERSION (3, 93, 0) -+ /* The area is the relative coordinates and this has to get the absolute -+ * ones in _set_cursor_location_internal() since GTK 4.0. -+ */ - if (ibusimcontext->cursor_area.x == area->x && - ibusimcontext->cursor_area.y == area->y && - ibusimcontext->cursor_area.width == area->width && - ibusimcontext->cursor_area.height == area->height) { - return; - } -+#endif - ibusimcontext->cursor_area = *area; - _set_cursor_location_internal (ibusimcontext); - gtk_im_context_set_cursor_location (ibusimcontext->slave, area); --- -2.28.0 - From 943d37444d9cc0881cb5fff87bdd4b9efd5abdb4 Mon Sep 17 00:00:00 2001 From: fujiwarat Date: Mon, 9 Aug 2021 12:49:15 +0900