fujiwara / rpms / ibus

Forked from rpms/ibus 4 years ago
Clone
Blob Blame History Raw
From 214b60a3af67b6e8dafdb8edba666a369f18be12 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
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 <takao.fujiwara1@gmail.com>
+# Copyright (c) 2018-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
 # 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 <takao.fujiwara1@gmail.com>
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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2015-2020 Takao Fujiwara <takao.fujiwara1@gmail.com>
- * Copyright (C) 2008-2020 Red Hat, Inc.
+ * Copyright (C) 2015-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * 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 <takao.fujiwara1@gmail.com>
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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2011-2020 Takao Fujiwara <takao.fujiwara1@gmail.com>
- * Copyright (C) 2008-2020 Red Hat, Inc.
+ * Copyright (C) 2011-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * 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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2011-2019 Takao Fujiwara <takao.fujiwara1@gmail.com>
- * Copyright (C) 2008-2019 Red Hat, Inc.
+ * Copyright (C) 2011-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * 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 <errno.h>
 #include <glib/gstdio.h>
 #include <gio/gio.h>
-#include <stdlib.h>
-#include <fcntl.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
 #include <string.h>
 
 #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 <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2019-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
  * 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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2015-2019 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2015-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
  * 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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2010 Red Hat, Inc.
+ * Copyright (C) 2012-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * 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 <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2016-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
  * 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 <glib/gi18n.h>\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 <glib/gi18n.h>\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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2015-2019 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2015-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
  * 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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2013-2019 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2013-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -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 <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2017-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
  * 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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2015-2019 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2015-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
  * 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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2018-2019 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2018-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
  * 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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2015-2020 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2015-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
  * 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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2015-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2015-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
  * 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 <shawn.p.huang@gmail.com>
- * Copyright (C) 2008-2010 Red Hat, Inc.
+ * Copyright (C) 2011-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * 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 <takao.fujiwara1@gmail.com>
- * Copyright (C) 2018-2019 Red Hat, Inc.
+ * Copyright (C) 2018-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * 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 <takao.fujiwara1@gmail.com>
- * Copyright (C) 2018 Red Hat, Inc.
+ * Copyright (C) 2018-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * 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 <glib/gi18n.h>\n"));
-    g_string_append (buff, g_strdup ("\n"));
-    g_string_append (buff, g_strdup ("#ifndef __IBUS_UNICODE_GEN_H_\n"));
-    g_string_append (buff, g_strdup ("#define __IBUS_UNICODE_GEN_H_\n"));
-    g_string_append (buff, g_strdup ("const static char *unicode_blocks[] = {\n"));
+    g_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 <glib/gi18n.h>\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 <takao.fujiwara1@gmail.com>
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- <software@lfcode.ca>
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 <glib.h>
 #include <glib/gstdio.h>
-#include <locale.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -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 <a> <b>...: %s", line);
+        g_warning ("too few words; key sequence format is <a> <b>...: %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 <takao.fujiwara1@gmail.com>
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- <software@lfcode.ca>
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:
```
<Multi_key> <g> <h> : "η"
<Multi_key> <g> <v> <t> <h> : "ϑ"
<Multi_key> <g> <h>     : "ɣ"
```

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 <takao.fujiwara1@gmail.com>
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 <takao.fujiwara1@gmail.com>
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 @@
       <description>The shortcut keys for turning Unicode typing on or off</description>
     </key>
     <key name="hotkey" type="as">
-      <default>[ '&lt;Control&gt;&lt;Shift&gt;e' ]</default>
+      <default>[ '&lt;Control&gt;period' ]</default>
       <summary>Emoji shortcut keys for gtk_accelerator_parse</summary>
       <description>The shortcut keys for turning emoji typing on or off</description>
     </key>
-- 
2.28.0

From a4939f67f9de8275219e2cfcd3873e0fbe59058f Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
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 <takao.fujiwara1@gmail.com>
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 <shawn.p.huang@gmail.com>
-# Copyright (c) 2015-2019 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2015-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
 # 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 <takao.fujiwara1@gmail.com>
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 <takao.fujiwara1@gmail.com>
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 <takao.fujiwara1@gmail.com>
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 <takao.fujiwara1@gmail.com>
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 <takao.fujiwara1@gmail.com>
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 <errno.h>
+#include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <glib/gstdio.h>
 #include <gio/gio.h>
+#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