public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Takao Fujiwara <tfujiwar@redhat.com>
To: git-commits@fedoraproject.org
Subject: [rpms/ibus] rawhide: Delete upstreamed patches
Date: Wed, 12 Aug 2026 03:33:32 GMT	[thread overview]
Message-ID: <178650561244.1.7653892918845798900.rpms-ibus-d3bddab90644@fedoraproject.org> (raw)

A new commit has been pushed.

Repo   : rpms/ibus
Branch : rawhide
Commit : d3bddab90644a1c1aa1452a1a3c86e8316db01b0
Author : Takao Fujiwara <tfujiwar@redhat.com>
Date   : 2026-08-12T12:27:05+09:00
Stats  : +0/-2546 in 1 file(s)
URL    : https://src.fedoraproject.org/rpms/ibus/c/d3bddab90644a1c1aa1452a1a3c86e8316db01b0?branch=rawhide

Log:
Delete upstreamed patches

---
diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch
deleted file mode 100644
index 0e34d54..0000000
--- a/ibus-HEAD.patch
+++ /dev/null
@@ -1,2546 +0,0 @@
-From 44e22e5e7602bc79040df42cbfa836ba32da01ef Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Thu, 16 Jul 2026 12:37:28 +0900
-Subject: [PATCH 1/2] src/tests: Fix CI issues in GNOME 50
-
-- 100-ibus-ci.rules: Disable authentication dialogs in gnome-shell
-- ibus-compose:
-  o Add taking screenshots with IBUS_TEST_SCREENSHOT
-  o Define ibus_break_if_fail() from g_return_if_fail()
-- ibus-desktop-testing-autostart: Call dump_screen_of_test_cases()
-- ibus-desktop-testing-module:
-  o Update the latest gnome-shell service file for GNOME 50.
-  o Replace init with systemctl in ibus-desktop-testing-module
-  o Set locale for gnome-shell while the user systemd runs in C locale
-  o Implement dump_screen_of_test_cases() to dump screenshots of test cases
-  o export IBUS_TEST_SCREENSHOT to each test case to take screenshots
-  o Install polkit rule file
-  o forward --screendump option to autostart script
-- runtest: Set tstdir for Python test cases
-
-- src/meson: Reduce time to build emoji dicts
-- src/tests/[Makefile|meson]: Install 100-ibus-ci.rules
-
-Closes #2921
----
- src/meson.build                             |  41 ++++---
- src/tests/100-ibus-ci.rules                 |   8 ++
- src/tests/Makefile.am                       |  12 +-
- src/tests/ibus-compose.c                    |  76 ++++++++++++
- src/tests/ibus-desktop-testing-autostart.in |   1 +
- src/tests/ibus-desktop-testing-module       | 122 ++++++++++++++++----
- src/tests/meson.build                       |   5 +
- src/tests/runtest                           |  81 ++++++-------
- 8 files changed, 266 insertions(+), 80 deletions(-)
- create mode 100644 src/tests/100-ibus-ci.rules
-
-diff --git a/src/meson.build b/src/meson.build
-index 1fb0786b..34da1334 100644
---- a/src/meson.build
-+++ b/src/meson.build
-@@ -301,23 +301,30 @@ if get_option('emoji-dict')
-       ]
-     endif
- 
--    emoji_parser_gen = custom_target(gen_emoji_dict,
--      input: emoji_xml,
--      output: gen_emoji_dict,
--      command: [
--        emoji_parser,
--        '--unicode-emoji-dir', get_option('unicode-emoji-dir'),
--        '--xml', emoji_xml,
--        '--out', '@OUTPUT@',
--        emoji_parser_extra_opts,
--      ],
--      install_dir: pkgdatadir / 'dicts',
--      # The conditional installation does not work so use
--      # meson.add_install_script()
--      # install: fs.exists('@OUTPUT@') and fs.size('@OUTPUT@') > 0,
--      install: true,
--      build_by_default: true,
--    )
-+    if fs.exists(meson.current_build_dir() / gen_emoji_dict)
-+      install_data(
-+        meson.current_build_dir() / gen_emoji_dict,
-+        install_dir: pkgdatadir / 'dicts',
-+      )
-+    else
-+      emoji_parser_gen = custom_target(gen_emoji_dict,
-+        input: emoji_xml,
-+        output: gen_emoji_dict,
-+        command: [
-+          emoji_parser,
-+          '--unicode-emoji-dir', get_option('unicode-emoji-dir'),
-+          '--xml', emoji_xml,
-+          '--out', '@OUTPUT@',
-+          emoji_parser_extra_opts,
-+        ],
-+        install_dir: pkgdatadir / 'dicts',
-+        # The conditional installation does not work so use
-+        # meson.add_install_script()
-+        # install: fs.exists('@OUTPUT@') and fs.size('@OUTPUT@') > 0,
-+        install: true,
-+        build_by_default: true,
-+      )
-+    endif
-   endforeach
- 
-   # There are cases where there was no .dict file to output
-diff --git a/src/tests/100-ibus-ci.rules b/src/tests/100-ibus-ci.rules
-new file mode 100644
-index 00000000..d6d2f7c0
---- /dev/null
-+++ b/src/tests/100-ibus-ci.rules
-@@ -0,0 +1,8 @@
-+polkit.addRule(function(action, subject) {
-+    if ((action.id == "org.freedesktop.Flatpak.metadata-update" ||
-+         action.id == "org.freedesktop.Flatpak.modify-repo" ||
-+         action.id == "org.freedesktop.fwupd.refresh-remote" ) &&
-+        subject.isInGroup("itestuser")) {
-+        return polkit.Result.YES;
-+    }
-+});
-diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
-index 75caab57..47cd3db1 100644
---- a/src/tests/Makefile.am
-+++ b/src/tests/Makefile.am
-@@ -131,11 +131,14 @@ CLEANFILES += ibus-compose-locales
- endif
- test_execsdir = $(libexecdir)/installed-tests/ibus
- libexec_SCRIPTS = \
--  ibus-desktop-testing-autostart \
--  ibus-desktop-testing-module \
--  $(NULL)
-+    ibus-desktop-testing-autostart \
-+    ibus-desktop-testing-module \
-+    $(NULL)
- 
--test_frame_DATA = org.freedesktop.IBus.Desktop.Testing.desktop
-+test_frame_DATA = \
-+    100-ibus-ci.rules \
-+    org.freedesktop.IBus.Desktop.Testing.desktop \
-+    $(NULL)
- test_framedir = $(pkgdatadir)/tests
- org.freedesktop.IBus.Desktop.Testing.desktop: ibus-desktop-testing.desktop.in
- 	$(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|g" \
-@@ -194,6 +197,7 @@ ibus-desktop-testing-runner: ibus-desktop-testing-runner.in
- EXTRA_DIST = \
-     $(test_metas_in) \
-     $(TESTS_SCRIPT) \
-+    100-ibus-ci.rules \
-     runtest \
-     ibus-compose.basic \
-     ibus-compose.basic2 \
-diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c
-index 69f844b2..c36b4c81 100644
---- a/src/tests/ibus-compose.c
-+++ b/src/tests/ibus-compose.c
-@@ -7,6 +7,17 @@
- #define RED   "\033[0;31m"
- #define NC    "\033[0m"
- 
-+#define ibus_break_if_fail(expr) \
-+    G_STMT_START { \
-+        if (G_LIKELY (expr)) { \
-+        } else { \
-+            g_return_if_fail_warning (G_LOG_DOMAIN, \
-+                                      G_STRFUNC, \
-+                                      #expr); \
-+            break; \
-+        } \
-+    } G_STMT_END
-+
- static gchar *m_test_locale;
- static gchar *m_test_name;
- static gchar *m_session_name;
-@@ -113,6 +124,67 @@ get_compose_path ()
- }
- 
- 
-+static void
-+take_screenshot (void)
-+{
-+    gint64 t;
-+    GDateTime *dt;
-+    gchar *prgname = NULL;
-+    gchar *casename = NULL;
-+    gchar *filename = NULL;
-+    gchar *path = NULL;
-+    gchar *args[4] = { "gnome-screenshot", "--file", 0, 0 };
-+    GSpawnFlags flags = G_SPAWN_SEARCH_PATH;
-+    gchar *std_output = NULL;
-+    gchar *std_error = NULL;
-+    GError *error = NULL;
-+
-+    t = g_get_real_time ();
-+    t = t / G_USEC_PER_SEC;
-+    dt = g_date_time_new_from_unix_utc (t);
-+    g_return_if_fail (dt);
-+
-+    while (FALSE) {
-+        prgname = g_path_get_basename (g_get_prgname ());
-+        casename = g_path_get_basename (g_test_get_path ());
-+        ibus_break_if_fail (prgname);
-+        ibus_break_if_fail (casename);
-+        filename = g_strdup_printf ("%s%s-%02d%02d%02d.png",
-+                                    prgname, casename,
-+                                    g_date_time_get_hour (dt),
-+                                    g_date_time_get_minute (dt),
-+                                    g_date_time_get_second (dt));
-+        ibus_break_if_fail (filename);
-+        /* The ibus-compose-locales runs in a temp dir. */
-+        path = g_build_filename (g_get_home_dir (), filename, NULL);
-+        ibus_break_if_fail (path);
-+        args[2] = path;
-+        if (!g_spawn_sync (NULL, args, NULL, flags, NULL, NULL,
-+                           &std_output, &std_error,
-+                           NULL,
-+                           &error)) {
-+            g_warning ("Failed to take a screenshot: %s: %s: %s",
-+                       error->message,
-+                       std_output ? std_output : "",
-+                       std_error ? std_error : "");
-+            g_error_free (error);
-+        } else if (std_error && *std_error) {
-+            g_warning ("Failed to take a screenshot: %s: %s",
-+                       std_output ? std_output : "",
-+                       std_error);
-+        }
-+    }
-+
-+    g_free (prgname);
-+    g_free (casename);
-+    g_date_time_unref (dt);
-+    g_free (filename);
-+    g_free (path);
-+    g_free (std_output);
-+    g_free (std_error);
-+}
-+
-+
- gboolean
- idle_cb (gpointer user_data)
- {
-@@ -436,9 +508,13 @@ set_engine_cb (GObject      *object,
-         return;
-     }
- 
-+    if (g_getenv ("IBUS_TEST_SCREENSHOT"))
-+        take_screenshot ();
-     send_key_event (m_compose_table);
-     if (m_no_load_compose_table)
-         send_key_event (m_no_load_compose_table);
-+    if (g_getenv ("IBUS_TEST_SCREENSHOT"))
-+        take_screenshot ();
- 
- #if GTK_CHECK_VERSION (4, 0, 0)
-     g_signal_handlers_disconnect_by_func (
-diff --git a/src/tests/ibus-desktop-testing-autostart.in b/src/tests/ibus-desktop-testing-autostart.in
-index 9ecc8c27..a9a57bed 100755
---- a/src/tests/ibus-desktop-testing-autostart.in
-+++ b/src/tests/ibus-desktop-testing-autostart.in
-@@ -76,6 +76,7 @@ main()
-     #run_monitor
-     save_screen
-     run_test_suite
-+    dump_screen_of_test_cases
-     finit
- }
- 
-diff --git a/src/tests/ibus-desktop-testing-module b/src/tests/ibus-desktop-testing-module
-index 55eb248e..b71d73a9 100755
---- a/src/tests/ibus-desktop-testing-module
-+++ b/src/tests/ibus-desktop-testing-module
-@@ -51,16 +51,19 @@ TEST_USER=itestuser
- TEST_USER_HOME=/export/home/$TEST_USER
- GDM_CONF=/run/gdm/custom.conf
- AUTOSTART_DESKTOP_FILE="org.freedesktop.IBus.Desktop.Testing.desktop"
-+POLKIT_CUSTOM_RULE_FILE="100-ibus-ci.rules"
- TESTS=""
- TIMEOUT=300
- GREEN='\033[0;32m'
- RED='\033[0;31m'
- NC='\033[0m'
-+DQ='"'
- ENV_CHECK=0
- ENV_COMMANDS='
- id
- pwd
- pstree -asp $$
-+tr "\\0" "\\n" < /proc/$$/environ
- gsettings list-recursively org.gnome.shell
- rpm -q gnome-shell-extension-no-overview gnome-shell gnome-session
- ps -ef | grep ibus | grep -v TMT | grep -v grep
-@@ -132,7 +135,7 @@ delete-tests\
- check_tty()
- {
-     TTY=`tty`
--    if echo $PROGNAME | grep -q runner ; then
-+    if echo "$PROGNAME" | grep -q runner ; then
-         if [ $ENABLED_SYSTEMD -eq 1 ] && [  $SESSION_IS_GNOME -eq 1 ] ; then
-             # "not a tty" is correct with TMT tool
-             if echo "$TTY" | grep -E 'tty|console' | grep -v "not a tty" ; then
-@@ -217,6 +220,20 @@ save_screen()
- }
- 
- 
-+dump_screen_of_test_cases()
-+{
-+    if test x"$SCREEN_LOG" != xSTDOUT ; then
-+        return
-+    fi
-+    for png in "$TEST_USER_HOME"/*.png ; do
-+        test -f "$png" || continue
-+        echo "## Dump start $png" 2>>$TEST_LOG 1>>$TEST_LOG
-+        base64 "$png"             2>>$TEST_LOG 1>>$TEST_LOG
-+        echo "## Dump end $png"   2>>$TEST_LOG 1>>$TEST_LOG
-+    done
-+}
-+
-+
- create_test_user()
- {
-     if grep -q $TEST_USER /etc/passwd; then
-@@ -230,10 +247,11 @@ create_test_user()
- 
- create_autologin_gdm()
- {
--    if test -f $GDM_CONF && grep -q $TEST_USER $GDM_CONF; then
-+    mkdir -p  `dirname "$GDM_CONF"`
-+    if test -f "$GDM_CONF" && grep -q "$TEST_USER" "$GDM_CONF"; then
-         return;
-     fi
--    cat > $GDM_CONF << _EOF_GDM_CONF
-+    cat > "$GDM_CONF" << _EOF_GDM_CONF
- [daemon]
- AutomaticLoginEnable=true
- AutomaticLogin=$TEST_USER
-@@ -256,7 +274,12 @@ create_xdg_autostart()
-         exit 1
-     fi
-     mkdir -p "$TEST_USER_HOME/.config/autostart"
--    sed -e "s/\(^Exec=.*\)tests ibus\(.*\)/\1tests $TESTS\2/" "$desktop_file" \
-+    ARGS_PLUS=""
-+    if test x"$SCREEN_LOG" != x ; then
-+        ARGS_PLUS="$ARGS_PLUS --screendump $SCREEN_LOG"
-+    fi
-+    sed -e "s/\(^Exec=.*\)tests ibus\(.*\)/\1tests $TESTS $ARGS_PLUS\2/" \
-+        "$desktop_file" \
-         > "$TEST_USER_HOME/.config/autostart/$AUTOSTART_DESKTOP_FILE"
-     LINE="AutostartCondition=if-exists $TEST_USER_HOME/.config/autostart/$AUTOSTART_DESKTOP_FILE"
-     echo "$LINE" >> "$TEST_USER_HOME/.config/autostart/$AUTOSTART_DESKTOP_FILE"
-@@ -334,6 +357,21 @@ init_session()
-         TESTS='ibus'
-     fi
-     check_tty
-+    IS_SYSTEM_ACCOUNT=false
-+    if [ "$LOGIN_USER" = "root" ] ; then
-+            IS_SYSTEM_ACCOUNT=true
-+    fi
-+    if test x"$SESSION_LANG" = x ; then
-+        SESSION_LANG=$LANG
-+    fi
-+    if test x"$SCREEN_LOG" != x ; then
-+        export IBUS_TEST_SCREENSHOT=1
-+    fi
-+
-+    if ! echo "$PROGNAME" | grep -q runner ; then
-+        return
-+    fi
-+
-     if [ $ENABLED_SYSTEMD -eq 1 ] && [  $SESSION_IS_GNOME -eq 1 ] ; then
-         SESSION_FILE1="/usr/lib/systemd/system/gnome-headless-session@.service"
-         SESSION_FILE2="/usr/lib/systemd/system/graphical.target"
-@@ -365,13 +403,6 @@ init_session()
-         touch $LOGIN_HOME/.config/gnome-initial-setup-done
-         chown -R $LOGIN_USER $LOGIN_HOME/.config
-     fi
--    IS_SYSTEM_ACCOUNT=false
--    if [ "$LOGIN_USER" = "root" ] ; then
--            IS_SYSTEM_ACCOUNT=true
--    fi
--    if test x"$SESSION_LANG" = x ; then
--        SESSION_LANG=$LANG
--    fi
-     if test -f /var/lib/AccountsService/users/$LOGIN_USER; then
-         sed -i -e "s/\(Language=\).*/\1$SESSION_LANG/" \
-                 /var/lib/AccountsService/users/$LOGIN_USER
-@@ -384,6 +415,35 @@ XSession=gnome
- SystemAccount=$IS_SYSTEM_ACCOUNT
- _EOF_AS_CONF
-     fi
-+    # for ibus-keypress
-+    ls -l /dev/uinput 2>>$TEST_LOG 1>>$TEST_LOG
-+    chgrp itestuser /dev/uinput
-+    chmod g+rw /dev/uinput
-+    ls -l /dev/uinput 2>>$TEST_LOG 1>>$TEST_LOG
-+
-+    # aciton.id 'org.freedesktop.fwupd.refresh-remote' and
-+    # aciton.message "Authentication is required to update the metadata for a "
-+    # "configured remote used for firmware updates" is defined in
-+    # /usr/share/polkit-1/actions/org.freedesktop.fwupd.policy file
-+    # and that message is shown in "Authentication Required" dialog in
-+    # gnome-shell headless session in GNOME 50.
-+    # action.id 'org.freedesktop.Flatpak.metadata-update' and
-+    # action.id 'org.freedesktop.Flatpak.modify-repo' are also shown.
-+    rule_file="$AUTOSTART_DESKTOP_DIR/$POLKIT_CUSTOM_RULE_FILE"
-+    if test ! -f "$rule_file" ; then
-+        print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: No $rule_file"
-+        exit 1
-+    fi
-+    POLKIT_CUSTOM_RULE_DIR="/etc/polkit-1/rules.d"
-+    if test ! -d "$POLKIT_CUSTOM_RULE_DIR" ; then
-+        mkdir -p  "$POLKIT_CUSTOM_RULE_DIR"
-+        chmod 755 "$POLKIT_CUSTOM_RULE_DIR"
-+    fi
-+    if test ! -f "$POLKIT_CUSTOM_RULE_DIR/$POLKIT_CUSTOM_RULE_FILE" ; then
-+        cp "$rule_file" "$POLKIT_CUSTOM_RULE_DIR/$POLKIT_CUSTOM_RULE_FILE"
-+        chmod 644 "$POLKIT_CUSTOM_RULE_DIR/$POLKIT_CUSTOM_RULE_FILE"
-+        systemctl restart polkit
-+    fi
- 
-     # Prevent from launching a XDG dialog
-     XDG_LOCALE_FILE="$LOGIN_HOME/.config/user-dirs.locale"
-@@ -503,19 +563,39 @@ init_gnome()
-     ## gnome-headless-session does not pull LANG from AccountsService.
-     ##
-     if [ $LOGIN_USER != $USER ] ; then
--        SHELL_SERVICE_FILE="org.gnome.Shell@wayland.service"
-+        SHELL_SERVICE_FILE="org.gnome.Shell@.service"
-+        SHELL_SERVICE_DEST_FILE="org.gnome.Shell@user.service"
-         SYSTEMD_USER_DIR="$TEST_USER_HOME/.config/systemd/user"
-         ENV_USER_DIR="$TEST_USER_HOME/.config/environment.d"
-         LOCALE_CONF="$ENV_USER_DIR/ibus.conf"
-+        # If GNOME version < 50
-+        if test ! -f "$SYSTEMD_SYSTEM_DIR/$SHELL_SERVICE_FILE" ; then
-+            SHELL_SERVICE_FILE="org.gnome.Shell@wayland.service"
-+            SHELL_SERVICE_DEST_FILE="$SHELL_SERVICE_FILE"
-+        else
-+            GNOME_SHELL_WAYLAND_COMMAND="$GNOME_SHELL_WAYLAND_COMMAND --mode=%i"
-+        fi
-+        if test x"$SCREEN_LOG" != x ; then
-+            GNOME_SHELL_WAYLAND_COMMAND="$GNOME_SHELL_WAYLAND_COMMAND --unsafe-mode"
-+        fi
-         if test $HAVE_GRAPHICS -ne 1 ; then
-             if test ! -f "$SYSTEMD_USER_DIR/$SHELL_SERVICE_FILE" ; then
-+                PREV_DIR="$PWD"
-                 mkdir -p "$SYSTEMD_USER_DIR"
--                pushd "$SYSTEMD_USER_DIR"
-+                cd "$SYSTEMD_USER_DIR"
-+                # The user systemd and $GNOME_SHELL_WAYLAND_COMMAND no longer
-+                # loads $LOCALE_CONF file
-+                # So sets Environment in the service file.
-                 sed -e "s|^ExecStart=.*|ExecStart=$GNOME_SHELL_WAYLAND_COMMAND|" \
--                    $SYSTEMD_SYSTEM_DIR/$SHELL_SERVICE_FILE \
--                    > $SHELL_SERVICE_FILE
--                diff $SYSTEMD_SYSTEM_DIR/$SHELL_SERVICE_FILE $SHELL_SERVICE_FILE
--                popd
-+                    $SYSTEMD_SYSTEM_DIR/$SHELL_SERVICE_FILE | \
-+                sed -e "/^ExecStart=/i\\
-+Environment=LANG=$DQ$SESSION_LANG$DQ" \
-+                    > "$SHELL_SERVICE_DEST_FILE"
-+                echo "# diff $SYSTEMD_SYSTEM_DIR/$SHELL_SERVICE_FILE" \
-+                     "$SHELL_SERVICE_DEST_FILE" 2>>$TEST_LOG 1>>$TEST_LOG
-+                diff "$SYSTEMD_SYSTEM_DIR/$SHELL_SERVICE_FILE" \
-+                     "$SHELL_SERVICE_DEST_FILE" 2>>$TEST_LOG 1>>$TEST_LOG
-+                cd "$PREV_DIR"
-             fi
-             mkdir -p "$ENV_USER_DIR"
-             cat > "$LOCALE_CONF" << _EOF_LOCALE_CONF
-@@ -590,7 +670,7 @@ operate_desktop_with_systemd()
-         "start") systemctl isolate graphical.target
-                  echo ""
-                  ;;
--        "stop")  init 3;;
-+        "stop")  systemctl isolate multi-user.target;;
-         "")      print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: Wrong command $COMMAND"
-                  exit 1;;
-         esac
-@@ -808,6 +888,8 @@ run_gnome_desktop_testing_runner()
-     fail=0
-     if echo $PROGNAME | grep -q autostart ; then
-         export IBUS_DAEMON_WITH_SYSTEMD=1
-+        #export GSK_RENDERER=cairo
-+        export VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/lvp_icd.`uname -m`.json
-     fi
-     for tst in $TESTS; do
-         tst_dir="$TEST_CASE_DIR/$tst"
-@@ -840,7 +922,7 @@ EOF
- run_test_suite()
- {
-     print_log -e "Start test suite `date '+%F %H:%M:%S:%N'`"
--    if echo $PROGNAME | grep -q runner ; then
-+    if echo "$PROGNAME" | grep -q runner ; then
-         if [ $ENABLED_SYSTEMD -eq 1 ] && [  $SESSION_IS_GNOME -eq 1 ] ; then
-             wait_for_systemd_autostart
-             return
-@@ -903,7 +985,7 @@ finit()
-             echo "$LEFT_CALENDAR" | awk '{print $2}' | xargs kill
-         fi
-     fi
--    if echo $PROGNAME | grep -q runner ; then
-+    if echo "$PROGNAME" | grep -q runner ; then
-         if [ $ENABLED_SYSTEMD -eq 1 ] && [  $SESSION_IS_GNOME -eq 1 ] ; then
-             operate_desktop_with_systemd "stop"
-         fi
-diff --git a/src/tests/meson.build b/src/tests/meson.build
-index 94ac03e0..0baa6c8f 100644
---- a/src/tests/meson.build
-+++ b/src/tests/meson.build
-@@ -193,4 +193,9 @@ if get_option('install-tests')
-     },
-     install_dir: pkgdatadir / 'tests',
-   )
-+
-+  install_data(
-+    '100-ibus-ci.rules',
-+    install_dir: pkgdatadir / 'tests',
-+  )
- endif
-diff --git a/src/tests/runtest b/src/tests/runtest
-index 4e54420f..dee675cb 100755
---- a/src/tests/runtest
-+++ b/src/tests/runtest
-@@ -94,12 +94,12 @@ func_dirname () {
- 
- # Kill ibus-daemon process and remove temporary files.
- func_cleanup () {
--    tstdir=$1
--    if test -f $tstdir/ibus-daemon.pid; then
--        . $tstdir/ibus-daemon.pid
-+    tstdir="$1"
-+    if test -f "$tstdir/ibus-daemon.pid"; then
-+        . "$tstdir/ibus-daemon.pid"
-         kill $IBUS_DAEMON_PID > /dev/null 2>&1
-     fi
--    rm -fr $tstdir
-+    rm -fr "$tstdir"
- }
- 
- # Prepare component files necessary for testing, under components/.
-@@ -115,13 +115,18 @@ func_copy_component () {
-     fi
- }
- 
--trap 'func_cleanup $tstdir' 1 2 3 15
-+trap 'func_cleanup "$tstdir"' 1 2 3 15
- 
--tst=$1; shift
--tstdir=tmp-`func_basename $tst`
-+tst="$1"; shift
-+real_tst="$tst"
-+if echo "$tst" | grep -q 'python' ; then
-+    real_tst="$1"
-+fi
-+real_tst_name=`func_basename "$real_tst"`
-+tstdir="tmp-$real_tst_name"
- 
- for t in $DISABLE_GUI_TESTS; do
--    if test $t = `func_basename $tst`; then
-+    if test "$t" = "$real_tst_name"; then
-         exit 77
-     fi
- done
-@@ -134,24 +139,22 @@ fi
- 
- run_test_case()
- {
--    test -d $tstdir || mkdir $tstdir
--    backup_dir=$PWD
--    cd $tstdir
--
-     if echo "$tst" | grep -q 'python' ; then
-         # Convert the relative path to the absolute path.
-         if echo "$tst" | grep -q "\./" ; then
--            tst=`realpath $tst`
-+            tst=`realpath "$tst"`
-         elif ! echo "$tst" | grep -q "/" ; then
--            tst=`command -v $tst`
-+            tst=`command -v "$tst"`
-         fi
--        name=`func_basename "$1"`
--    else
--        name=`func_basename "$tst"`
-     fi
-+
-+    test -d "$tstdir" || mkdir "$tstdir"
-+    backup_dir="$PWD"
-+    cd "$tstdir"
-+
-     need_bus=no
-     for t in $BUS_REQUIRED_TESTS; do
--        if test "$t" = "$name"; then
-+        if test "$t" = "$real_tst_name"; then
-             need_bus=yes
-         fi
-     done
-@@ -165,10 +168,10 @@ run_test_case()
-         func_copy_component "$test_top_srcdir/engine/simple.xml"
-         func_copy_component "$test_top_srcdir/conf/memconf/memconf.xml"
- 
--        IBUS_COMPONENT_PATH=$PWD/components
-+        IBUS_COMPONENT_PATH="$PWD/components"
-         export IBUS_COMPONENT_PATH
- 
--        IBUS_ADDRESS_FILE=$PWD/ibus-daemon.pid
-+        IBUS_ADDRESS_FILE="$PWD/ibus-daemon.pid"
-         export IBUS_ADDRESS_FILE
- 
-         test $TEST_GTK -eq 1 && case $TEST_GTK_VERSION in
-@@ -194,9 +197,9 @@ run_test_case()
-                 echo "NOT FOUND $top_builddir/client/gtk3/im-ibus.so"
-                 exit 1
-             fi
--            GTK_IM_MODULE_FILE=$PWD/imcache
-+            GTK_IM_MODULE_FILE="$PWD/imcache"
-             export GTK_IM_MODULE_FILE
--            $GTK_QUERY_MODULE "$IM_IBUS_SO" > $GTK_IM_MODULE_FILE
-+            $GTK_QUERY_MODULE "$IM_IBUS_SO" > "$GTK_IM_MODULE_FILE"
-             ;;
-         *)
-             echo "NOT SUPPORT GTK_VERSION $TEST_GTK_VERSION"
-@@ -204,19 +207,19 @@ run_test_case()
-             ;;
-         esac || :
- 
--        cp "$test_top_srcdir/data/dconf/$IBUS_SCHEMA_FILE" $PWD
--        glib-compile-schemas $PWD 2>/dev/null
-+        cp "$test_top_srcdir/data/dconf/$IBUS_SCHEMA_FILE" "$PWD"
-+        glib-compile-schemas "$PWD" 2>/dev/null
-         if test $? -ne 0 ; then
-             echo "FAILED glib-compile-schemas"
-             retval=1
-             return
-         fi
--        if test ! -f $PWD/gschemas.compiled ; then
-+        if test ! -f "$PWD/gschemas.compiled" ; then
-             echo "NOT FOUND $PWD/gschemas.compiled"
-             retval=1
-             return
-         fi
--        export GSETTINGS_SCHEMA_DIR=$PWD
-+        export GSETTINGS_SCHEMA_DIR="$PWD"
- 
-         # Start ibus-daemon.
-         DAEMON_ARGS='
-@@ -227,10 +230,10 @@ run_test_case()
-             --verbose
-         '
-         if test x"$DISABLE_DAEMONIZE_IN_TESTS" = x ; then
--            $test_top_builddir/bus/ibus-daemon \
-+            "$test_top_builddir/bus/ibus-daemon" \
-                 $DAEMON_ARGS --daemonize;
-         else
--            $test_top_builddir/bus/ibus-daemon \
-+            "$test_top_builddir/bus/ibus-daemon" \
-                 $DAEMON_ARGS &
-         fi
- 
-@@ -250,8 +253,8 @@ run_test_case()
- 
-     if echo "$tst" | grep -q '^/' ; then
-         if echo "$tst" | grep -q 'python' ; then
--            interpreter=$tst
--            tst=$1
-+            interpreter="$tst"
-+            tst="$1"
-             shift
-             if echo "$tst" | grep -q '^/' ; then
-                 # absolute path for Meson
-@@ -262,28 +265,28 @@ run_test_case()
-             fi
-         else
-             # absolute path for Meson
--            "$tst" $test_top_srcdir/src/tests ${1+"$@"}
-+            "$tst" "$test_top_srcdir/src/tests" ${1+"$@"}
-         fi
-     else
-         # relative path for each execution
--        "../$tst" $test_top_srcdir/src/tests ${1+"$@"}
-+        "../$tst" "$test_top_srcdir/src/tests" ${1+"$@"}
-     fi
- 
-     retval=`expr $retval \| $?`
- 
--    cd $backup_dir
-+    cd "$backup_dir"
- 
--    func_cleanup $tstdir
-+    func_cleanup "$tstdir"
- }
- 
--envfile=$srcdir/`func_basename $tst`.env
--if test -f $envfile ; then
-+envfile="$srcdir/$real_tst_name".env
-+if test -f "$envfile" ; then
-     ENVS="`cat $envfile`"
- fi;
- if test x"$ENVS" = x ; then
-     run_test_case $@
- else
--    LANG_backup=$LANG
-+    LANG_backup="$LANG"
-     i=1
-     # mesonbuild/mtest.py:TAPParser.parse_line() says:
-     # 'version number must be on the first line'
-@@ -307,7 +310,7 @@ else
-         unset COMPOSE_FILE
-         export $e
-         # TAP info should start with "# ".
--        echo "# Run `func_basename $tst` on $e"
-+        echo "# Run $real_tst_name on $e"
-         echo "# ======================="
-         run_test_case $@
-         name="/"`basename "$1"`":$LANG:$COMPOSE_FILE:$NO_LOAD_COMPOSE_FILE"
-@@ -325,7 +328,7 @@ else
-     `echo "$ENVS"`
- EOF_ENVS
-     unset G_TEST_ROOT_PROCESS
--    export LANG=$LANG_backup
-+    export LANG="$LANG_backup"
- fi
- 
- exit $retval
--- 
-2.54.0
-
-From 1a0d9a6bc3afe241838c97ca381e1bd0b376a2b5 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Sun, 19 Jul 2026 18:10:01 +0900
-Subject: [PATCH 2/2] src/tests/ibus-compose: Fix typo
-
-Fixes: 44e22e5e
----
- meson.build              | 1 +
- src/tests/ibus-compose.c | 4 ++--
- 2 files changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/meson.build b/meson.build
-index 7cd906d7..c57b002d 100644
---- a/meson.build
-+++ b/meson.build
-@@ -391,6 +391,7 @@ install_emptydir(get_option('datadir') / 'ibus' / 'engine')
- summary({
-   'Install prefix':                get_option('prefix'),
-   'CFLAGS':                        get_option('c_args'),
-+  'LDFLAGS':                       get_option('c_link_args'),
-   'Build endianness':              endian,
-   'PYTHON':                        python.full_path(),
-   'Build PyGObject':               enable_pygobject,
-diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c
-index c36b4c81..d0c573e5 100644
---- a/src/tests/ibus-compose.c
-+++ b/src/tests/ibus-compose.c
-@@ -144,7 +144,7 @@ take_screenshot (void)
-     dt = g_date_time_new_from_unix_utc (t);
-     g_return_if_fail (dt);
- 
--    while (FALSE) {
-+    do {
-         prgname = g_path_get_basename (g_get_prgname ());
-         casename = g_path_get_basename (g_test_get_path ());
-         ibus_break_if_fail (prgname);
-@@ -173,7 +173,7 @@ take_screenshot (void)
-                        std_output ? std_output : "",
-                        std_error);
-         }
--    }
-+    } while (FALSE);
- 
-     g_free (prgname);
-     g_free (casename);
--- 
-2.54.0
-
-From 84aaf61fc56735c65eb9c4686aa773cb3b05faa2 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Mon, 29 Jun 2026 12:50:56 +0900
-Subject: [PATCH 1/5] client/wayland: Fix latch key in Latvian(tilde) keymap
-
-"lv(tilde)" keymap has `ISO_Level3_Latch` and there are several issues.
-1. KDE Wayland does not handle `ISO_Level3_Latch` keysym but outputs the
-   tilde even if the system keymap is "lv(tilde)". The previous change
-   0104486 fixes that issue in IBus side.
-2. There is a race when @IBusWaylandIM receives the system keymap from
-   the Wayland compositor and the user keymap from the IBus XKB
-   engine and the user keymap should not be overridden by the system one.
-3. @IBusWaylandIM can handle the compose keys only if `ISO_Level3_Latch`
-   is held pressing at present. But the latch state should be held when
-   the latch key is released but cleared when other keys are pressed.
-4. In case the system keymap is not "lv(tilde)", E.g. "us", the release
-   event of the virtual `ISO_Level3_Latch` key, the Wayland compositor
-   immediately sends to zero modifier state to clear the latch state.
-   So probably @IBusWaylandIM should not send the release event of the
-   latch key.
-5. XKB group ID can be switched by XKB option key likes `grp:toggle`
-   but clicking keyboard icon in KDE panel does not work and maybe
-   it's a bug in KDE compositor.
-6. Fix to clear modifiers with the key release of Shift + Latch key.
-7. Save CapsLock state
-
-Fixes: 0104486
-Fixes: #2869
-Closes: rhbz#2444009
----
- client/wayland/ibuswaylandim.c | 360 ++++++++++++++++++++++++++-------
- 1 file changed, 285 insertions(+), 75 deletions(-)
-
-diff --git a/client/wayland/ibuswaylandim.c b/client/wayland/ibuswaylandim.c
-index d7d12d05..95b330f8 100644
---- a/client/wayland/ibuswaylandim.c
-+++ b/client/wayland/ibuswaylandim.c
-@@ -40,6 +40,9 @@
- #include "virtual-keyboard-unstable-v1-client-protocol.h"
- #include "ibuswaylandim.h"
- 
-+/* keysym & keycode should not be logged for the security issue. */
-+/* #define IBUS_LOG_SHOW_KEYSYM */
-+
- enum {
-     PROP_0 = 0,
-     PROP_BUS,
-@@ -146,6 +149,7 @@ struct _IBusWaylandIMPrivate
-     guint preedit_cursor_pos;
-     guint preedit_mode;
-     IBusModifierType modifiers;
-+    gboolean is_virtual_latch_state;
-     gboolean hiding_preedit_text;
-     IBusInputHints ibus_hints;
-     IBusInputPurpose ibus_purpose;
-@@ -203,10 +207,6 @@ static char _use_sync_mode = 1;
- 
- static guint wayland_im_signals[LAST_SIGNAL] = { 0 };
- 
--static void         input_method_deactivate
--                              (void                               *data,
--                               struct zwp_input_method_union      *input_method,
--                               struct zwp_input_method_context_v1 *context);
- static GObject     *ibus_wayland_im_constructor        (GType          type,
-                                                         guint          n_params,
-                                                         GObjectConstructParam
-@@ -228,6 +228,19 @@ static gboolean     ibus_wayland_im_post_key           (IBusWaylandIM *wlim,
-                                                         xkb_keysym_t   sym,
-                                                         gboolean
-                                                                       filtered);
-+static void         input_method_deactivate
-+                              (void                               *data,
-+                               struct zwp_input_method_union      *input_method,
-+                               struct zwp_input_method_context_v1 *context);
-+static void         input_method_keyboard_modifiers
-+                              (void                               *data,
-+                               struct zwp_keyboard_union          *keyboard,
-+                               uint32_t                            key_serial,
-+                               uint32_t
-+                                                                 mods_depressed,
-+                               uint32_t                            mods_latched,
-+                               uint32_t                            mods_locked,
-+                               uint32_t                            group);
- 
- 
- static char
-@@ -1079,7 +1092,7 @@ ibus_xkb_keymap_update_with_keymap (IBusXkbKeymap     *ibus_keymap,
-         xkb_state_unref (ibus_keymap->state);
-     if (ibus_keymap->keymap)
-         xkb_keymap_unref (ibus_keymap->keymap);
--    ibus_keymap->keymap = keymap;
-+    ibus_keymap->keymap = xkb_keymap_ref (keymap);
-     ibus_keymap->state = state;
- 
-     /* xkb_map_mod_get_index() can return any xkb_mod_index_t value, including
-@@ -1115,6 +1128,7 @@ _bus_global_engine_changed_cb (IBusBus       *bus,
-     IBusWaylandIMPrivate *priv;
-     IBusEngineDesc *desc;
-     struct xkb_keymap *keymap;
-+    gboolean has_keymap = FALSE;
- 
-     g_return_if_fail (IBUS_IS_BUS (bus));
-     g_return_if_fail (IBUS_IS_WAYLAND_IM (wlim));
-@@ -1127,10 +1141,18 @@ _bus_global_engine_changed_cb (IBusBus       *bus,
-      * immediately without checking the Gsettings.
-      */
-     keymap = create_user_xkb_keymap (priv->xkb_context, desc);
--    if (keymap && !ibus_xkb_keymap_update_with_keymap (&priv->key_user,
--                                                       keymap)) {
-+    if (keymap) {
-+        has_keymap = ibus_xkb_keymap_update_with_keymap (&priv->key_user,
-+                                                         keymap);
-         xkb_keymap_unref (keymap);
-     }
-+    if (priv->verbose) {
-+        fprintf (priv->log, "New engine:%s keymap:%s state:%s\n",
-+                 ibus_engine_desc_get_name (desc),
-+                 has_keymap ? "TRUE" : "FALSE",
-+                 priv->key_user.state ? "TRUE" : "FALSE");
-+        fflush (priv->log);
-+    }
-     g_object_unref (desc);
- }
- 
-@@ -1145,6 +1167,7 @@ input_method_keyboard_keymap (void                      *data,
-     IBusWaylandIM *wlim = data;
-     IBusWaylandIMPrivate *priv;
-     struct xkb_keymap *keymap;
-+    gboolean has_keymap = FALSE;
- 
-     if (!IBUS_IS_WAYLAND_IM (wlim)) {
-         close (fd);
-@@ -1194,25 +1217,25 @@ input_method_keyboard_keymap (void                      *data,
-         return;
-     }
-     keymap = create_system_xkb_keymap (priv->xkb_context, format, fd, size);
--    if (keymap &&
--        !ibus_xkb_keymap_update_with_keymap (&priv->key_sys,
--                                             xkb_keymap_ref (keymap))) {
--        xkb_keymap_unref (keymap);
--        g_clear_pointer (&keymap, xkb_keymap_unref);
--    }
--    if (keymap && !priv->key_user.state &&
--        !ibus_xkb_keymap_update_with_keymap (&priv->key_user,
--                                             xkb_keymap_ref (keymap))) {
--        xkb_keymap_unref (keymap);
--        g_clear_pointer (&keymap, xkb_keymap_unref);
--    }
--    if (keymap)
-+    if (keymap) {
-+        has_keymap = ibus_xkb_keymap_update_with_keymap (&priv->key_sys,
-+                                                         keymap);
-+        if (!has_keymap)
-+            g_clear_pointer (&keymap, xkb_keymap_unref);
-+    }
-+    if (has_keymap && !priv->key_user.state) {
-+        has_keymap = ibus_xkb_keymap_update_with_keymap (&priv->key_user,
-+                                                         keymap);
-+        if (!has_keymap)
-+            g_clear_pointer (&keymap, xkb_keymap_unref);
-+    }
-+    if (has_keymap)
-         xkb_keymap_unref (keymap);
-     if (priv->verbose) {
-         fprintf (priv->log, "System keymap format:%u fd:%d size:%u "
-                             "keymap:%s state:%s\n",
-                  format, fd, size,
--                 keymap ? "TRUE" : "FALSE",
-+                 has_keymap ? "TRUE" : "FALSE",
-                  priv->key_sys.state ? "TRUE" : "FALSE");
-         fflush (priv->log);
-     }
-@@ -1253,6 +1276,7 @@ _get_seat_with_name (GPtrArray *seats,
-     return NULL;
- }
- 
-+
- static gboolean
- ibus_wayland_im_post_key (IBusWaylandIM *wlim,
-                           uint32_t       key,
-@@ -1263,8 +1287,13 @@ ibus_wayland_im_post_key (IBusWaylandIM *wlim,
- {
-     IBusWaylandIMPrivate *priv;
-     IBusXkbKeymap *active_key;
-+    xkb_mod_mask_t mods_depressed = 0, new_mods_depressed = 0;
-+    xkb_mod_mask_t mods_locked;
-+    xkb_layout_index_t  group = 0;
-+    xkb_keysym_t system_sym = sym;
-     uint32_t code = key + 8;
-     uint32_t ch;
-+    gboolean clear_virtual_state = FALSE;
- 
-     g_return_val_if_fail (IBUS_IS_WAYLAND_IM (wlim), FALSE);
-     priv = ibus_wayland_im_get_instance_private (wlim);
-@@ -1288,49 +1317,135 @@ ibus_wayland_im_post_key (IBusWaylandIM *wlim,
-         active_key = &priv->key_user;
-     if (!active_key->state)
-         return FALSE;
-+    mods_depressed = xkb_state_serialize_mods (active_key->state,
-+                                               XKB_STATE_DEPRESSED |
-+                                               XKB_STATE_LATCHED);
-+    new_mods_depressed = mods_depressed;
-+    mods_locked = xkb_state_serialize_mods (active_key->state,
-+                                            XKB_STATE_MODS_LOCKED);
-+    /* XKB group layout is configured in the system keymap but not the
-+     * user keymap which always includes a single layout.
-+     */
-+    if (priv->key_sys.state) {
-+        group = xkb_state_serialize_layout (priv->key_sys.state,
-+                                            XKB_STATE_LAYOUT_LOCKED);
-+    }
-     if (!filtered) {
--#if 0
--        /* FIXME: Need to confirm any modifiers should be ignored. */
--        if (!ibus_accelerator_valid (
--                    sym,
--                    modifiers & IBUS_MODIFIER_MASK & ~IBUS_SHIFT_MASK)) {
--            filtered = TRUE;
--        }
--#else
-+        if (priv->key_sys.state)
-+            system_sym = xkb_state_key_get_one_sym (priv->key_sys.state, code);
-         switch (sym) {
--        case IBUS_ISO_Level2_Latch:
--        case IBUS_ISO_Level3_Latch:
--        case IBUS_ISO_Level5_Latch:
-+        case IBUS_KEY_ISO_Level2_Latch:
-             filtered = TRUE;
-             break;
-+        /* Level3_latch is caused by TLDE key in lv(tilde) keymap.
-+         * Level3_Shift is caused by Alt key in lv(tilde) keymap.
-+         */
-+        case IBUS_KEY_ISO_Level3_Latch:
-+        case IBUS_KEY_ISO_Level3_Shift:
-+            if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-+                new_mods_depressed |= active_key->mod5_mask;
-+                if (sym != system_sym)
-+                    priv->is_virtual_latch_state = TRUE;
-+                filtered = TRUE;
-+            }
-+            break;
-+        /* Level5_Latch is caused by Shift+Alt key in de(T3) keymap.
-+         */
-+        case IBUS_KEY_ISO_Level5_Latch:
-+        case IBUS_KEY_ISO_Level5_Shift:
-+            if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-+                new_mods_depressed |= active_key->mod3_mask;
-+                if (sym != system_sym)
-+                    priv->is_virtual_latch_state = TRUE;
-+                filtered = TRUE;
-+            }
-+            break;
-+        case IBUS_KEY_Shift_L:
-+        case IBUS_KEY_Shift_R:
-+            if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
-+                new_mods_depressed |= active_key->shift_mask;
-+            else
-+                new_mods_depressed &= ~active_key->shift_mask;
-+            break;
-         default:;
-         }
-+#ifdef IBUS_LOG_SHOW_KEYSYM
-+        if (priv->verbose) {
-+            fprintf (priv->log, "%s key:%u sym:%x system_sym:%x modifiers:%x "
-+                                "state:%s filtered:%d\n",
-+                     G_STRFUNC,
-+                     key, sym, system_sym, modifiers,
-+                     state ? "press" : "release",
-+                     filtered);
-+            fflush (priv->log);
-+        }
- #endif
-     }
--    /* In case `use_sys_keymap` is %TRUE, IBus does not commit ASCII chars
--     * but forwards the key events to the focused application here.
--     * Because some applications treat the printable keys as control keys,
--     * E.g. game apps "hjkl" use the cursor move like VI mode.
--     * Unfortunately the Wayland input-method protocol does not provide
--     * the fallback logic after apps handle the key events like GTK3/2
--     * IM modules. But The input-method always should handles key events
--     * prior to apps.
--     */
--    if (!filtered && (state != WL_KEYBOARD_KEY_STATE_RELEASED) &&
--        !priv->use_sys_keymap) {
--        ch = xkb_state_key_get_utf32 (active_key->state, code);
--        if (!(modifiers & IBUS_MODIFIER_MASK & ~IBUS_SHIFT_MASK) &&
--            ch && ch != '\n' && ch != '\b' && ch != '\r' && ch != '\t' &&
--            ch != '\033' && ch != '\x7f') {
--            gchar buff[8] = { 0, };
--            buff[g_unichar_to_utf8 (ch, buff)] = '\0';
--            ibus_wayland_im_commit_text (wlim, buff);
--            filtered = TRUE;
-+    if (state != WL_KEYBOARD_KEY_STATE_RELEASED) {
-+        ch = ibus_keyval_to_unicode (sym);
-+        if (ch == 0 || g_unichar_iscntrl (ch))
-+            ch = xkb_state_key_get_utf32 (active_key->state, code);
-+/* No text with Control & Alt & Super keys */
-+#ifndef GDK_WINDOWING_QUARTZ
-+#  define _IBUS_NO_TEXT_INPUT_MOD_MASK (\
-+    IBUS_CONTROL_MASK | IBUS_MOD1_MASK | IBUS_MOD4_MASK)
-+#else
-+#  define _IBUS_NO_TEXT_INPUT_MOD_MASK (\
-+    IBUS_CONTROL_MASK | IBUS_MOD2_MASK | IBUS_MOD4_MASK)
-+#endif
-+        if ((!filtered && !(modifiers & _IBUS_NO_TEXT_INPUT_MOD_MASK) &&
-+             !g_unichar_iscntrl (ch)) || filtered) {
-+        /* In case `use_sys_keymap` is %TRUE, IBus does not commit ASCII chars
-+         * but forwards the key events to the focused application here.
-+         * Because some applications treat the printable keys as control keys,
-+         * E.g. game apps "hjkl" use the cursor move like VI mode.
-+         * Unfortunately the Wayland input-method protocol does not provide
-+         * the fallback logic after apps handle the key events like GTK3/2
-+         * IM modules. But the input-method always should handle key events
-+         * prior to apps.
-+         */
-+            if (!filtered && !priv->use_sys_keymap) {
-+                gchar buff[8] = { 0, };
-+                g_unichar_to_utf8 (ch, buff);
-+                ibus_wayland_im_commit_text (wlim, buff);
-+                filtered = TRUE;
-+            }
-+            /* If `filtered` is %TRUE, the keysym can be eaten for the compose
-+             * preedit by IBus XKB engine. E.g. AltGr-Shift-V key produces
-+             * `Level3_Shift' and `Greek_OMEGA` keysym with "us(symbolic)"
-+             * keymap. However if you configure multiple keymaps, AltGr-Shift
-+             * may produce the keymap switch although AltGr-Shift-V produces
-+             * `Greek_OMEGA`.
-+             * I'm not clarified with "level3(ralt_switch)" in us XKB keymaps.
-+             */
-+            if (modifiers & IBUS_MOD3_MASK) {
-+                new_mods_depressed &= ~active_key->mod3_mask;
-+                clear_virtual_state = TRUE;
-+            }
-+            if (modifiers & IBUS_MOD5_MASK) {
-+                new_mods_depressed &= ~active_key->mod5_mask;
-+                clear_virtual_state = TRUE;
-+            }
-         }
-+#undef _IBUS_NO_TEXT_INPUT_MOD_MASK
-+    }
-+    if (priv->is_virtual_latch_state) {
-+        if (new_mods_depressed != mods_depressed) {
-+            input_method_keyboard_modifiers (wlim, NULL, 0,
-+                                             new_mods_depressed,
-+                                             0,
-+                                             mods_locked,
-+                                             group);
-+        }
-+        if (clear_virtual_state)
-+            priv->is_virtual_latch_state = FALSE;
-+    }
-+    if (!priv->is_virtual_latch_state ||
-+        (state != WL_KEYBOARD_KEY_STATE_RELEASED)) {
-+        xkb_state_update_key (active_key->state, code,
-+                              (state == WL_KEYBOARD_KEY_STATE_RELEASED)
-+                              ? XKB_KEY_UP : XKB_KEY_DOWN);
-     }
--    xkb_state_update_key (active_key->state, code,
--                          (state == WL_KEYBOARD_KEY_STATE_RELEASED)
--                          ? XKB_KEY_UP : XKB_KEY_DOWN);
-     return filtered;
- }
- 
-@@ -1777,12 +1892,36 @@ input_method_keyboard_key (void                      *data,
-     /* xkb_key_get_syms() does not return the capital syms with Shift key. */
-     if (priv->key_sys.state)
-         event.sym = xkb_state_key_get_one_sym (priv->key_sys.state, code);
--    if (event.sym != IBUS_KEY_Multi_key && priv->key_user.state)
--        event.sym = xkb_state_key_get_one_sym (priv->key_user.state, code);
-+    switch (event.sym) {
-+    case IBUS_KEY_Multi_key:
-+    case IBUS_KEY_ISO_Next_Group:
-+        break;
-+    default:
-+        if (priv->key_user.state)
-+            event.sym = xkb_state_key_get_one_sym (priv->key_user.state, code);
-+    }
-     event.modifiers = priv->modifiers;
-     if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
-         event.modifiers |= IBUS_RELEASE_MASK;
-     event.wlim = wlim;
-+#ifdef IBUS_LOG_SHOW_KEYSYM
-+    if (priv->verbose) {
-+        fprintf (priv->log, "%s serial:%u time:%u key:%u "
-+                            "sym:%x system_user:%x system_sym:%x "
-+                            "modifiers:%x state:%s\n",
-+                 G_STRFUNC,
-+                 key_serial, time, key,
-+                 event.sym,
-+                 priv->key_user.state ?
-+                     xkb_state_key_get_one_sym (priv->key_user.state, code) :
-+                     0,
-+                 priv->key_sys.state ?
-+                     xkb_state_key_get_one_sym (priv->key_sys.state, code) :
-+                     0,
-+                 event.modifiers, state ? "press" : "release");
-+        fflush (priv->log);
-+    }
-+#endif
- 
-     key_event_check_repeat (wlim, &event);
-     switch (_use_sync_mode) {
-@@ -1796,6 +1935,29 @@ input_method_keyboard_key (void                      *data,
- }
- 
- 
-+/**
-+ * input_method_keyboard_modifiers:
-+ *
-+ * This is a common API of input_method_keyboard_modifiers_v1() and
-+ * input_method_keyboard_modifiers_v2().
-+ * If you configure multiple XKB layouts in the system with
-+ * /etc/vconsole.conf file, you can switch the active layout with
-+ * the XKB options and @group is changed with the shortcut key like
-+ * "grp:lalt_lshift_toggle" but If you click the keyboard icon in
-+ * Plasma KDE and change the active layout with GUI, @group is not
-+ * changed and I assume it's a bug [1].
-+ * Currently there are two cases of the combinations of the IBus keymap and
-+ * the system keymap supported by IBus:
-+ * 1. Always Same keymaps
-+ *    E.g. IBus keymap is "lv(tilde)" and system one is "lv(tilde)"
-+ * 2. System keymap is "US" and switch IBus keymaps with Super-space key
-+ *    E.g. IBus keymap is "lv(tilde)" and system one is "us"
-+ * So you should use both XKB option keys and IBus shortcutkeys to switch the
-+ * keymaps to change both XKB keymaps and IBus keymaps but you should not
-+ * click the keyboard icon in KDE.
-+ *
-+ * [1] https://bugs.kde.org/show_bug.cgi?id=518371
-+ */
- static void
- input_method_keyboard_modifiers (void                      *data,
-                                  struct zwp_keyboard_union *keyboard,
-@@ -1816,27 +1978,59 @@ input_method_keyboard_modifiers (void                      *data,
-         active_key = &priv->key_sys;
-     else
-         active_key = &priv->key_user;
--    if (priv->key_user.state) {
--        xkb_state_update_mask (priv->key_user.state, mods_depressed,
--                               mods_latched, mods_locked, 0, 0, group);
--    }
--    /* Pressing XKB group key likes Alt_R with grp:toggle calls
--     * input_method_keyboard_modifiers() with the updated `group`
--     * and need to update priv->key_sys.state to switch the XKB group
--     * in the system keymap.
--     *
--     * XKB group key can switch `group` but clicking the keyboard icon
--     * of KDE does not change `group` at present. Maybe a bug in the
--     * KDE Wayland compositor.
-+    /* Do not reset Latch modifiers by system in case the system keymap
-+     * has no the Latch key.
-+     * In case the user keymap is "lv(tilde)" and the system one is "us",
-+     * input_method_keyboard_modifiers() clears state of Level3_Latch key
-+     * immediately after the Level3_Latch key is released because the "us"
-+     * keymap does not have the latch keys.
-+     * The behavior is different in case both user and system keymaps are
-+     * "lv(tilde)".
-+     * So `is_virtual_latch_state` keeps the virtual state of the latch keys
-+     * not to override the state of the "us" keymap.
-      */
--    if (priv->key_sys.state) {
--        xkb_state_update_mask (priv->key_sys.state, mods_depressed,
--                               mods_latched, mods_locked, 0, 0, group);
-+    if (!priv->is_virtual_latch_state || key_serial == 0) {
-+        if (priv->key_user.state) {
-+            xkb_state_update_mask (priv->key_user.state, mods_depressed,
-+                                   mods_latched, mods_locked, 0, 0, group);
-+        }
-+        /* Pressing XKB group key likes Alt_R with grp:toggle calls
-+         * input_method_keyboard_modifiers() with the updated `group`
-+         * and need to update priv->key_sys.state to switch the XKB group
-+         * in the system keymap.
-+         *
-+         * XKB group key can switch `group` but clicking the keyboard icon
-+         * of KDE does not change `group` at present. Maybe a bug in the
-+         * KDE Wayland compositor.
-+         */
-+        if (priv->key_sys.state) {
-+            xkb_state_update_mask (priv->key_sys.state, mods_depressed,
-+                                   mods_latched, mods_locked, 0, 0, group);
-+        }
-     }
-     if (active_key->state) {
-+        /* CapsLock needs XKB_STATE_MODS_LOCKED */
-         mask = xkb_state_serialize_mods (active_key->state,
-                                          XKB_STATE_DEPRESSED |
--                                         XKB_STATE_LATCHED);
-+                                         XKB_STATE_LATCHED |
-+                                         XKB_STATE_MODS_LOCKED);
-+    }
-+    if (priv->verbose) {
-+        struct xkb_state *state = active_key->state;
-+        fprintf (priv->log, "Update modifiers serial:%u depress:%X latch:%X "
-+                             "lock:%X group:%X orig_depre:%X orig_latch:%X "
-+                             "orig_lock:%X\n",
-+                 key_serial, mods_depressed, mods_latched, mods_locked, group,
-+                 state ?
-+                     xkb_state_serialize_mods (state, XKB_STATE_DEPRESSED) :
-+                     0xFFFFFFFF,
-+                 state ?
-+                     xkb_state_serialize_mods (state, XKB_STATE_LATCHED) :
-+                     0xFFFFFFFF,
-+                 state ?
-+                     xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED) :
-+                     0xFFFFFFFF);
-+        fflush (priv->log);
-     }
- 
-     priv->modifiers = 0;
-@@ -1863,6 +2057,9 @@ input_method_keyboard_modifiers (void                      *data,
-     if (mask & active_key->meta_mask)
-         priv->modifiers |= IBUS_META_MASK;
- 
-+    if (!key_serial)
-+        return;
-+
-     switch (priv->version) {
-     case INPUT_METHOD_V1:
-         zwp_input_method_context_v1_modifiers (priv->context, key_serial,
-@@ -2834,6 +3031,7 @@ ibus_wayland_im_constructor (GType                  type,
-     IBusWaylandSeat *seat = NULL;
-     IBusEngineDesc *desc;
-     struct xkb_keymap *keymap = NULL;
-+    gboolean has_keymap = FALSE;
- 
-     object = G_OBJECT_CLASS (ibus_wayland_im_parent_class)->constructor (
-             type, n_params, params);
-@@ -2882,9 +3080,21 @@ ibus_wayland_im_constructor (GType                  type,
-     desc = ibus_bus_get_global_engine (priv->ibusbus);
-     if (desc)
-         keymap = create_user_xkb_keymap (priv->xkb_context, desc);
--    if (keymap && !ibus_xkb_keymap_update_with_keymap (&priv->key_user,
--                                                       keymap)) {
--        g_clear_pointer (&keymap, xkb_keymap_unref);
-+    if (keymap) {
-+        has_keymap = ibus_xkb_keymap_update_with_keymap (&priv->key_user,
-+                                                         keymap);
-+        xkb_keymap_unref (keymap);
-+    }
-+    if (priv->verbose) {
-+        if (!desc) {
-+            fprintf (priv->log, "Constructor has no global engine\n");
-+        } else {
-+            fprintf (priv->log, "Constructor engine %s keymap:%s state:%s\n",
-+                     ibus_engine_desc_get_name (desc),
-+                     has_keymap ? "TRUE" : "FALSE",
-+                     priv->key_user.state ? "TRUE" : "FALSE");
-+        }
-+        fflush (priv->log);
-     }
-     ibus_bus_set_watch_ibus_signal (priv->ibusbus, TRUE);
-     g_signal_connect (priv->ibusbus, "global-engine-changed",
--- 
-2.54.0
-
-From df8230ff90ec3aafffe10af769ad66aa948ac349 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Mon, 29 Jun 2026 12:51:07 +0900
-Subject: [PATCH 2/5] client/wayland: Refactor ibus_wayland_im_post_key()
-
-Separate 3 functions.
-
-Fixes: #2869
-Closes: rhbz#2444009
----
- client/wayland/ibuswaylandim.c | 377 +++++++++++++++++++++------------
- 1 file changed, 246 insertions(+), 131 deletions(-)
-
-diff --git a/client/wayland/ibuswaylandim.c b/client/wayland/ibuswaylandim.c
-index 95b330f8..b16ff521 100644
---- a/client/wayland/ibuswaylandim.c
-+++ b/client/wayland/ibuswaylandim.c
-@@ -367,6 +367,81 @@ ibus_wayland_im_commit_text (IBusWaylandIM *wlim,
- }
- 
- 
-+static gboolean
-+ibus_wayland_im_commit_key_event (IBusWaylandIM  *wlim,
-+                                  uint32_t        key,
-+                                  uint32_t        modifiers,
-+                                  uint32_t        state,
-+                                  xkb_keysym_t    sym,
-+                                  IBusXkbKeymap  *active_key,
-+                                  gboolean        filtered,
-+                                  xkb_mod_mask_t *new_mods_depressed,
-+                                  gboolean       *clear_virtual_state)
-+{
-+    IBusWaylandIMPrivate *priv;
-+    uint32_t code = key + 8;
-+    uint32_t ch;
-+
-+    g_return_val_if_fail (IBUS_IS_WAYLAND_IM (wlim), filtered);
-+    priv = ibus_wayland_im_get_instance_private (wlim);
-+
-+    if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
-+        return filtered;
-+
-+    ch = ibus_keyval_to_unicode (sym);
-+    if (ch == 0 || g_unichar_iscntrl (ch))
-+        ch = xkb_state_key_get_utf32 (active_key->state, code);
-+
-+/* No text with Control & Alt & Super keys */
-+#ifndef GDK_WINDOWING_QUARTZ
-+#  define _IBUS_NO_TEXT_INPUT_MOD_MASK (\
-+    IBUS_CONTROL_MASK | IBUS_MOD1_MASK | IBUS_MOD4_MASK)
-+#else
-+#  define _IBUS_NO_TEXT_INPUT_MOD_MASK (\
-+    IBUS_CONTROL_MASK | IBUS_MOD2_MASK | IBUS_MOD4_MASK)
-+#endif
-+    if ((!filtered && !(modifiers & _IBUS_NO_TEXT_INPUT_MOD_MASK) &&
-+         !g_unichar_iscntrl (ch)) || filtered) {
-+        /* In case `use_sys_keymap` is %TRUE, IBus does not commit ASCII chars
-+         * but forwards the key events to the focused application here.
-+         * Because some applications treat the printable keys as control keys,
-+         * E.g. game apps "hjkl" use the cursor move like VI mode.
-+         * Unfortunately the Wayland input-method protocol does not provide
-+         * the fallback logic after apps handle the key events like GTK3/2
-+         * IM modules. But the input-method always should handle key events
-+         * prior to apps.
-+         */
-+        if (!filtered && !priv->use_sys_keymap) {
-+            gchar buff[8] = { 0, };
-+            g_unichar_to_utf8 (ch, buff);
-+            ibus_wayland_im_commit_text (wlim, buff);
-+            filtered = TRUE;
-+        }
-+        /* If `filtered` is %TRUE, the keysym can be eaten for the compose
-+         * preedit by IBus XKB engine. E.g. AltGr-Shift-V key produces
-+         * `Level3_Shift' and `Greek_OMEGA` keysym with "us(symbolic)" keymap.
-+         * However if you configure multiple keymaps, AltGr-Shift may produce
-+         * the keymap switch although AltGr-Shift-V produces `Greek_OMEGA`.
-+         * I'm not clarified with "level3(ralt_switch)" in us XKB keymaps.
-+         */
-+        if (modifiers & IBUS_MOD3_MASK) {
-+            if (new_mods_depressed)
-+                *new_mods_depressed &= ~active_key->mod3_mask;
-+            if (clear_virtual_state)
-+                *clear_virtual_state = TRUE;
-+        }
-+        if (modifiers & IBUS_MOD5_MASK) {
-+            if (new_mods_depressed)
-+                *new_mods_depressed &= ~active_key->mod5_mask;
-+            if (clear_virtual_state)
-+                *clear_virtual_state = TRUE;
-+        }
-+    }
-+#undef _IBUS_NO_TEXT_INPUT_MOD_MASK
-+    return filtered;
-+}
-+
-+
- static void
- ibus_wayland_im_key (IBusWaylandIM *wlim,
-                      uint32_t       key_serial,
-@@ -431,6 +506,152 @@ ibus_wayland_im_keysym (IBusWaylandIM *wlim,
- }
- 
- 
-+/**
-+ * ibus_wayland_im_update_virtual_depressed:
-+ *
-+ * If the IBus keymap is different from the compositor keymap,
-+ * IBus needs to maintain the modifiers state by itself to call
-+ * xkb_state_update_mask(), E.g. IBus keymap is "lv(tilde)" and the system
-+ * one is "us", because input_method_keyboard_modifiers()
-+ * is not called by the Wayland compositor in that case.
-+ * So this API updates @mods_depressed with ISO level3 and level5
-+ * latch and shift states, and send it to
-+ * ibus_wayland_im_update_virtual_xkb_state().
-+ */
-+static gboolean
-+ibus_wayland_im_update_virtual_depressed (IBusWaylandIM  *wlim,
-+                                          uint32_t        key,
-+                                          uint32_t        modifiers,
-+                                          uint32_t        state,
-+                                          xkb_keysym_t    sym,
-+                                          IBusXkbKeymap  *active_key,
-+                                          gboolean        filtered,
-+                                          xkb_mod_mask_t *mods_depressed)
-+{
-+    IBusWaylandIMPrivate *priv;
-+    uint32_t code = key + 8;
-+    xkb_mod_mask_t new_mods_depressed;
-+    xkb_keysym_t system_sym = sym;
-+
-+    if (filtered)
-+        return filtered;
-+
-+    g_assert (IBUS_IS_WAYLAND_IM (wlim));
-+    g_assert (active_key);
-+    g_assert (mods_depressed);
-+
-+    priv = ibus_wayland_im_get_instance_private (wlim);
-+    new_mods_depressed = *mods_depressed;
-+
-+    if ((modifiers & ~IBUS_RELEASE_MASK ) != new_mods_depressed) {
-+        g_warning ("IBus modifiers %X is different from XKB depressed %X",
-+                   modifiers, new_mods_depressed);
-+    }
-+    if (priv->key_sys.state)
-+        system_sym = xkb_state_key_get_one_sym (priv->key_sys.state, code);
-+    switch (sym) {
-+    case IBUS_KEY_ISO_Level2_Latch:
-+        filtered = TRUE;
-+        break;
-+    /* Level3_latch is caused by TLDE key in lv(tilde) keymap.
-+     * Level3_Shift is caused by Alt key in lv(tilde) keymap.
-+     */
-+    case IBUS_KEY_ISO_Level3_Latch:
-+    case IBUS_KEY_ISO_Level3_Shift:
-+        if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-+            new_mods_depressed |= active_key->mod5_mask;
-+            if (sym != system_sym)
-+                priv->is_virtual_latch_state = TRUE;
-+            filtered = TRUE;
-+        }
-+        break;
-+    /* Level5_Latch is caused by Shift+Alt key in de(T3) keymap.
-+     */
-+    case IBUS_KEY_ISO_Level5_Latch:
-+    case IBUS_KEY_ISO_Level5_Shift:
-+        if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-+            new_mods_depressed |= active_key->mod3_mask;
-+            if (sym != system_sym)
-+                priv->is_virtual_latch_state = TRUE;
-+            filtered = TRUE;
-+        }
-+        break;
-+    case IBUS_KEY_Shift_L:
-+    case IBUS_KEY_Shift_R:
-+        if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
-+            new_mods_depressed |= active_key->shift_mask;
-+        else
-+            new_mods_depressed &= ~active_key->shift_mask;
-+        break;
-+    default:;
-+    }
-+#ifdef IBUS_LOG_SHOW_KEYSYM
-+    if (priv->verbose) {
-+        fprintf (priv->log, "%s key:%u sym:%x system_sym:%x modifiers:%x "
-+                            "state:%s filtered:%d\n",
-+                 G_STRFUNC,
-+                 key, sym, system_sym, modifiers, state ? "press" : "release",
-+                 filtered);
-+        fflush (priv->log);
-+    }
-+#endif
-+    *mods_depressed = new_mods_depressed;
-+    return filtered;
-+}
-+
-+
-+/**
-+ * ibus_wayland_im_update_virtual_xkb_state:
-+ *
-+ * Update virtual IBus xkb_state by KeyPress and KeyRelease.
-+ */
-+static void
-+ibus_wayland_im_update_virtual_xkb_state (IBusWaylandIM *wlim,
-+                                          uint32_t       key,
-+                                          uint32_t       state,
-+                                          IBusXkbKeymap *active_key,
-+                                          xkb_mod_mask_t mods_depressed,
-+                                          xkb_mod_mask_t new_mods_depressed,
-+                                          gboolean       clear_virtual_state)
-+{
-+    IBusWaylandIMPrivate *priv;
-+    uint32_t code = key + 8;
-+    xkb_mod_mask_t mods_locked;
-+    xkb_layout_index_t  group = 0;
-+
-+    g_assert (IBUS_IS_WAYLAND_IM (wlim));
-+
-+    priv = ibus_wayland_im_get_instance_private (wlim);
-+    mods_locked = xkb_state_serialize_mods (active_key->state,
-+                                            XKB_STATE_MODS_LOCKED);
-+    /* XKB group layout is configured in the system keymap but not the
-+     * user keymap which always includes a single layout.
-+     */
-+    if (priv->key_sys.state) {
-+        group = xkb_state_serialize_layout (priv->key_sys.state,
-+                                            XKB_STATE_LAYOUT_LOCKED);
-+    }
-+
-+    if (priv->is_virtual_latch_state) {
-+        if (new_mods_depressed != mods_depressed) {
-+            input_method_keyboard_modifiers (wlim, NULL, 0,
-+                                             new_mods_depressed,
-+                                             0,
-+                                             mods_locked,
-+                                             group);
-+        }
-+        if (clear_virtual_state)
-+            priv->is_virtual_latch_state = FALSE;
-+    }
-+    if (!priv->is_virtual_latch_state ||
-+        (state != WL_KEYBOARD_KEY_STATE_RELEASED)) {
-+        xkb_state_update_key (active_key->state, code,
-+                              (state == WL_KEYBOARD_KEY_STATE_RELEASED)
-+                              ? XKB_KEY_UP : XKB_KEY_DOWN);
-+    }
-+}
-+
-+
- static void
- _context_commit_text_cb (IBusInputContext *context,
-                          IBusText         *text,
-@@ -1287,12 +1508,7 @@ ibus_wayland_im_post_key (IBusWaylandIM *wlim,
- {
-     IBusWaylandIMPrivate *priv;
-     IBusXkbKeymap *active_key;
--    xkb_mod_mask_t mods_depressed = 0, new_mods_depressed = 0;
--    xkb_mod_mask_t mods_locked;
--    xkb_layout_index_t  group = 0;
--    xkb_keysym_t system_sym = sym;
--    uint32_t code = key + 8;
--    uint32_t ch;
-+    xkb_mod_mask_t mods_depressed, new_mods_depressed;
-     gboolean clear_virtual_state = FALSE;
- 
-     g_return_val_if_fail (IBUS_IS_WAYLAND_IM (wlim), FALSE);
-@@ -1321,131 +1537,30 @@ ibus_wayland_im_post_key (IBusWaylandIM *wlim,
-                                                XKB_STATE_DEPRESSED |
-                                                XKB_STATE_LATCHED);
-     new_mods_depressed = mods_depressed;
--    mods_locked = xkb_state_serialize_mods (active_key->state,
--                                            XKB_STATE_MODS_LOCKED);
--    /* XKB group layout is configured in the system keymap but not the
--     * user keymap which always includes a single layout.
--     */
--    if (priv->key_sys.state) {
--        group = xkb_state_serialize_layout (priv->key_sys.state,
--                                            XKB_STATE_LAYOUT_LOCKED);
--    }
--    if (!filtered) {
--        if (priv->key_sys.state)
--            system_sym = xkb_state_key_get_one_sym (priv->key_sys.state, code);
--        switch (sym) {
--        case IBUS_KEY_ISO_Level2_Latch:
--            filtered = TRUE;
--            break;
--        /* Level3_latch is caused by TLDE key in lv(tilde) keymap.
--         * Level3_Shift is caused by Alt key in lv(tilde) keymap.
--         */
--        case IBUS_KEY_ISO_Level3_Latch:
--        case IBUS_KEY_ISO_Level3_Shift:
--            if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
--                new_mods_depressed |= active_key->mod5_mask;
--                if (sym != system_sym)
--                    priv->is_virtual_latch_state = TRUE;
--                filtered = TRUE;
--            }
--            break;
--        /* Level5_Latch is caused by Shift+Alt key in de(T3) keymap.
--         */
--        case IBUS_KEY_ISO_Level5_Latch:
--        case IBUS_KEY_ISO_Level5_Shift:
--            if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
--                new_mods_depressed |= active_key->mod3_mask;
--                if (sym != system_sym)
--                    priv->is_virtual_latch_state = TRUE;
--                filtered = TRUE;
--            }
--            break;
--        case IBUS_KEY_Shift_L:
--        case IBUS_KEY_Shift_R:
--            if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
--                new_mods_depressed |= active_key->shift_mask;
--            else
--                new_mods_depressed &= ~active_key->shift_mask;
--            break;
--        default:;
--        }
--#ifdef IBUS_LOG_SHOW_KEYSYM
--        if (priv->verbose) {
--            fprintf (priv->log, "%s key:%u sym:%x system_sym:%x modifiers:%x "
--                                "state:%s filtered:%d\n",
--                     G_STRFUNC,
--                     key, sym, system_sym, modifiers,
--                     state ? "press" : "release",
--                     filtered);
--            fflush (priv->log);
--        }
--#endif
--    }
--    if (state != WL_KEYBOARD_KEY_STATE_RELEASED) {
--        ch = ibus_keyval_to_unicode (sym);
--        if (ch == 0 || g_unichar_iscntrl (ch))
--            ch = xkb_state_key_get_utf32 (active_key->state, code);
--/* No text with Control & Alt & Super keys */
--#ifndef GDK_WINDOWING_QUARTZ
--#  define _IBUS_NO_TEXT_INPUT_MOD_MASK (\
--    IBUS_CONTROL_MASK | IBUS_MOD1_MASK | IBUS_MOD4_MASK)
--#else
--#  define _IBUS_NO_TEXT_INPUT_MOD_MASK (\
--    IBUS_CONTROL_MASK | IBUS_MOD2_MASK | IBUS_MOD4_MASK)
--#endif
--        if ((!filtered && !(modifiers & _IBUS_NO_TEXT_INPUT_MOD_MASK) &&
--             !g_unichar_iscntrl (ch)) || filtered) {
--        /* In case `use_sys_keymap` is %TRUE, IBus does not commit ASCII chars
--         * but forwards the key events to the focused application here.
--         * Because some applications treat the printable keys as control keys,
--         * E.g. game apps "hjkl" use the cursor move like VI mode.
--         * Unfortunately the Wayland input-method protocol does not provide
--         * the fallback logic after apps handle the key events like GTK3/2
--         * IM modules. But the input-method always should handle key events
--         * prior to apps.
--         */
--            if (!filtered && !priv->use_sys_keymap) {
--                gchar buff[8] = { 0, };
--                g_unichar_to_utf8 (ch, buff);
--                ibus_wayland_im_commit_text (wlim, buff);
--                filtered = TRUE;
--            }
--            /* If `filtered` is %TRUE, the keysym can be eaten for the compose
--             * preedit by IBus XKB engine. E.g. AltGr-Shift-V key produces
--             * `Level3_Shift' and `Greek_OMEGA` keysym with "us(symbolic)"
--             * keymap. However if you configure multiple keymaps, AltGr-Shift
--             * may produce the keymap switch although AltGr-Shift-V produces
--             * `Greek_OMEGA`.
--             * I'm not clarified with "level3(ralt_switch)" in us XKB keymaps.
--             */
--            if (modifiers & IBUS_MOD3_MASK) {
--                new_mods_depressed &= ~active_key->mod3_mask;
--                clear_virtual_state = TRUE;
--            }
--            if (modifiers & IBUS_MOD5_MASK) {
--                new_mods_depressed &= ~active_key->mod5_mask;
--                clear_virtual_state = TRUE;
--            }
--        }
--#undef _IBUS_NO_TEXT_INPUT_MOD_MASK
--    }
--    if (priv->is_virtual_latch_state) {
--        if (new_mods_depressed != mods_depressed) {
--            input_method_keyboard_modifiers (wlim, NULL, 0,
--                                             new_mods_depressed,
--                                             0,
--                                             mods_locked,
--                                             group);
--        }
--        if (clear_virtual_state)
--            priv->is_virtual_latch_state = FALSE;
--    }
--    if (!priv->is_virtual_latch_state ||
--        (state != WL_KEYBOARD_KEY_STATE_RELEASED)) {
--        xkb_state_update_key (active_key->state, code,
--                              (state == WL_KEYBOARD_KEY_STATE_RELEASED)
--                              ? XKB_KEY_UP : XKB_KEY_DOWN);
--    }
-+    filtered = ibus_wayland_im_update_virtual_depressed (wlim,
-+                                                         key,
-+                                                         modifiers,
-+                                                         state,
-+                                                         sym,
-+                                                         active_key,
-+                                                         filtered,
-+                                                         &new_mods_depressed);
-+    filtered = ibus_wayland_im_commit_key_event (wlim,
-+                                                 key,
-+                                                 modifiers,
-+                                                 state,
-+                                                 sym,
-+                                                 active_key,
-+                                                 filtered,
-+                                                 &new_mods_depressed,
-+                                                 &clear_virtual_state);
-+    ibus_wayland_im_update_virtual_xkb_state (wlim,
-+                                              key,
-+                                              state,
-+                                              active_key,
-+                                              mods_depressed,
-+                                              new_mods_depressed,
-+                                              clear_virtual_state);
-     return filtered;
- }
- 
--- 
-2.54.0
-
-From 056b3e59cc91bdd97efc8b28860bf21e36416afd Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Wed, 17 Jun 2026 19:51:08 +0900
-Subject: [PATCH 3/5] client/wayland: Refactor ISO_Level[3|5]_Shift state
-
-The states of ISO Shift keys should be cleared when the key is released
-against ISO Latch keys. E.g. "RALT" key in "lv(tilde)" keymap.
-
-The state of the "RALT" key is strange in "de(T3)" keymap, i.e.
-"ISO_Level3_Shift" keysym for the keypress and ISO_Level5_Latch keysm
-for keyrelease and IBus could not get the correct dead keys and
-clear the state. Now the "is_pressed_mod5" flag checks if the
-key is pressed and add a workaround.
-
-Fixes: #2869
-Closes: rhbz#2444009
----
- client/wayland/ibuswaylandim.c | 139 ++++++++++++++++++++++++++++++---
- 1 file changed, 127 insertions(+), 12 deletions(-)
-
-diff --git a/client/wayland/ibuswaylandim.c b/client/wayland/ibuswaylandim.c
-index b16ff521..97e3ce38 100644
---- a/client/wayland/ibuswaylandim.c
-+++ b/client/wayland/ibuswaylandim.c
-@@ -64,6 +64,13 @@ typedef enum
-     INPUT_METHOD_V2,
- } IMProtocolVersion;
- 
-+typedef enum {
-+    IBUS_KEY_ISO_LEVEL_INVALID,
-+    IBUS_KEY_ISO_LEVEL_2,
-+    IBUS_KEY_ISO_LEVEL_3,
-+    IBUS_KEY_ISO_LEVEL_5
-+} IBusKeyIsoLevelValue;
-+
- struct zwp_input_method_context_union {
-     union {
-         struct zwp_input_method_context_v1 *context_v1;
-@@ -163,6 +170,8 @@ struct _IBusWaylandIMPrivate
- 
-     IBusXkbKeymap key_user;
-     IBusXkbKeymap key_sys;
-+    gboolean is_pressed_mod3;
-+    gboolean is_pressed_mod5;
- 
-     uint32_t im_serial;
-     int32_t repeat_rate;
-@@ -341,6 +350,28 @@ ibus_wayland_source_new (struct wl_display *display)
- }
- 
- 
-+static void
-+ibus_wayland_im_reset_modifiers (IBusWaylandIM *wlim)
-+{
-+    IBusWaylandIMPrivate *priv;
-+    xkb_layout_index_t  group = 0;
-+
-+    g_assert (IBUS_IS_WAYLAND_IM (wlim));
-+
-+    priv = ibus_wayland_im_get_instance_private (wlim);
-+    priv->is_virtual_latch_state = FALSE;
-+    priv->is_pressed_mod3 = FALSE;
-+    priv->is_pressed_mod5 = FALSE;
-+    if (priv->key_user.state && priv->key_sys.state) {
-+        group = xkb_state_serialize_layout (priv->key_sys.state,
-+                                            XKB_STATE_LAYOUT_LOCKED);
-+        input_method_keyboard_modifiers (wlim, NULL, 0, 0, 0, 0, group);
-+    } else {
-+        priv->modifiers = 0;
-+    }
-+}
-+
-+
- static void
- ibus_wayland_im_commit_text (IBusWaylandIM *wlim,
-                              const char    *str)
-@@ -526,7 +557,8 @@ ibus_wayland_im_update_virtual_depressed (IBusWaylandIM  *wlim,
-                                           xkb_keysym_t    sym,
-                                           IBusXkbKeymap  *active_key,
-                                           gboolean        filtered,
--                                          xkb_mod_mask_t *mods_depressed)
-+                                          xkb_mod_mask_t *mods_depressed,
-+                                          gboolean       *clear_virtual_state)
- {
-     IBusWaylandIMPrivate *priv;
-     uint32_t code = key + 8;
-@@ -539,6 +571,7 @@ ibus_wayland_im_update_virtual_depressed (IBusWaylandIM  *wlim,
-     g_assert (IBUS_IS_WAYLAND_IM (wlim));
-     g_assert (active_key);
-     g_assert (mods_depressed);
-+    g_assert (clear_virtual_state);
- 
-     priv = ibus_wayland_im_get_instance_private (wlim);
-     new_mods_depressed = *mods_depressed;
-@@ -555,25 +588,87 @@ ibus_wayland_im_update_virtual_depressed (IBusWaylandIM  *wlim,
-         break;
-     /* Level3_latch is caused by TLDE key in lv(tilde) keymap.
-      * Level3_Shift is caused by Alt key in lv(tilde) keymap.
-+     * Level5_Latch is caused by Shift+Alt key in de(T3) keymap.
-      */
-     case IBUS_KEY_ISO_Level3_Latch:
-     case IBUS_KEY_ISO_Level3_Shift:
--        if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
--            new_mods_depressed |= active_key->mod5_mask;
--            if (sym != system_sym)
--                priv->is_virtual_latch_state = TRUE;
--            filtered = TRUE;
--        }
--        break;
--    /* Level5_Latch is caused by Shift+Alt key in de(T3) keymap.
--     */
-     case IBUS_KEY_ISO_Level5_Latch:
-     case IBUS_KEY_ISO_Level5_Shift:
-         if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
--            new_mods_depressed |= active_key->mod3_mask;
-+            switch (sym) {
-+            case IBUS_KEY_ISO_Level3_Latch:
-+            case IBUS_KEY_ISO_Level3_Shift:
-+                priv->is_pressed_mod5 = TRUE;
-+                new_mods_depressed |= active_key->mod5_mask;
-+                break;
-+            case IBUS_KEY_ISO_Level5_Latch:
-+            case IBUS_KEY_ISO_Level5_Shift:
-+                priv->is_pressed_mod3 = TRUE;
-+                new_mods_depressed |= active_key->mod3_mask;
-+                break;
-+            default:
-+                g_assert_not_reached ();
-+            }
-             if (sym != system_sym)
-                 priv->is_virtual_latch_state = TRUE;
-             filtered = TRUE;
-+        } else {
-+            IBusKeyIsoLevelValue current_level = IBUS_KEY_ISO_LEVEL_INVALID;
-+            gboolean *is_pressed_current_mod = NULL;
-+            gboolean *is_pressed_reverse_mod = NULL;
-+            xkb_mod_mask_t current_mode_mask = 0;
-+            xkb_mod_mask_t reverse_mode_mask = 0;
-+            switch (sym) {
-+            case IBUS_KEY_ISO_Level3_Latch:
-+            case IBUS_KEY_ISO_Level3_Shift:
-+                current_level = IBUS_KEY_ISO_LEVEL_3;
-+                is_pressed_current_mod = &priv->is_pressed_mod5;
-+                is_pressed_reverse_mod = &priv->is_pressed_mod3;
-+                current_mode_mask = active_key->mod5_mask;
-+                reverse_mode_mask = active_key->mod3_mask;
-+                break;
-+            case IBUS_KEY_ISO_Level5_Latch:
-+            case IBUS_KEY_ISO_Level5_Shift:
-+                current_level = IBUS_KEY_ISO_LEVEL_5;
-+                is_pressed_current_mod = &priv->is_pressed_mod3;
-+                is_pressed_reverse_mod = &priv->is_pressed_mod5;
-+                current_mode_mask = active_key->mod3_mask;
-+                reverse_mode_mask = active_key->mod5_mask;
-+                break;
-+            default:;
-+            }
-+            g_assert (current_level != IBUS_KEY_ISO_LEVEL_INVALID);
-+            g_assert (is_pressed_current_mod && is_pressed_reverse_mod);
-+            if (G_LIKELY (*is_pressed_current_mod)) {
-+                *is_pressed_current_mod = FALSE;
-+            } else if (*is_pressed_reverse_mod &&
-+                       (new_mods_depressed & active_key->mod3_mask)) {
-+                /* The unlikely case !priv->is_pressed_mod3 and
-+                 * priv->is_pressed_mod5 means that "de(T3)" keymap gives
-+                 * the pressed "Level3_Shift" keysym and
-+                 * the released "Level5_Latch" keysym for the key <RALT>.
-+                 * Maybe a bug in "de(T3)" so need to clear the MOD5 state
-+                 * by the pressed "Level3_Shift" keysym.
-+                 */
-+                *is_pressed_reverse_mod = FALSE;
-+                new_mods_depressed &= ~reverse_mode_mask;
-+                *clear_virtual_state = TRUE;
-+                g_debug ("Got a wrong released %s key without the "
-+                         "pressed one. Maybe a bug in XKB.",
-+                         current_level == IBUS_KEY_ISO_LEVEL_3 ?
-+                                 "Level3" : "Level5");
-+            }
-+            /* The "lv(tilde)" keymap gives the "Level3_Shift" keysym
-+             * with the key <RALT>.
-+             */
-+            if ((current_level == IBUS_KEY_ISO_LEVEL_3 &&
-+                 sym == IBUS_KEY_ISO_Level3_Shift) ||
-+                (current_level == IBUS_KEY_ISO_LEVEL_5 &&
-+                 sym == IBUS_KEY_ISO_Level5_Shift)) {
-+                new_mods_depressed &= ~current_mode_mask;
-+                if (sym != system_sym)
-+                    clear_virtual_state = TRUE;
-+            }
-         }
-         break;
-     case IBUS_KEY_Shift_L:
-@@ -649,6 +744,23 @@ ibus_wayland_im_update_virtual_xkb_state (IBusWaylandIM *wlim,
-                               (state == WL_KEYBOARD_KEY_STATE_RELEASED)
-                               ? XKB_KEY_UP : XKB_KEY_DOWN);
-     }
-+    if (priv->is_virtual_latch_state &&
-+        (new_mods_depressed != mods_depressed) &&
-+        (state != WL_KEYBOARD_KEY_STATE_RELEASED)) {
-+        xkb_mod_mask_t new2_mods_depressed;
-+        new2_mods_depressed = xkb_state_serialize_mods (active_key->state,
-+                                                        XKB_STATE_DEPRESSED |
-+                                                        XKB_STATE_LATCHED);
-+        /* "de(T3)" keymap gives the pressed "Level3_Shift" keysym and
-+         * sets both MOD3(Level5) and MOD5(Level3) states after
-+         * xkb_state_update_key() is called with the keypress.
-+         * Maybe a bug in "de(T3)" and sets MOD5(Level3) again here.
-+         */
-+        if (G_UNLIKELY (new_mods_depressed != new2_mods_depressed)) {
-+            xkb_state_update_mask (active_key->state, new_mods_depressed,
-+                                   0, mods_locked, 0, 0, group);
-+        }
-+    }
- }
- 
- 
-@@ -1355,6 +1467,7 @@ _bus_global_engine_changed_cb (IBusBus       *bus,
-     g_return_if_fail (IBUS_IS_WAYLAND_IM (wlim));
-     priv = ibus_wayland_im_get_instance_private (wlim);
-     desc = ibus_bus_get_global_engine (bus);
-+    ibus_wayland_im_reset_modifiers (wlim);
-     g_assert (desc);
-     g_assert (!g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name));
-     /* Always update priv->key_user even if priv->use_sys_keymap is %FALSE
-@@ -1544,7 +1657,8 @@ ibus_wayland_im_post_key (IBusWaylandIM *wlim,
-                                                          sym,
-                                                          active_key,
-                                                          filtered,
--                                                         &new_mods_depressed);
-+                                                         &new_mods_depressed,
-+                                                         &clear_virtual_state);
-     filtered = ibus_wayland_im_commit_key_event (wlim,
-                                                  key,
-                                                  modifiers,
-@@ -2427,6 +2541,7 @@ _create_input_context_done (GObject      *object,
-                                                            TRUE);
-         }
-         ibus_input_context_focus_in (priv->ibuscontext);
-+        ibus_wayland_im_reset_modifiers (wlim);
-         g_signal_emit (wlim,
-                        wayland_im_signals[IBUS_FOCUS_IN],
-                        0,
--- 
-2.54.0
-
-From 22ca37a5d43ac7cf049780da5e1452505406c072 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Thu, 25 Jun 2026 22:16:42 +0900
-Subject: [PATCH 4/5] client/wayland: Fix infinite dead_diaeresis with fr(ergol) keymap
-
-Typing the key <AD09> twice gives different keysyms between KeyPress
-and KeyRelease events and causes the reverse order of KeyPress and
-KeyRelease of the "dead_diaeresis" keysym.
-Now ibus-wayland checks the special order not to cause the key repeating.
-Also ibus-wayland releases the state of "ISO_Level5_Latch" with typing
-the key <AD09> twice.
-
-Fixes: #2869
-Closes: #2894
----
- client/wayland/ibuswaylandim.c | 245 +++++++++++++++++++++++----------
- 1 file changed, 172 insertions(+), 73 deletions(-)
-
-diff --git a/client/wayland/ibuswaylandim.c b/client/wayland/ibuswaylandim.c
-index 97e3ce38..efeb6783 100644
---- a/client/wayland/ibuswaylandim.c
-+++ b/client/wayland/ibuswaylandim.c
-@@ -71,6 +71,12 @@ typedef enum {
-     IBUS_KEY_ISO_LEVEL_5
- } IBusKeyIsoLevelValue;
- 
-+typedef enum {
-+    IBUS_KEY_ISO_LEVEL_STATE_RELEASE,
-+    IBUS_KEY_ISO_LEVEL_STATE_SHIFT,
-+    IBUS_KEY_ISO_LEVEL_STATE_LATCH
-+} IBusKeyIsoLevelState;
-+
- struct zwp_input_method_context_union {
-     union {
-         struct zwp_input_method_context_v1 *context_v1;
-@@ -170,12 +176,14 @@ struct _IBusWaylandIMPrivate
- 
-     IBusXkbKeymap key_user;
-     IBusXkbKeymap key_sys;
--    gboolean is_pressed_mod3;
--    gboolean is_pressed_mod5;
-+    IBusKeyIsoLevelState iso_level3_state;
-+    IBusKeyIsoLevelState iso_level5_state;
- 
-     uint32_t im_serial;
-     int32_t repeat_rate;
-     int32_t repeat_delay;
-+    xkb_keysym_t pressed_dead_key;
-+    xkb_keysym_t released_dead_key_wo_press;
- 
-     GCancellable *cancellable;
- };
-@@ -360,8 +368,10 @@ ibus_wayland_im_reset_modifiers (IBusWaylandIM *wlim)
- 
-     priv = ibus_wayland_im_get_instance_private (wlim);
-     priv->is_virtual_latch_state = FALSE;
--    priv->is_pressed_mod3 = FALSE;
--    priv->is_pressed_mod5 = FALSE;
-+    priv->iso_level3_state = IBUS_KEY_ISO_LEVEL_STATE_RELEASE;
-+    priv->iso_level5_state = IBUS_KEY_ISO_LEVEL_STATE_RELEASE;
-+    priv->pressed_dead_key = 0;
-+    priv->released_dead_key_wo_press = 0;
-     if (priv->key_user.state && priv->key_sys.state) {
-         group = xkb_state_serialize_layout (priv->key_sys.state,
-                                             XKB_STATE_LAYOUT_LOCKED);
-@@ -407,7 +417,8 @@ ibus_wayland_im_commit_key_event (IBusWaylandIM  *wlim,
-                                   IBusXkbKeymap  *active_key,
-                                   gboolean        filtered,
-                                   xkb_mod_mask_t *new_mods_depressed,
--                                  gboolean       *clear_virtual_state)
-+                                  gboolean       *clear_virtual_state,
-+                                  gboolean       *is_invalid_key)
- {
-     IBusWaylandIMPrivate *priv;
-     uint32_t code = key + 8;
-@@ -416,9 +427,6 @@ ibus_wayland_im_commit_key_event (IBusWaylandIM  *wlim,
-     g_return_val_if_fail (IBUS_IS_WAYLAND_IM (wlim), filtered);
-     priv = ibus_wayland_im_get_instance_private (wlim);
- 
--    if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
--        return filtered;
--
-     ch = ibus_keyval_to_unicode (sym);
-     if (ch == 0 || g_unichar_iscntrl (ch))
-         ch = xkb_state_key_get_utf32 (active_key->state, code);
-@@ -431,23 +439,28 @@ ibus_wayland_im_commit_key_event (IBusWaylandIM  *wlim,
- #  define _IBUS_NO_TEXT_INPUT_MOD_MASK (\
-     IBUS_CONTROL_MASK | IBUS_MOD2_MASK | IBUS_MOD4_MASK)
- #endif
--    if ((!filtered && !(modifiers & _IBUS_NO_TEXT_INPUT_MOD_MASK) &&
--         !g_unichar_iscntrl (ch)) || filtered) {
--        /* In case `use_sys_keymap` is %TRUE, IBus does not commit ASCII chars
--         * but forwards the key events to the focused application here.
--         * Because some applications treat the printable keys as control keys,
--         * E.g. game apps "hjkl" use the cursor move like VI mode.
--         * Unfortunately the Wayland input-method protocol does not provide
--         * the fallback logic after apps handle the key events like GTK3/2
--         * IM modules. But the input-method always should handle key events
--         * prior to apps.
--         */
--        if (!filtered && !priv->use_sys_keymap) {
--            gchar buff[8] = { 0, };
--            g_unichar_to_utf8 (ch, buff);
--            ibus_wayland_im_commit_text (wlim, buff);
--            filtered = TRUE;
--        }
-+    if ((state == WL_KEYBOARD_KEY_STATE_RELEASED) ||
-+        (modifiers & _IBUS_NO_TEXT_INPUT_MOD_MASK)) {
-+        return filtered;
-+    }
-+#undef _IBUS_NO_TEXT_INPUT_MOD_MASK
-+
-+    /* In case `use_sys_keymap` is %TRUE, IBus does not commit ASCII chars
-+     * but forwards the key events to the focused application here.
-+     * Because some applications treat the printable keys as control keys,
-+     * E.g. game apps "hjkl" use the cursor move like VI mode.
-+     * Unfortunately the Wayland input-method protocol does not provide
-+     * the fallback logic after apps handle the key events like GTK3/2
-+     * IM modules. But the input-method always should handle key events
-+     * prior to apps.
-+     */
-+    if (!filtered && !g_unichar_iscntrl (ch) && !priv->use_sys_keymap) {
-+        gchar buff[8] = { 0, };
-+        g_unichar_to_utf8 (ch, buff);
-+        ibus_wayland_im_commit_text (wlim, buff);
-+        filtered = TRUE;
-+    }
-+    if (!g_unichar_iscntrl (ch) || IS_DEAD_KEY (sym)) {
-         /* If `filtered` is %TRUE, the keysym can be eaten for the compose
-          * preedit by IBus XKB engine. E.g. AltGr-Shift-V key produces
-          * `Level3_Shift' and `Greek_OMEGA` keysym with "us(symbolic)" keymap.
-@@ -456,19 +469,42 @@ ibus_wayland_im_commit_key_event (IBusWaylandIM  *wlim,
-          * I'm not clarified with "level3(ralt_switch)" in us XKB keymaps.
-          */
-         if (modifiers & IBUS_MOD3_MASK) {
-+            /* With the "fr(ergol)" keymap, Typing the key <AD09> twice
-+             * produces the "ISO_Level5_Latch" keysym for the first KeyPress
-+             * and the "dead_diaeresis" keysym for the first KeyReleease
-+             * because the release key event has MOD3(level5) state.
-+             * And the second KeyPress has the "dead_diaeresis" keysym and
-+             * the second KeyRelease has the "ISO_Level5_Latch" keysym.
-+             * The latch state should be cleared with the dead keys.
-+             * I downgrade the latch state to the shift state here and
-+             * the shift state will be cleared by the released
-+             * "ISO_Level5_Latch" keysym but not the pressed dead keys
-+             * because xkb_state_update_key() will revert the MOD3(level5)
-+             * state of the depressed xkb_state_serialize_mods()
-+             * with the dead keys.
-+             */
-+            if (priv->iso_level5_state == IBUS_KEY_ISO_LEVEL_STATE_LATCH) {
-+                priv->iso_level5_state = IBUS_KEY_ISO_LEVEL_STATE_SHIFT;
-+                if (is_invalid_key)
-+                    *is_invalid_key = TRUE;
-+            } else if (clear_virtual_state) {
-+                *clear_virtual_state = TRUE;
-+            }
-             if (new_mods_depressed)
-                 *new_mods_depressed &= ~active_key->mod3_mask;
--            if (clear_virtual_state)
--                *clear_virtual_state = TRUE;
-         }
-         if (modifiers & IBUS_MOD5_MASK) {
-+            if (priv->iso_level3_state == IBUS_KEY_ISO_LEVEL_STATE_LATCH) {
-+                priv->iso_level3_state = IBUS_KEY_ISO_LEVEL_STATE_SHIFT;
-+                if (is_invalid_key)
-+                    *is_invalid_key = TRUE;
-+            } else if (clear_virtual_state) {
-+                *clear_virtual_state = TRUE;
-+            }
-             if (new_mods_depressed)
-                 *new_mods_depressed &= ~active_key->mod5_mask;
--            if (clear_virtual_state)
--                *clear_virtual_state = TRUE;
-         }
-     }
--#undef _IBUS_NO_TEXT_INPUT_MOD_MASK
-     return filtered;
- }
- 
-@@ -558,7 +594,8 @@ ibus_wayland_im_update_virtual_depressed (IBusWaylandIM  *wlim,
-                                           IBusXkbKeymap  *active_key,
-                                           gboolean        filtered,
-                                           xkb_mod_mask_t *mods_depressed,
--                                          gboolean       *clear_virtual_state)
-+                                          gboolean       *clear_virtual_state,
-+                                          gboolean       *is_invalid_key)
- {
-     IBusWaylandIMPrivate *priv;
-     uint32_t code = key + 8;
-@@ -572,6 +609,7 @@ ibus_wayland_im_update_virtual_depressed (IBusWaylandIM  *wlim,
-     g_assert (active_key);
-     g_assert (mods_depressed);
-     g_assert (clear_virtual_state);
-+    g_assert (is_invalid_key);
- 
-     priv = ibus_wayland_im_get_instance_private (wlim);
-     new_mods_depressed = *mods_depressed;
-@@ -597,13 +635,19 @@ ibus_wayland_im_update_virtual_depressed (IBusWaylandIM  *wlim,
-         if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-             switch (sym) {
-             case IBUS_KEY_ISO_Level3_Latch:
-+                priv->iso_level3_state = IBUS_KEY_ISO_LEVEL_STATE_LATCH;
-+                new_mods_depressed |= active_key->mod5_mask;
-+                break;
-             case IBUS_KEY_ISO_Level3_Shift:
--                priv->is_pressed_mod5 = TRUE;
-+                priv->iso_level3_state = IBUS_KEY_ISO_LEVEL_STATE_SHIFT;
-                 new_mods_depressed |= active_key->mod5_mask;
-                 break;
-             case IBUS_KEY_ISO_Level5_Latch:
-+                priv->iso_level5_state = IBUS_KEY_ISO_LEVEL_STATE_LATCH;
-+                new_mods_depressed |= active_key->mod3_mask;
-+                break;
-             case IBUS_KEY_ISO_Level5_Shift:
--                priv->is_pressed_mod3 = TRUE;
-+                priv->iso_level5_state = IBUS_KEY_ISO_LEVEL_STATE_SHIFT;
-                 new_mods_depressed |= active_key->mod3_mask;
-                 break;
-             default:
-@@ -614,61 +658,70 @@ ibus_wayland_im_update_virtual_depressed (IBusWaylandIM  *wlim,
-             filtered = TRUE;
-         } else {
-             IBusKeyIsoLevelValue current_level = IBUS_KEY_ISO_LEVEL_INVALID;
--            gboolean *is_pressed_current_mod = NULL;
--            gboolean *is_pressed_reverse_mod = NULL;
--            xkb_mod_mask_t current_mode_mask = 0;
--            xkb_mod_mask_t reverse_mode_mask = 0;
-+            IBusKeyIsoLevelState *current_state = NULL;
-+            IBusKeyIsoLevelState *reverse_state = NULL;
-             switch (sym) {
-             case IBUS_KEY_ISO_Level3_Latch:
-             case IBUS_KEY_ISO_Level3_Shift:
-                 current_level = IBUS_KEY_ISO_LEVEL_3;
--                is_pressed_current_mod = &priv->is_pressed_mod5;
--                is_pressed_reverse_mod = &priv->is_pressed_mod3;
--                current_mode_mask = active_key->mod5_mask;
--                reverse_mode_mask = active_key->mod3_mask;
-+                current_state = &priv->iso_level3_state;
-+                reverse_state = &priv->iso_level5_state;
-                 break;
-             case IBUS_KEY_ISO_Level5_Latch:
-             case IBUS_KEY_ISO_Level5_Shift:
-                 current_level = IBUS_KEY_ISO_LEVEL_5;
--                is_pressed_current_mod = &priv->is_pressed_mod3;
--                is_pressed_reverse_mod = &priv->is_pressed_mod5;
--                current_mode_mask = active_key->mod3_mask;
--                reverse_mode_mask = active_key->mod5_mask;
-+                current_state = &priv->iso_level5_state;
-+                reverse_state = &priv->iso_level3_state;
-                 break;
-             default:;
-             }
-             g_assert (current_level != IBUS_KEY_ISO_LEVEL_INVALID);
--            g_assert (is_pressed_current_mod && is_pressed_reverse_mod);
--            if (G_LIKELY (*is_pressed_current_mod)) {
--                *is_pressed_current_mod = FALSE;
--            } else if (*is_pressed_reverse_mod &&
--                       (new_mods_depressed & active_key->mod3_mask)) {
-+            g_assert (current_state && reverse_state);
-+            /* The "lv(tilde)" keymap gives the "Level3_Shift" keysym
-+             * with the key <RALT>.
-+             *
-+             * Handle the "ISO_Level5_Latch" keysym in the "fr(ergol)" keymap.
-+             * Do not use keysym but `current_state` because the latch state
-+             * can be changed to the shift state with some key conditions.
-+             */
-+            if (*current_state == IBUS_KEY_ISO_LEVEL_STATE_SHIFT) {
-+                *current_state = IBUS_KEY_ISO_LEVEL_STATE_RELEASE;
-+                if (current_level == IBUS_KEY_ISO_LEVEL_3)
-+                    new_mods_depressed &= ~active_key->mod5_mask;
-+                else if (current_level == IBUS_KEY_ISO_LEVEL_5)
-+                    new_mods_depressed &= ~active_key->mod3_mask;
-+                else
-+                    g_assert_not_reached ();
-+                if (sym != system_sym)
-+                    *clear_virtual_state = TRUE;
-+            } else if (!*current_state && *reverse_state &&
-+                       (((current_level == IBUS_KEY_ISO_LEVEL_3) &&
-+                         (new_mods_depressed & active_key->mod3_mask)) ||
-+                        ((current_level == IBUS_KEY_ISO_LEVEL_5) &&
-+                         (new_mods_depressed & active_key->mod5_mask))
-+                       )) {
-                 /* The unlikely case !priv->is_pressed_mod3 and
-                  * priv->is_pressed_mod5 means that "de(T3)" keymap gives
-                  * the pressed "Level3_Shift" keysym and
-                  * the released "Level5_Latch" keysym for the key <RALT>.
--                 * Maybe a bug in "de(T3)" so need to clear the MOD5 state
--                 * by the pressed "Level3_Shift" keysym.
-+                 * This case can happen if the normal keysym and shift keysym
-+                 * are different.
-                  */
--                *is_pressed_reverse_mod = FALSE;
--                new_mods_depressed &= ~reverse_mode_mask;
-+                *reverse_state = IBUS_KEY_ISO_LEVEL_STATE_RELEASE;
-+                *is_invalid_key = TRUE;
-+                if (current_level == IBUS_KEY_ISO_LEVEL_3)
-+                    new_mods_depressed &= ~active_key->mod3_mask;
-+                else if (current_level == IBUS_KEY_ISO_LEVEL_5)
-+                    new_mods_depressed &= ~active_key->mod5_mask;
-+                else
-+                    g_assert_not_reached ();
-                 *clear_virtual_state = TRUE;
-                 g_debug ("Got a wrong released %s key without the "
--                         "pressed one. Maybe a bug in XKB.",
-+                         "pressed one. Maybe the next Shift state will "
-+                         "produce the delayed pressed one.",
-                          current_level == IBUS_KEY_ISO_LEVEL_3 ?
-                                  "Level3" : "Level5");
-             }
--            /* The "lv(tilde)" keymap gives the "Level3_Shift" keysym
--             * with the key <RALT>.
--             */
--            if ((current_level == IBUS_KEY_ISO_LEVEL_3 &&
--                 sym == IBUS_KEY_ISO_Level3_Shift) ||
--                (current_level == IBUS_KEY_ISO_LEVEL_5 &&
--                 sym == IBUS_KEY_ISO_Level5_Shift)) {
--                new_mods_depressed &= ~current_mode_mask;
--                if (sym != system_sym)
--                    clear_virtual_state = TRUE;
--            }
-         }
-         break;
-     case IBUS_KEY_Shift_L:
-@@ -707,7 +760,8 @@ ibus_wayland_im_update_virtual_xkb_state (IBusWaylandIM *wlim,
-                                           IBusXkbKeymap *active_key,
-                                           xkb_mod_mask_t mods_depressed,
-                                           xkb_mod_mask_t new_mods_depressed,
--                                          gboolean       clear_virtual_state)
-+                                          gboolean       clear_virtual_state,
-+                                          gboolean       is_invalid_key)
- {
-     IBusWaylandIMPrivate *priv;
-     uint32_t code = key + 8;
-@@ -738,8 +792,9 @@ ibus_wayland_im_update_virtual_xkb_state (IBusWaylandIM *wlim,
-         if (clear_virtual_state)
-             priv->is_virtual_latch_state = FALSE;
-     }
--    if (!priv->is_virtual_latch_state ||
--        (state != WL_KEYBOARD_KEY_STATE_RELEASED)) {
-+    if (G_LIKELY (!is_invalid_key) &&
-+        (!priv->is_virtual_latch_state ||
-+         (state != WL_KEYBOARD_KEY_STATE_RELEASED))) {
-         xkb_state_update_key (active_key->state, code,
-                               (state == WL_KEYBOARD_KEY_STATE_RELEASED)
-                               ? XKB_KEY_UP : XKB_KEY_DOWN);
-@@ -754,7 +809,8 @@ ibus_wayland_im_update_virtual_xkb_state (IBusWaylandIM *wlim,
-         /* "de(T3)" keymap gives the pressed "Level3_Shift" keysym and
-          * sets both MOD3(Level5) and MOD5(Level3) states after
-          * xkb_state_update_key() is called with the keypress.
--         * Maybe a bug in "de(T3)" and sets MOD5(Level3) again here.
-+         * FIXME: Should set `is_invalid_key` in this case of the "de(T3)"
-+         * keymap too not to call xkb_state_update_key() here?
-          */
-         if (G_UNLIKELY (new_mods_depressed != new2_mods_depressed)) {
-             xkb_state_update_mask (active_key->state, new_mods_depressed,
-@@ -1623,6 +1679,7 @@ ibus_wayland_im_post_key (IBusWaylandIM *wlim,
-     IBusXkbKeymap *active_key;
-     xkb_mod_mask_t mods_depressed, new_mods_depressed;
-     gboolean clear_virtual_state = FALSE;
-+    gboolean is_invalid_key = FALSE;
- 
-     g_return_val_if_fail (IBUS_IS_WAYLAND_IM (wlim), FALSE);
-     priv = ibus_wayland_im_get_instance_private (wlim);
-@@ -1658,7 +1715,8 @@ ibus_wayland_im_post_key (IBusWaylandIM *wlim,
-                                                          active_key,
-                                                          filtered,
-                                                          &new_mods_depressed,
--                                                         &clear_virtual_state);
-+                                                         &clear_virtual_state,
-+                                                         &is_invalid_key);
-     filtered = ibus_wayland_im_commit_key_event (wlim,
-                                                  key,
-                                                  modifiers,
-@@ -1667,14 +1725,16 @@ ibus_wayland_im_post_key (IBusWaylandIM *wlim,
-                                                  active_key,
-                                                  filtered,
-                                                  &new_mods_depressed,
--                                                 &clear_virtual_state);
-+                                                 &clear_virtual_state,
-+                                                 &is_invalid_key);
-     ibus_wayland_im_update_virtual_xkb_state (wlim,
-                                               key,
-                                               state,
-                                               active_key,
-                                               mods_depressed,
-                                               new_mods_depressed,
--                                              clear_virtual_state);
-+                                              clear_virtual_state,
-+                                              is_invalid_key);
-     return filtered;
- }
- 
-@@ -2053,6 +2113,21 @@ key_event_check_repeat (IBusWaylandIM       *wlim,
-         g_clear_pointer (&repeating_event.ibus_object_path, g_free);
-         if (!priv->ibuscontext)
-             return FALSE;
-+        if (IS_DEAD_KEY (event->sym)) {
-+            /* With "fr(ergol)" keymap, in case that key <AD09> is typed
-+             * twice, the second pressed keysym is "dead_diaeresis" and
-+             * the second released keysym is "ISO_Level5_Latch".
-+             * The keysym "dead_diaeresis" should not be auto-repeated
-+             * in this case.
-+             */
-+            if (priv->released_dead_key_wo_press == event->sym) {
-+                priv->released_dead_key_wo_press = 0;
-+                return TRUE;
-+            }
-+            priv->pressed_dead_key = event->sym;
-+        } else {
-+            priv->released_dead_key_wo_press = 0;
-+        }
-         source = g_timeout_source_new (priv->repeat_delay);
-         g_source_attach (source, NULL);
-         g_source_unref (source);
-@@ -2066,6 +2141,30 @@ key_event_check_repeat (IBusWaylandIM       *wlim,
-         g_source_set_callback (source, _process_key_event_repeat_delay_cb,
-                                &repeating_event, NULL);
-     } else {
-+        if (event->sym != repeating_event.sym) {
-+            if (IS_DEAD_KEY (event->sym)) {
-+                if (event->sym == priv->pressed_dead_key) {
-+                    priv->pressed_dead_key = 0;
-+                } else if (!priv->pressed_dead_key) {
-+                    /* With "fr(ergol)" keymap, in case that key <AD09> is
-+                     * typed twice, the first pressed keysym is
-+                     * "ISO_Level5_Latch" and the first released keysym is
-+                     * "dead_diaeresis" with the MOD3(the level5) mask,
-+                     * the second pressed keysym is "dead_diaeresis" and
-+                     * the second released keysym is "ISO_Level5_Latch".
-+                     * So the first released "dead_diaeresis" is invalid and
-+                     * the second pressed "dead_diaeresis" should be released
-+                     * immediately.
-+                     */
-+                    priv->released_dead_key_wo_press = event->sym;
-+                }
-+            }
-+        } else if (IS_DEAD_KEY (repeating_event.sym)) {
-+            if (repeating_event.sym == priv->pressed_dead_key)
-+                priv->pressed_dead_key = 0;
-+        } else {
-+            priv->released_dead_key_wo_press = 0;
-+        }
-         if (repeating_event.repeat_rate_id) {
-             g_source_remove (repeating_event.repeat_rate_id);
-             repeating_event.repeat_rate_id = 0;
--- 
-2.54.0
-
-From b60b54044406ff508fd025de32c10d78829ff2a3 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Sun, 19 Jul 2026 18:15:42 +0900
-Subject: [PATCH 5/5] client/wayland: Fix CapsLock between focus changes
-
-ibus_wayland_im_reset_modifiers() should not reset the state of CapsLock
-and ibus_wayland_im_update_virtual_depressed() should compare
-`priv->modifiers` and `(mods_depressed & mods_locked)`.
-
-Fixes: #2869
----
- client/wayland/ibuswaylandim.c | 33 ++++++++++++++++++++++++---------
- 1 file changed, 24 insertions(+), 9 deletions(-)
-
-diff --git a/client/wayland/ibuswaylandim.c b/client/wayland/ibuswaylandim.c
-index efeb6783..8b1e7b53 100644
---- a/client/wayland/ibuswaylandim.c
-+++ b/client/wayland/ibuswaylandim.c
-@@ -362,6 +362,7 @@ static void
- ibus_wayland_im_reset_modifiers (IBusWaylandIM *wlim)
- {
-     IBusWaylandIMPrivate *priv;
-+    xkb_mod_mask_t mods_locked = 0;
-     xkb_layout_index_t  group = 0;
- 
-     g_assert (IBUS_IS_WAYLAND_IM (wlim));
-@@ -373,11 +374,15 @@ ibus_wayland_im_reset_modifiers (IBusWaylandIM *wlim)
-     priv->pressed_dead_key = 0;
-     priv->released_dead_key_wo_press = 0;
-     if (priv->key_user.state && priv->key_sys.state) {
-+        mods_locked = xkb_state_serialize_mods (priv->key_sys.state,
-+                                                XKB_STATE_LOCKED);
-         group = xkb_state_serialize_layout (priv->key_sys.state,
-                                             XKB_STATE_LAYOUT_LOCKED);
--        input_method_keyboard_modifiers (wlim, NULL, 0, 0, 0, 0, group);
-+        input_method_keyboard_modifiers (wlim, NULL, 0, 0, 0,
-+                                         mods_locked,
-+                                         group);
-     } else {
--        priv->modifiers = 0;
-+        priv->modifiers &= IBUS_LOCK_MASK;
-     }
- }
- 
-@@ -600,6 +605,7 @@ ibus_wayland_im_update_virtual_depressed (IBusWaylandIM  *wlim,
-     IBusWaylandIMPrivate *priv;
-     uint32_t code = key + 8;
-     xkb_mod_mask_t new_mods_depressed;
-+    xkb_mod_mask_t mods_locked;
-     xkb_keysym_t system_sym = sym;
- 
-     if (filtered)
-@@ -613,10 +619,13 @@ ibus_wayland_im_update_virtual_depressed (IBusWaylandIM  *wlim,
- 
-     priv = ibus_wayland_im_get_instance_private (wlim);
-     new_mods_depressed = *mods_depressed;
-+    mods_locked = xkb_state_serialize_mods (active_key->state,
-+                                            XKB_STATE_LOCKED);
- 
--    if ((modifiers & ~IBUS_RELEASE_MASK ) != new_mods_depressed) {
-+    if ((modifiers & ~IBUS_RELEASE_MASK ) !=
-+        (new_mods_depressed | mods_locked)) {
-         g_warning ("IBus modifiers %X is different from XKB depressed %X",
--                   modifiers, new_mods_depressed);
-+                   modifiers, new_mods_depressed | mods_locked);
-     }
-     if (priv->key_sys.state)
-         system_sym = xkb_state_key_get_one_sym (priv->key_sys.state, code);
-@@ -772,7 +781,7 @@ ibus_wayland_im_update_virtual_xkb_state (IBusWaylandIM *wlim,
- 
-     priv = ibus_wayland_im_get_instance_private (wlim);
-     mods_locked = xkb_state_serialize_mods (active_key->state,
--                                            XKB_STATE_MODS_LOCKED);
-+                                            XKB_STATE_LOCKED);
-     /* XKB group layout is configured in the system keymap but not the
-      * user keymap which always includes a single layout.
-      */
-@@ -2220,9 +2229,15 @@ input_method_keyboard_key (void                      *data,
-     /* xkb_key_get_syms() does not return the capital syms with Shift key. */
-     if (priv->key_sys.state)
-         event.sym = xkb_state_key_get_one_sym (priv->key_sys.state, code);
-+    /* The position of Caps_Lock, Control, ISO_Next_Group, Multi_key keysyms
-+     * can be customzied by each desktop configuration.
-+     */
-     switch (event.sym) {
--    case IBUS_KEY_Multi_key:
-+    case IBUS_KEY_Caps_Lock:
-+    case IBUS_KEY_Control_L:
-+    case IBUS_KEY_Control_R:
-     case IBUS_KEY_ISO_Next_Group:
-+    case IBUS_KEY_Multi_key:
-         break;
-     default:
-         if (priv->key_user.state)
-@@ -2337,11 +2352,11 @@ input_method_keyboard_modifiers (void                      *data,
-         }
-     }
-     if (active_key->state) {
--        /* CapsLock needs XKB_STATE_MODS_LOCKED */
-+        /* CapsLock needs XKB_STATE_LOCKED */
-         mask = xkb_state_serialize_mods (active_key->state,
-                                          XKB_STATE_DEPRESSED |
-                                          XKB_STATE_LATCHED |
--                                         XKB_STATE_MODS_LOCKED);
-+                                         XKB_STATE_LOCKED);
-     }
-     if (priv->verbose) {
-         struct xkb_state *state = active_key->state;
-@@ -2356,7 +2371,7 @@ input_method_keyboard_modifiers (void                      *data,
-                      xkb_state_serialize_mods (state, XKB_STATE_LATCHED) :
-                      0xFFFFFFFF,
-                  state ?
--                     xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED) :
-+                     xkb_state_serialize_mods (state, XKB_STATE_LOCKED) :
-                      0xFFFFFFFF);
-         fflush (priv->log);
-     }
--- 
-2.54.0
-

             reply	other threads:[~2026-08-12  3:33 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-12  3:33 Takao Fujiwara [this message]
  -- strict thread matches above, loose matches on Subject: below --
2026-06-19 12:15 [rpms/ibus] rawhide: Delete upstreamed patches Takao Fujiwara

Reply instructions:

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

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

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

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

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

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

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