public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Takao Fujiwara <tfujiwar@redhat.com>
To: git-commits@fedoraproject.org
Subject: [rpms/ibus] autotool: Replace GNOME Xorg with GNOME Wayland in CI
Date: Sun, 31 May 2026 02:08:37 GMT [thread overview]
Message-ID: <178019331746.1.10463635213017488872.rpms-ibus-cb19883e9b52@fedoraproject.org> (raw)
A new commit has been pushed.
Repo : rpms/ibus
Branch : autotool
Commit : cb19883e9b523e591ad874827b2a1cf3eb9d74ca
Author : Takao Fujiwara <tfujiwar@redhat.com>
Date : 2024-07-27T20:35:24+09:00
Stats : +3913/-1 in 2 file(s)
URL : https://src.fedoraproject.org/rpms/ibus/c/cb19883e9b523e591ad874827b2a1cf3eb9d74ca?branch=autotool
Log:
Replace GNOME Xorg with GNOME Wayland in CI
---
diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch
index d2f5082..bafefcd 100644
--- a/ibus-HEAD.patch
+++ b/ibus-HEAD.patch
@@ -66,3 +66,3911 @@ index 7531a4b2..a8e41a33 100644
--
2.45.0
+From a52861385bb5d15598f6c3c3d86c7a9ee19f140a Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Sat, 27 Jul 2024 19:00:53 +0900
+Subject: [PATCH 1/6] src/tests: Enable CI in GNOME Wayland
+
+- Implement headless desktop to test Wayland sessions
+- Implement ibus-desktop-testing-autostart to be executed in XDG
+ autostart in GNOME Wayland
+- Move shared codes to ibus-desktop-testing-module between
+ ibus-desktop-testing-runner and ibus-desktop-testing-autostart
+- Add --no-systemd option to enable the previous testing frame with running
+ gnome-session directly
+- Rename --desktop option to --session
+- Move save_screen() from runner to module
+- Copy gnome-shell service file to user home for headless & virtual-monitor
+- Add --delete-tests option to clean up tests
+- Add AutostartCondition=if-exists in XDG autostart desktop file
+- Add 60 secs in ibus-compose-locales for systemd desktop sessions
+- Quote file names as much as possible.
+- Check file existant and not to use "rm -f" as much as possible
+- Do not set GTK_IM_MODULE=ibus for Wayland
+
+BUG=https://github.com/ibus/ibus/pull/2657
+---
+ src/tests/Makefile.am | 23 +-
+ src/tests/ibus-compose-locales.in | 16 +-
+ src/tests/ibus-desktop-testing-autostart | 57 --
+ src/tests/ibus-desktop-testing-autostart.in | 83 ++
+ src/tests/ibus-desktop-testing-module | 876 ++++++++++++++++++++
+ src/tests/ibus-desktop-testing-runner.in | 495 +----------
+ src/tests/ibus-desktop-testing.desktop.in | 2 +-
+ 7 files changed, 1034 insertions(+), 518 deletions(-)
+ delete mode 100755 src/tests/ibus-desktop-testing-autostart
+ create mode 100755 src/tests/ibus-desktop-testing-autostart.in
+ create mode 100755 src/tests/ibus-desktop-testing-module
+
+diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
+index b30a39fb..6c4c86cf 100644
+--- a/src/tests/Makefile.am
++++ b/src/tests/Makefile.am
+@@ -106,6 +106,7 @@ test_sourcesdir = $(datadir)/installed-tests/ibus
+
+ CLEANFILES += \
+ $(test_metas) \
++ ibus-desktop-testing-autostart \
+ ibus-desktop-testing-runner \
+ org.freedesktop.IBus.Desktop.Testing.desktop \
+ $(NULL)
+@@ -119,7 +120,10 @@ CLEANFILES += \
+ $(NULL)
+ endif
+ test_execsdir = $(libexecdir)/installed-tests/ibus
+-libexec_SCRIPTS = ibus-desktop-testing-autostart
++libexec_SCRIPTS = \
++ ibus-desktop-testing-autostart \
++ ibus-desktop-testing-module \
++ $(NULL)
+
+ test_frame_DATA = org.freedesktop.IBus.Desktop.Testing.desktop
+ test_framedir = $(pkgdatadir)/tests
+@@ -142,9 +146,21 @@ ibus-compose-locales: ibus-compose-locales.in
+ mv $@.tmp $@; \
+ $(NULL)
+
++ibus-desktop-testing-autostart: ibus-desktop-testing-autostart.in
++ INSTALLEDDIR=$(datadir)/installed-tests; \
++ sed -e "s|@DATADIR[@]|$(datadir)|g" \
++ -e "s|@INSTALLEDDIR[@]|$$INSTALLEDDIR|g" \
++ -e "s|@LIBEXECDIR[@]|$(libexecdir)|g" \
++ $< > $@.tmp; \
++ mv $@.tmp $@; \
++ $(NULL)
++
+ ibus-desktop-testing-runner: ibus-desktop-testing-runner.in
+ INSTALLEDDIR=$(datadir)/installed-tests; \
+- sed -e "s|@INSTALLEDDIR[@]|$$INSTALLEDDIR|g" $< > $@.tmp; \
++ sed -e "s|@DATADIR[@]|$(datadir)|g" \
++ -e "s|@INSTALLEDDIR[@]|$$INSTALLEDDIR|g" \
++ -e "s|@LIBEXECDIR[@]|$(libexecdir)|g" \
++ $< > $@.tmp; \
+ mv $@.tmp $@; \
+ $(NULL)
+
+@@ -157,7 +173,8 @@ EXTRA_DIST = \
+ ibus-compose.env \
+ ibus-compose-locales.in \
+ ibus-desktop-testing.desktop.in \
+- ibus-desktop-testing-autostart \
++ ibus-desktop-testing-autostart.in \
++ ibus-desktop-testing-module \
+ ibus-desktop-testing-runner.in \
+ $(NULL)
+
+diff --git a/src/tests/ibus-compose-locales.in b/src/tests/ibus-compose-locales.in
+index b36165fe..7a133ce0 100755
+--- a/src/tests/ibus-compose-locales.in
++++ b/src/tests/ibus-compose-locales.in
+@@ -6,7 +6,8 @@ BUILDDIR=`dirname $0`
+
+ export IBUS_COMPOSE_CACHE_DIR=$PWD
+
+-retval=0
++RETVAL=0
++INITED=0
+ # Deleted for var in `cat *.env` because IFS=$'\n' is not supported in POSIX sh
+ while read var
+ do
+@@ -14,19 +15,26 @@ do
+ if [ "x$IS_COMMENT" != x ] ; then
+ continue
+ fi
++ while [ x"$IBUS_DAEMON_WITH_SYSTEMD" != x ] && [ $INITED -lt 6 ] ; do
++ echo "Waiting for ${INITED}0 secs till 60 secs"
++ sleep 10
++ INITED=`expr $INITED + 1`
++ done
+ # Use $* instead of $@ not to mix strings and integers
+ echo "# Starting $var $BUILDDIR/ibus-compose $SRCDIR $*"
+ # Need to enclose $@ with double quotes not to split the array.
+ env $var $BUILDDIR/ibus-compose $SRCDIR "$@"
+- retval=`expr $retval + $?`
+- echo "# Finished $var $BUILDDIR/ibus-compose $SRCDIR $* with $retval"
++ RETVAL=`expr $RETVAL + $?`
++ echo "# Finished $var $BUILDDIR/ibus-compose $SRCDIR $* with $RETVAL"
+
+ CACHE_FILES=`ls *.cache`
+ if [ x"$CACHE_FILES" != x ] ; then
+ echo "Clean $CACHE_FILES"
+ rm $CACHE_FILES
+ fi
++ # Need to wait for 1 sec not to be freezed with gnome-shell in Wayland
++ sleep 1
+ done << EOF_ENVS
+ `cat $SRCDIR/ibus-compose.env`
+ EOF_ENVS
+-exit $retval
++exit $RETVAL
+diff --git a/src/tests/ibus-desktop-testing-autostart b/src/tests/ibus-desktop-testing-autostart
+deleted file mode 100755
+index 1e1eb180..00000000
+--- a/src/tests/ibus-desktop-testing-autostart
++++ /dev/null
+@@ -1,57 +0,0 @@
+-#!/bin/sh
+-# -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*-
+-# vim:set noet ts=4:
+-#
+-# ibus - The Input Bus
+-#
+-# Copyright (c) 2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
+-# Copyright (c) 2021 Red Hat, Inc.
+-#
+-# This program is free software; you can redistribute it and/or modify
+-# it under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 2 of the License, or
+-# (at your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful,
+-# but WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-# GNU General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License along
+-# with this program; if not, write to the Free Software Foundation, Inc.,
+-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+-
+-TEST_LOG=
+-COMMANDS='
+-id
+-echo $DISPLAY
+-pwd
+-pstree -asp $$
+-gsettings list-recursively org.gnome.shell
+-rpm -q gnome-shell-extension-no-overview gnome-shell gnome-session
+-ps -ef | grep ibus | grep -v grep
+-ibus address
+-'
+-
+-if [ $# -gt 0 ] ; then
+- TEST_LOG=$1
+-fi
+-
+-run_test()
+-{
+-while read cmd ; do
+- if [ x"$cmd" = x ] ; then
+- continue
+- fi
+- echo "# $cmd"
+- eval "$cmd"
+-done << EOF_COMMANDS
+-`echo "$COMMANDS"`
+-EOF_COMMANDS
+-}
+-
+-if [ x"$TEST_LOG" = x ] ; then
+- run_test
+-else
+- run_test 2>>$TEST_LOG 1>>$TEST_LOG
+-fi
+diff --git a/src/tests/ibus-desktop-testing-autostart.in b/src/tests/ibus-desktop-testing-autostart.in
+new file mode 100755
+index 00000000..d50354df
+--- /dev/null
++++ b/src/tests/ibus-desktop-testing-autostart.in
+@@ -0,0 +1,83 @@
++#!/bin/sh
++# -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*-
++# vim:set noet ts=4:
++#
++# ibus - The Input Bus
++#
++# Copyright (c) 2021-2024 Takao Fujiwara <takao.fujiwara1@gmail.com>
++# Copyright (c) 2021 Red Hat, Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License along
++# with this program; if not, write to the Free Software Foundation, Inc.,
++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++
++
++PROGNAME=`basename $0`
++TEST_CASE_DIR="@INSTALLEDDIR@"
++MODULE_SH='ibus-desktop-testing-module'
++MODULE_SH_PATH="@LIBEXECDIR@/$MODULE_SH"
++TEST_LOG="test-autostart.log"
++TESTING_RUNNER=""
++
++
++if test -f $MODULE_SH_PATH ; then
++ . $MODULE_SH_PATH
++elif test -f $(dirname $0)/$MODULE_SH ; then
++ . $(dirname $0)/$MODULE_SH
++else
++ echo "Not found $MODULE_SH"
++ exit 1
++fi
++
++
++usage()
++{
++ $ECHO -e \
++"This test suite is called from /etc/xdg/autostart for systemd sessions\n" \
++"$PROGNAME [OPTIONS…]\n" \
++"\n" \
++"OPTIONS:\n" \
++"-h, --help This help\n" \
++"-v, --version Show version\n" \
++"-b, --builddir=BUILDDIR Set the BUILDDIR\n" \
++"-s, --srcdir=SOURCEDIR Set the SOURCEDIR\n" \
++"-V, --verbose Verbose log for ibus-daemon\n" \
++"-t, --tests=\"TESTS...\" Run TESTS programs which is separated by space\n" \
++"-r, --runner=RUNNER Run TESTS programs with a test RUNNER.\n" \
++" RUNNDER = 'gnome', 'default' or ''.\n" \
++" 'default' is an embedded runner.\n" \
++" '' is no tests.\n" \
++"-T, --timeout=TIMEOUT Set timeout (default TIMEOUT is 300 sec).\n" \
++"-o, --output=OUTPUT_FILE Output the log to OUTPUT_FILE\n" \
++" default is $TEST_LOG\n" \
++"-O, --result=RESULT_FILE Output the result to RESULT_FILE\n" \
++" default is stdout\n" \
++"-S, --screendump=DUMP_FILE Output the screen to DUMP_FILE ('STDOUT' can be stdout)\n" \
++"-e, --envcheck Retrieve environment variables\n" \
++""
++}
++
++
++main()
++{
++ parse_args "$@"
++ init_session
++ check_env
++ save_screen
++ run_test_suite
++ finit
++}
++
++
++# Need to enclose $@ with double quotes not to split the array.
++main "$@"
+diff --git a/src/tests/ibus-desktop-testing-module b/src/tests/ibus-desktop-testing-module
+new file mode 100755
+index 00000000..2d686813
+--- /dev/null
++++ b/src/tests/ibus-desktop-testing-module
+@@ -0,0 +1,876 @@
++#!/bin/sh
++# -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*-
++# vim:set noet ts=4:
++#
++# ibus - The Input Bus
++#
++# Copyright (c) 2018-2024 Takao Fujiwara <takao.fujiwara1@gmail.com>
++# Copyright (c) 2018 Red Hat, Inc.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License along
++# with this program; if not, write to the Free Software Foundation, Inc.,
++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++
++
++# POSIX sh has no 'echo -e'
++: ${ECHO:='/usr/bin/echo'}
++# POSIX sh has $UID
++# DASH saves the graves in '``' as characters not to be extracted
++: ${UID:=`id -u`}
++: ${TEST_CASE_DIR='/usr/share/installed-tests'}
++: ${AUTOSTART_DESKTOP_DIR='/usr/share/ibus/tests'}
++
++
++VERSION=0.4
++BUILDDIR="."
++SRCDIR="."
++TEST_LOG_STDOUT=0
++RESULT_LOG=""
++SCREEN_LOG=""
++HAVE_GRAPHICS=1
++VERBOSE=0
++SESSION_COMMAND="dbus-launch --exit-with-session gnome-session"
++SESSION_LANG=
++SESSION_IS_GNOME=1
++GNOME_SHELL_WAYLAND_COMMAND="gnome-shell --wayland --headless --virtual-monitor 1024x768"
++SYSTEMD_SYSTEM_DIR="/usr/lib/systemd/user"
++PID_XORG=0
++PID_GNOME_SESSION=0
++ENABLED_SYSTEMD=1
++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"
++TESTS=""
++TIMEOUT=300
++GREEN='\033[0;32m'
++RED='\033[0;31m'
++NC='\033[0m'
++ENV_CHECK=0
++ENV_COMMANDS='
++id
++pwd
++pstree -asp $$
++gsettings list-recursively org.gnome.shell
++rpm -q gnome-shell-extension-no-overview gnome-shell gnome-session
++ps -ef | grep ibus | grep -v grep
++ibus address
++env
++#dbus-send --session --print-reply --dest=org.gnome.Shell.Introspect /org/gnome/Shell/Introspect org.gnome.Shell.Introspect.GetWindows
++'
++
++
++print_log()
++{
++ if [ x"$RESULT_LOG" != x ] ; then
++ # avoid 'echo -e' before call 'sed'.
++ if [ x"$1" = x'-e' ] ; then
++ shift
++ fi
++ NO_ESCAPE=`echo "$@" | sed -e 's/\\\033\\[0;3.m//g' -e 's/\\\033\\[0m//g'`
++ $ECHO $NO_ESCAPE >> $RESULT_LOG
++ else
++ $ECHO "$@"
++ fi
++}
++
++
++parse_args()
++{
++ # This is GNU getopt. "sudo port getopt" in BSD?
++ ARGS=`getopt -o hvb:s:cVd:t:r:iT:o:O:S:el:D --long \
++help,version,builddir:,srcdir:,no-graphics,verbose,desktop:,session:,tests:,\
++runner:,no-systemd,timeout:,output:,result:,screendump:,envcheck,lang:,\
++delete-tests\
++ -- "$@"`;
++ eval set -- "$ARGS"
++ while [ 1 ] ; do
++ case "$1" in
++ -h | --help ) usage; exit 0;;
++ -v | --version ) $ECHO -e "$VERSION"; exit 0;;
++ -b | --builddir ) BUILDDIR="$2"; shift 2;;
++ -s | --srcdir ) SRCDIR="$2"; shift 2;;
++ -c | --no-graphics ) HAVE_GRAPHICS=0; shift;;
++ -V | --verbose ) VERBOSE=1; shift;;
++ --desktop ) SESSION_COMMAND="$2"
++ print_log -e "--desktop is deprecated. Use --session instead"
++ shift 2;;
++ -d | --session ) SESSION_COMMAND="$2"; shift 2;;
++ -t | --tests ) TESTS="$2"; shift 2;;
++ -r | --runner ) TESTING_RUNNER="$2"; shift 2;;
++ -i | --no-systemd ) ENABLED_SYSTEMD=0; shift;;
++ -T | --timeout ) TIMEOUT="$2"; shift 2;;
++ -o | --output ) TEST_LOG="$2"; shift 2;;
++ -O | --result ) RESULT_LOG="$2"; shift 2;;
++ -S | --screendump ) SCREEN_LOG="$2"; shift 2;;
++ -e | --envcheck ) ENV_CHECK=1; shift;;
++ -l | --lang ) SESSION_LANG="$2"; shift 2;;
++ -D | --delete-tests ) delete_test_user; exit 0;;
++ -- ) shift; break;;
++ * ) usage; exit 1;;
++ esac
++ done
++ DL='$'
++ if echo "$SESSION_COMMAND" | grep -q -E ".*-with-dbus$DL" ; then
++ SESSION_COMMAND=`echo "$SESSION_COMMAND" | sed -e 's/-with-dbus$//'`
++ SESSION_COMMAND="dbus-launch --exit-with-session $SESSION_COMMAND"
++ fi
++}
++
++
++check_tty()
++{
++ TTY=`tty`
++ if echo $PROGNAME | grep -q runner ; then
++ if [ $ENABLED_SYSTEMD -eq 1 ] && [ $SESSION_IS_GNOME -eq 1 ] ; then
++ if echo "$TTY" | grep -E 'tty|console' ; then
++ print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: Changing runlevel does not support console. Please log into the host with ssh."
++ exit 1
++ fi
++ fi
++ if [ $ENABLED_SYSTEMD -eq 0 ] ; then
++ if echo "$TTY" | grep -E 'pts' ; then
++ print_log -e "Running session with ssh. It might be good to use console instead."
++ fi
++ fi
++ SESSION=`ps -ef | grep session | grep -v grep`
++ if [ x"$SESSION" != x ] ; then
++ print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: Session is running: $SESSION"
++ exit 1
++ fi
++ fi
++}
++
++
++check_env()
++{
++ if test $ENV_CHECK -eq 0 ; then
++ return
++ fi
++ while read cmd ; do
++ if test x"$cmd" = x ; then
++ continue
++ fi
++ if echo "$cmd" | grep -q "^#"; then
++ continue
++ fi
++ echo "# $cmd" 2>>$TEST_LOG 1>>$TEST_LOG
++ eval "$cmd" 2>>$TEST_LOG 1>>$TEST_LOG
++ done << EOF_ENV_COMMANDS
++`echo "$ENV_COMMANDS"`
++EOF_ENV_COMMANDS
++}
++
++
++save_screen_real()
++{
++ SCREEN_PNG="`date '+%Y%m%d%H%M%S'`.png"
++ gnome-screenshot --file=$SCREEN_PNG
++ if test x"$SCREEN_LOG" = xSTDOUT ; then
++ base64 $SCREEN_PNG
++ touch /var/tmp/STDOUT.log
++ else
++ base64 $SCREEN_PNG > $SCREEN_LOG
++ fi
++}
++
++
++save_screen()
++{
++ if test x"$SCREEN_LOG" = x ; then
++ return
++ fi
++ if test x"$SCREEN_LOG" = xSTDOUT ; then
++ if test -f /var/tmp/STDOUT.log ; then
++ rm /var/tmp/STDOUT.log
++ fi
++ else
++ if test -f "$SCREEN_LOG" ; then
++ rm "$SCREEN_LOG"
++ fi
++ fi
++ save_screen_real &
++ while test 1 ; do
++ if test x"$SCREEN_LOG" = xSTDOUT ; then
++ if test -f /var/tmp/STDOUT.log ; then
++ break
++ fi
++ else
++ if test -f "$SCREEN_LOG" ; then
++ break
++ fi
++ fi
++ sleep 1
++ done
++}
++
++
++create_test_user()
++{
++ if grep -q $TEST_USER /etc/passwd; then
++ return;
++ fi
++ useradd -d $TEST_USER_HOME -m -s /bin/bash $TEST_USER
++ pwconv
++ passwd -d $TEST_USER
++}
++
++
++create_autologin_gdm()
++{
++ if test -f $GDM_CONF && grep -q $TEST_USER $GDM_CONF; then
++ return;
++ fi
++ cat > $GDM_CONF << _EOF_GDM_CONF
++[daemon]
++AutomaticLoginEnable=true
++AutomaticLogin=$TEST_USER
++_EOF_GDM_CONF
++}
++
++
++create_xdg_autostart()
++{
++ if test -f "$TEST_USER_HOME/.config/autostart/$AUTOSTART_DESKTOP_FILE" ; then
++ return
++ fi
++ if test ! -d "$TEST_USER_HOME" ; then
++ print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: No $TEST_USER_HOME"
++ exit 1
++ fi
++ desktop_file="$AUTOSTART_DESKTOP_DIR/$AUTOSTART_DESKTOP_FILE"
++ if test ! -f $desktop_file ; then
++ print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: No $desktop_file"
++ exit 1
++ fi
++ mkdir -p "$TEST_USER_HOME/.config/autostart"
++ cp "$desktop_file" "$TEST_USER_HOME/.config/autostart"
++ LINE="AutostartCondition=if-exists $TEST_USER_HOME/.config/autostart/$AUTOSTART_DESKTOP_FILE"
++ echo "$LINE" >> "$TEST_USER_HOME/.config/autostart/$AUTOSTART_DESKTOP_FILE"
++ chown -R "$TEST_USER" "$TEST_USER_HOME/.config"
++}
++
++
++delete_test_user()
++{
++ print_log "Deleting $TEST_USER"
++ pkill -u $TEST_USER
++ if grep -q $TEST_USER /etc/passwd; then
++ userdel -r $TEST_USER
++ fi
++ if test -f $GDM_CONF && grep -q $TEST_USER $GDM_CONF; then
++ rm $GDM_CONF
++ fi
++
++ if echo "$SESSION_COMMAND" | grep -q gnome-session ; then
++ SESSION_IS_GNOME=1
++ else
++ SESSION_IS_GNOME=0
++ fi
++
++ LOGIN_USER=$USER
++ LOGIN_HOME=$HOME
++ if [ $ENABLED_SYSTEMD -eq 1 ] && [ $SESSION_IS_GNOME -eq 1 ] ; then
++ LOGIN_USER=$TEST_USER
++ LOGIN_HOME=$TEST_USER_HOME
++ fi
++
++ print_log "Deleting $LOGIN_USER environments"
++ if test -f "$LOGIN_HOME/.config/gnome-initial-setup-done" ; then
++ rm "$LOGIN_HOME/.config/gnome-initial-setup-done"
++ fi
++ if test -f "$LOGIN_HOME/.config/user-dirs.locale" ; then
++ rm "$LOGIN_HOME/.config/user-dirs.locale"
++ fi
++ if test -f /var/lib/AccountsService/users/$LOGIN_USER ; then
++ rm /var/lib/AccountsService/users/$LOGIN_USER
++ fi
++ sync
++}
++
++
++init_session()
++{
++ if [ "$RESULT_LOG" != "" ] ; then
++ if [ -f $RESULT_LOG ] ; then
++ rm $RESULT_LOG
++ fi
++ fi
++ echo "$TEST_LOG" | grep ':stdout' > /dev/null
++ HAS_STDOUT=$?
++ if [ $HAS_STDOUT -eq 0 ] ; then
++ TEST_LOG=`echo "$TEST_LOG" | sed -e 's|:stdout||'`
++ TEST_LOG_STDOUT=1
++ fi
++ if [ "$TEST_LOG" = "" ] ; then
++ print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: a log file is required to get return value with 'read' command"
++ exit 1
++ elif [ -f $TEST_LOG ] ; then
++ rm $TEST_LOG
++ fi
++
++ if echo "$SESSION_COMMAND" | grep -q gnome-session ; then
++ SESSION_IS_GNOME=1
++ else
++ SESSION_IS_GNOME=0
++ fi
++
++ LOGIN_USER=$USER
++ LOGIN_HOME=$HOME
++ check_tty
++ 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"
++ if [ $HAVE_GRAPHICS -eq 0 ] && [ ! -f "$SESSION_FILE1" ] ; then
++ print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: No $SESSION_FILE1: You need to install 'gdm' and 'systemd' package"
++ exit 1
++ fi
++ if [ $HAVE_GRAPHICS -eq 1 ] ; then
++ if [ ! -f "$SESSION_FILE2" ] ; then
++ print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: No $SESSION_FILE2: You need to install 'systemd' package"
++ exit 1
++ fi
++ if [ ! -f /usr/sbin/gdm ] ; then
++ print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: No /usr/sbin/gdm: Currently only gdm is supported for auto login."
++ exit 1
++ fi
++ fi
++ create_test_user
++ create_autologin_gdm
++ create_xdg_autostart
++ LOGIN_USER=$TEST_USER
++ LOGIN_HOME=$TEST_USER_HOME
++ else
++ rm -f $TEST_USER_HOME/.config/autostart/$AUTOSTART_DESKTOP_FILE
++ fi
++
++ if [ ! -f $LOGIN_HOME/.config/gnome-initial-setup-done ] ; then
++ mkdir -p $LOGIN_HOME/.config
++ 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
++ else
++ mkdir -p /var/lib/AccountsService/users
++ cat > /var/lib/AccountsService/users/$LOGIN_USER << _EOF_AS_CONF
++[User]
++Language=$SESSION_LANG
++XSession=gnome
++SystemAccount=$IS_SYSTEM_ACCOUNT
++_EOF_AS_CONF
++ fi
++
++ # Prevent from launching a XDG dialog
++ XDG_LOCALE_FILE="$LOGIN_HOME/.config/user-dirs.locale"
++ if [ -f $XDG_LOCALE_FILE ] ; then
++ XDG_LANG_ORIG=`cat $XDG_LOCALE_FILE`
++ XDG_LANG_NEW=`echo $SESSION_LANG | sed -e 's/\(.*\)\..*/\1/'`
++ if [ "$XDG_LANG_ORIG" != "$XDG_LANG_NEW" ] ; then
++ echo "# Overriding XDG locale $XDG_LANG_ORIG with $XDG_LANG_NEW"
++ echo "$XDG_LANG_NEW" > $XDG_LOCALE_FILE
++ fi
++ fi
++
++ if [ $ENABLED_SYSTEMD -eq 1 ] && [ $SESSION_IS_GNOME -eq 1 ] ; then
++ return
++ fi
++ # `su` command does not run loginctl
++ export XDG_SESSION_TYPE='x11'
++ export XDG_SESSION_CLASS=user
++ # `su` command does not get focus in events without this variable.
++ # Need to restart sshd after set "PermitRootLogin yes" in sshd_config
++ if [ "x$XDG_RUNTIME_DIR" = x ] ; then
++ export XDG_RUNTIME_DIR="/run/user/$UID"
++ is_root_login=`grep "^PermitRootLogin" /etc/ssh/sshd_config | grep yes`
++ if [ "x$ANSIBLE" != x ] && [ "x$is_root_login" = x ] ; then
++ print_log -e "${RED}FAIL${NC}: No permission to get focus-in events in GtkWindow with ansible"
++ echo "su command does not configure necessary login info " \
++ "with systemd and GtkWindow cannot receive focus-events " \
++ "when ibus-desktop-testing-runner is executed by " \
++ "ansible-playbook." >> $TEST_LOG
++ echo "Enabling root login via sshd, restarting sshd, set " \
++ "XDG_RUNTIME_DIR can resolve the problem under " \
++ "ansible-playbook." >> $TEST_LOG
++ exit 1
++ fi
++ fi
++ # Do we need XDG_SESSION_ID and XDG_SEAT?
++ #export XDG_CONFIG_DIRS=/etc/xdg
++ #export XDG_SESSION_ID=10
++ #export XDG_SESSION_DESKTOP=gnome
++ #export XDG_SEAT=seat0
++}
++
++
++run_dbus_daemon()
++{
++ if [ $ENABLED_SYSTEMD -eq 1 ] && [ $SESSION_IS_GNOME -eq 1 ] ; then
++ return
++ fi
++ # Use dbus-launch --exit-with-session later instead of --sh-syntax
++ # GNOME uses a unix:abstract address and it effects gsettings set values
++ # in each test case.
++ # TODO: Should we comment out this line?
++ export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$UID/bus"
++}
++
++
++init_gnome()
++{
++ if test $SESSION_IS_GNOME -ne 1 ; then
++ print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: Should not be called"
++ exit 1
++ fi
++ LOGIN_USER=$USER
++ if test $ENABLED_SYSTEMD -eq 1 ; then
++ LOGIN_USER=$TEST_USER
++ fi
++ # gsettings set command needs dconf-service with the same $DISPLAY
++ pkill dconf-service
++ # G_MESSAGES_DEBUG=all or G_MESSAGES_DEBUG=GLib-GIO-DEBUG would append
++ # debug messages to gsettings output and could not get the result correctly.
++ backup_G_MESSAGES_DEBUG="$G_MESSAGES_DEBUG"
++ unset G_MESSAGES_DEBUG
++ # Disable Tour dialog to get focus
++ GET_WELCOME_DIALOG="gsettings get org.gnome.shell welcome-dialog-last-shown-version"
++ if test $LOGIN_USER = $USER ; then
++ V=`dbus-run-session $GET_WELCOME_DIALOG`
++ else
++ V=`sudo -u $LOGIN_USER dbus-run-session $GET_WELCOME_DIALOG`
++ fi
++ if [ x"$V" = x"''" ] ; then
++ SET_WELCOME_DIALOG="gsettings set org.gnome.shell welcome-dialog-last-shown-version '100'"
++ if test $LOGIN_USER = $USER ; then
++ dbus-run-session $SET_WELCOME_DIALOG
++ else
++ sudo -u $LOGIN_USER dbus-run-session $SET_WELCOME_DIALOG
++ fi
++ fi
++ # gnome-shell now starts overview mode by login.
++ # https://extensions.gnome.org/extension/4099/no-overview/
++ NO_SYS_DIR=/usr/share/gnome-shell/extensions/no-overview@fthx
++ if test $LOGIN_USER = $USER ; then
++ NO_USER_DIR=$HOME/.local/share/gnome-shell/extensions/no-overview@fthx
++ else
++ NO_USER_DIR=$TEST_USER_HOME/.local/share/gnome-shell/extensions/no-overview@fthx
++ fi
++ if [ ! -d $NO_SYS_DIR ] && [ ! -d $NO_USER_DIR ] ; then
++ mkdir -p "`dirname $NO_USER_DIR`"
++ cp -R "no-overview@fthx" "`dirname $NO_USER_DIR`"
++ if test $LOGIN_USER = $USER ; then
++ chown -R $LOGIN_USER $HOME/.local
++ else
++ chown -R $LOGIN_USER $TEST_USER_HOME/.local
++ fi
++ fi
++ if [ $LOGIN_USER != $USER ] ; then
++ SHELL_SERVICE_FILE="org.gnome.Shell@wayland.service"
++ SYSTEMD_USER_DIR="$TEST_USER_HOME/.config/systemd/user"
++ if test $HAVE_GRAPHICS -ne 1 ; then
++ if test ! -f "$SYSTEMD_USER_DIR/$SHELL_SERVICE_FILE" ; then
++ mkdir -p "$SYSTEMD_USER_DIR"
++ pushd "$SYSTEMD_USER_DIR"
++ 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
++ chown -R $LOGIN_USER "$TEST_USER_HOME/.config"
++ fi
++ else
++ if test -f "$SYSTEMD_USER_DIR/$SHELL_SERVICE_FILE" ; then
++ rm "$SYSTEMD_USER_DIR/$SHELL_SERVICE_FILE"
++ fi
++ fi
++ fi
++ GET_DISABLE_USER_EX="gsettings get org.gnome.shell disable-user-extensions"
++ if test $LOGIN_USER = $USER ; then
++ V=`dbus-run-session $GET_DISABLE_USER_EX`
++ else
++ V=`sudo -u $LOGIN_USER dbus-run-session $GET_DISABLE_USER_EX`
++ fi
++ if [ x"$V" = x"true" ] ; then
++ SET_DISABLE_USER_EX="gsettings set org.gnome.shell disable-user-extensions false"
++ if test $LOGIN_USER = $USER ; then
++ dbus-run-session $SET_DISABLE_USER_EX
++ else
++ sudo -u $LOGIN_USER dbus-run-session $SET_DISABLE_USER_EX
++ fi
++ fi
++ GET_ENABLED_EXS="gsettings get org.gnome.shell enabled-extensions"
++ if test $LOGIN_USER = $USER ; then
++ V=`dbus-run-session $GET_ENABLED_EXS`
++ else
++ V=`sudo -u $LOGIN_USER dbus-run-session $GET_ENABLED_EXS`
++ fi
++ echo "$V" | grep "no-overview" > /dev/null
++ V2=$?
++ if [ $V2 -ne 0 ] ; then
++ V3=`echo "$V" | sed -e 's/@as //' -e 's/\[//' -e 's/\]//'`
++ if [ x"$V3" = x"''" ] || [ x"$V3" = x"" ]; then
++ V4="['no-overview@fthx']"
++ else
++ V4="[$V3,'no-overview@fthx']"
++ fi
++ SET_ENABLED_EXS="gsettings set org.gnome.shell enabled-extensions \"$V4\""
++ if test $LOGIN_USER = $USER ; then
++ eval dbus-run-session $SET_ENABLED_EXS
++ else
++ eval sudo -u $LOGIN_USER dbus-run-session $SET_ENABLED_EXS
++ fi
++ fi
++ # Disable notify dialog when the disk usage is low.
++ SET_NOTIFY_DISK="gsettings set org.gnome.settings-daemon.plugins.housekeeping free-size-gb-no-notify 0"
++ if test $LOGIN_USER = $USER ; then
++ eval dbus-run-session $SET_NOTIFY_DISK
++ else
++ eval sudo -u $LOGIN_USER dbus-run-session $SET_NOTIFY_DISK
++ fi
++ if [ x"$backup_G_MESSAGES_DEBUG" != x ] ; then
++ export G_MESSAGES_DEBUG="$backup_G_MESSAGES_DEBUG"
++ fi
++}
++
++
++operate_desktop_with_systemd()
++{
++ SESSION=gnome-headless-session
++ COMMAND="$1"
++
++ #if test $HAVE_GRAPHICS -eq 1 ; then
++ case "$COMMAND" in
++ "start") systemctl isolate graphical.target
++ echo ""
++ ;;
++ "stop") init 3;;
++ "") print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: Wrong command $COMMAND"
++ exit 1;;
++ esac
++ #else
++ # setenforce 0
++ # systemctl $COMMAND ${SESSION}@${TEST_USER}
++ #fi
++ case "$COMMAND" in
++ "start") sleep 30;;
++ "") ;;
++ esac
++ #if test $HAVE_GRAPHICS -eq 1 ; then
++ systemctl status --no-pager graphical.target
++ #else
++ # systemctl status --no-pager ${SESSION}@${TEST_USER}
++ #fi
++ ps -ef | grep X
++ ps -ef | grep session
++ ps -ef | grep ibus
++}
++
++
++run_session()
++{
++ if [ $ENABLED_SYSTEMD -eq 1 ] && [ $SESSION_IS_GNOME -eq 1 ] ; then
++ init_gnome
++ operate_desktop_with_systemd "start"
++ return
++ fi
++ export DISPLAY=:99.0
++ if test $HAVE_GRAPHICS -eq 1 ; then
++ /usr/libexec/Xorg.wrap -noreset +extension GLX +extension RANDR +extension RENDER -logfile ./xorg.log -config ./xorg.conf -configdir . $DISPLAY &
++ else
++ /usr/bin/Xvfb $DISPLAY -noreset +extension GLX +extension RANDR +extension RENDER -screen 0 1280x1024x24 &
++ fi
++ PID_XORG=$!
++ sleep 1
++ # init_gnome need to be called with $DISPLAY before gnome-session is called
++ if [ $SESSION_IS_GNOME -eq 1 ] ; then
++ init_gnome
++ fi
++ echo "Running $SESSION_COMMAND with $USER and LANG=$SESSION_LANG in `tty`"
++ if test x"$SESSION_LANG" = x ; then
++ $SESSION_COMMAND &
++ else
++ env LANG=$SESSION_LANG $SESSION_COMMAND &
++ fi
++ PID_GNOME_SESSION=$!
++ sleep 30
++
++ IBUS_ARGS="--verbose --panel disable"
++ # gnome-shell 42 checks if org.freedesktop.IBus.session.GNOME.service
++ # systemd file is available with org.freedesktop.systemd1.Manager.GetUnit
++ # D-Bus method, which is provided by IBus 1.5.26, and if the file
++ # is available, gnome-shell no longer launch ibus-daemon
++ # because gnome-shell assumes gnome-session would launch ibus-daemon
++ # with org.freedesktop.systemd1.Manager.StartUnit D-Bus method.
++ # But actually gnome-session failed to launch ibus-daemon
++ # because the IBus systemd file depends on gnome-session.target
++ # but this CI launches gnome-session directly.
++ #
++ # So ibus-dameon is now always called here after gnome-shell fails to
++ # launch ibus-daemon.
++ # It may be better this CI launches GDM autologin to run gnome-session
++ # with gnome-session.target systemd file.
++ # But `systemctl start gdm` terminates the parent script forcibly
++ # and the script cannot get the CI result.
++ if test $VERBOSE -eq 1 ; then
++ ibus-daemon $IBUS_ARGS &
++ else
++ ibus-daemon $IBUS_ARGS --daemonize
++ fi
++ sleep 3
++ ps -ef | grep ibus
++}
++
++
++count_case_result()
++{
++ retval=$1
++ pass=$2
++ fail=$3
++
++ if test $retval -eq 0 ; then
++ pass=`expr $pass + 1`
++ else
++ fail=`expr $fail + 1`
++ fi
++ echo $pass $fail
++}
++
++
++echo_case_result()
++{
++ retval=$1
++ tst=$2
++ subtst=${3:-''}
++
++ if test $retval -eq 0 ; then
++ echo "PASS: $tst $subtst" >>$TEST_LOG
++ else
++ echo "FAIL: $tst $subtst" >>$TEST_LOG
++ fi
++}
++
++
++wait_for_systemd_autostart()
++{
++ PS_IBUS="ps -ef | grep ibus-desktop-testing | grep autostart | grep -v grep"
++ i=0
++ while test 1 ; do
++ R=`eval "$PS_IBUS"`
++ if test x"$R" != x ; then
++ break;
++ fi
++ if test $i -ge 12 ; then
++ print_log -e "${RED}FAIL${NC}: Timeout to run ibus-desktop-testing-autostart"
++ return
++ fi
++ i=`expr $i + 1`
++ sleep 5
++ done
++ print_log -e "Start ibus-desktop-testing-autostart"
++ i=0
++ while test 1 ; do
++ R=`eval "$PS_IBUS"`
++ if test x"$R" = x ; then
++ break;
++ fi
++ if test $i -ge $TIMEOUT ; then
++ print_log -e "${RED}FAIL${NC}: Timeout to exit ibus-desktop-testing-autostart"
++ return
++ fi
++ i=`expr $i + 1`
++ sleep 5
++ done
++ print_log -e "Exit ibus-desktop-testing-autostart"
++}
++
++run_direct_test_cases()
++{
++ pass=0
++ fail=0
++ for tst in $TESTS; do
++ ENVS=
++ if test -f $SRCDIR/${tst}.env ; then
++ ENVS="`cat $SRCDIR/${tst}.env`"
++ fi
++ if test x"$ENVS" = x ; then
++ $BUILDDIR/$tst $SRCDIR 2>>$TEST_LOG 1>>$TEST_LOG
++ retval=$?
++ read pass fail << EOF_COUNT
++ `count_case_result $retval $pass $fail`
++EOF_COUNT
++ echo_case_result $retval $tst
++ CACHE_FILES=`ls *.cache`
++ if [ x"$CACHE_FILES" != x ] ; then
++ echo "# Clean $CACHE_FILES" >>$TEST_LOG
++ rm $CACHE_FILES
++ fi
++ else
++ i=1
++ # Deleted for var in "$ENVS" because IFS=$'\n' is not supported
++ # in POSIX sh
++ while read e ; do
++ first=`echo "$e" | grep '^#'`
++ if test x"$first" = x"#" ; then
++ continue
++ fi
++ echo "# Starting $e $BUILDDIR/$tst $SRCDIR" >>$TEST_LOG
++ env $e $BUILDDIR/$tst $SRCDIR 2>>$TEST_LOG 1>>$TEST_LOG
++ retval=$?
++ echo "# Finished $e $BUILDDIR/$tst $SRCDIR with $retval" >>$TEST_LOG
++ read pass fail << EOF_COUNT
++ `count_case_result $retval $pass $fail`
++EOF_COUNT
++ echo_case_result $retval $tst $e
++ CACHE_FILES=`ls *.cache`
++ if [ x"$CACHE_FILES" != x ] ; then
++ echo "# Clean $CACHE_FILES" >>$TEST_LOG
++ rm $CACHE_FILES
++ fi
++ i=`expr $i + 1`
++ done << EOF_ENVS
++ `echo "$ENVS"`
++EOF_ENVS
++ fi
++ done
++ echo $pass $fail
++}
++
++
++run_gnome_desktop_testing_runner()
++{
++ pass=0
++ fail=0
++ if [ x"$TESTS" = x ] ; then
++ TESTS='ibus'
++ fi
++ if echo $PROGNAME | grep -q autostart ; then
++ export IBUS_DAEMON_WITH_SYSTEMD=1
++ fi
++ for tst in $TESTS; do
++ tst_dir="$TEST_CASE_DIR/$tst"
++ if [ ! -d "$tst_dir" ] ; then
++ print_log -e "${RED}FAIL${NC}: Not found %tst_dir"
++ fail=1
++ continue
++ fi
++ gnome-desktop-testing-runner --timeout=$TIMEOUT $tst \
++ 2>>$TEST_LOG 1>>$TEST_LOG
++ retval=$?
++ read pass fail << EOF
++ `count_case_result $retval $pass $fail`
++EOF
++ done
++ child_pass=`grep '^PASS:' $TEST_LOG | wc -l`
++ child_fail=`grep '^FAIL:' $TEST_LOG | wc -l`
++ if [ $child_pass -ne 0 ] || [ $child_fail -ne 0 ] ; then
++ pass=$child_pass
++ if [ $child_fail -ne 0 ] ; then
++ fail=`expr $child_fail / 2`
++ else
++ fail=0
++ fi
++ fi
++ echo $pass $fail
++}
++
++
++run_test_suite()
++{
++ print_log -e "Start test suite `date '+%F %H:%M:%S:%N'`"
++ if echo $PROGNAME | grep -q runner ; then
++ if [ $ENABLED_SYSTEMD -eq 1 ] && [ $SESSION_IS_GNOME -eq 1 ] ; then
++ wait_for_systemd_autostart
++ return
++ fi
++ if ps -ef | grep X | grep -q wayland ; then
++ # Expect GTK_IM_MODULE=wayland by default
++ :
++ else
++ export GTK_IM_MODULE=ibus
++ fi
++ else
++ if test x"$XDG_SESSION_TYPE" = xwayland ; then
++ :
++ else
++ export GTK_IM_MODULE=ibus
++ fi
++ fi
++ pass=0
++ fail=0
++ export IBUS_COMPOSE_CACHE_DIR=$PWD
++ if test x"$TESTING_RUNNER" = x ; then
++ return
++ fi
++ case $TESTING_RUNNER in
++ default)
++ # Get only the last value with do-while.
++ read pass fail << EOF_RUNNER
++ `run_direct_test_cases`
++EOF_RUNNER
++ ;;
++ gnome)
++ read pass fail << EOF_RUNNER
++ `run_gnome_desktop_testing_runner`
++EOF_RUNNER
++ ;;
++ esac
++ echo ""
++ print_log -e "End test suite `date '+%F %H:%M:%S:%N'`"
++ # Fedora CI assumes the test is failed even if $fail is 0.
++ if [ $pass -ne 0 ] ; then
++ print_log -e "${GREEN}PASS${NC}: $pass"
++ fi
++ if [ $fail -ne 0 ] ; then
++ print_log -e "${RED}FAIL${NC}: $fail"
++ fi
++}
++
++
++finit()
++{
++ if test $PID_XORG -ne 0 ; then
++ echo "# Killing left gnome-session and Xorg"
++ kill $PID_GNOME_SESSION $PID_XORG
++ ibus exit
++ SUSER=`echo "$USER" | cut -c 1-7`
++ LEFT_CALENDAR=`ps -ef | grep gnome-shell-calendar-server | grep $SUSER | grep -v grep`
++ if test x"$LEFT_CALENDAR" != x ; then
++ echo "# Killing left gnome-shell-calendar-server"
++ echo "$LEFT_CALENDAR"
++ echo "$LEFT_CALENDAR" | awk '{print $2}' | xargs kill
++ fi
++ fi
++ if echo $PROGNAME | grep -q runner ; then
++ if [ $ENABLED_SYSTEMD -eq 1 ] && [ $SESSION_IS_GNOME -eq 1 ] ; then
++ operate_desktop_with_systemd "stop"
++ fi
++ fi
++
++ echo ""
++ if test -f $TEST_LOG ; then
++ if [ $TEST_LOG_STDOUT -eq 1 ] ; then
++ cat $TEST_LOG
++ else
++ echo "# See $TEST_LOG"
++ fi
++ fi
++ echo "# Finished $PROGNAME testing"
++}
+diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in
+index 1ac2dfc8..1d82bc76 100755
+--- a/src/tests/ibus-desktop-testing-runner.in
++++ b/src/tests/ibus-desktop-testing-runner.in
+@@ -4,7 +4,7 @@
+ #
+ # ibus - The Input Bus
+ #
+-# Copyright (c) 2018-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
++# Copyright (c) 2018-2024 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ # Copyright (c) 2018 Red Hat, Inc.
+ #
+ # This program is free software; you can redistribute it and/or modify
+@@ -22,58 +22,39 @@
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ # This test runs /usr/bin/ibus-daemon after install ibus
+-#
+-# # init 3
+-# Login as root
+-# # /root/ibus/tests/test-console.sh --tests ibus-compose \
+-# --builddir /root/ibus/src/tests --srcdir /root/ibus/src/tests
+-
+-# POSIX sh has no 'echo -e'
+-: ${ECHO:='/usr/bin/echo'}
+-# POSIX sh has $UID
+-# DASH saves the graves in '``' as characters not to be extracted
+-: ${UID:=`id -u`}
+
+
+ PROGNAME=`basename $0`
+-VERSION=0.3
+-DISPLAY=:99.0
+-BUILDDIR="."
+-SRCDIR="."
++TEST_CASE_DIR="@INSTALLEDDIR@"
++MODULE_SH='ibus-desktop-testing-module'
++MODULE_SH_PATH="@LIBEXECDIR@/$MODULE_SH"
++AUTOSTART_DESKTOP_DIR="@DATADIR@/ibus/tests"
+ TEST_LOG="test-suite.log"
+-TEST_LOG_STDOUT=0
+-RESULT_LOG=""
+-SCREEN_LOG=""
+-HAVE_GRAPHICS=1
+-VERBOSE=0
+-DESKTOP_COMMAND="dbus-launch --exit-with-session gnome-session"
+-PID_XORG=0
+-PID_GNOME_SESSION=0
+ TESTING_RUNNER="default"
+-TESTS=""
+-TIMEOUT=300
+-GREEN='\033[0;32m'
+-RED='\033[0;31m'
+-NC='\033[0m'
+
+
+-print_log()
+-{
+- if [ x"$RESULT_LOG" != x ] ; then
+- # avoid 'echo -e' before call 'sed'.
+- if [ x"$1" = x'-e' ] ; then
+- shift
+- fi
+- NO_ESCAPE=`echo "$@" | sed -e 's/\\\033\\[0;3.m//g' -e 's/\\\033\\[0m//g'`
+- $ECHO $NO_ESCAPE >> $RESULT_LOG
+- else
+- $ECHO "$@"
+- fi
+-}
++if test -f $MODULE_SH_PATH ; then
++ . $MODULE_SH_PATH
++elif test -f $(dirname $0)/$MODULE_SH ; then
++ . $(dirname $0)/$MODULE_SH
++else
++ echo "Not found $MODULE_SH"
++ exit 1
++fi
+
+
+ usage()
+ {
++ command=""
++ for element in $SESSION_COMMAND; do
++ if test x"$element" = x; then
++ continue
++ fi
++ if echo "$element" | grep -q -E "^-" ; then
++ continue
++ fi
++ command="$element"
++ done
+ $ECHO -e \
+ "This test runs /usr/bin/ibus-daemon after install ibus\n" \
+ "$PROGNAME [OPTIONS…]\n" \
+@@ -83,429 +64,37 @@ usage()
+ "-v, --version Show version\n" \
+ "-b, --builddir=BUILDDIR Set the BUILDDIR\n" \
+ "-s, --srcdir=SOURCEDIR Set the SOURCEDIR\n" \
+-"-c, --no-graphics Use Xvfb instead of Xorg\n" \
++"-c, --no-graphics Use Xvfb instead of Xorg or Wayland\n" \
+ "-V, --verbose Verbose log for ibus-daemon\n" \
+-"-d, --desktop=DESKTOP Run DESTKTOP. The default is gnome-session.\n" \
+-" Suffix '-with-dbus' can run DESKTOP with dbus session." \
+-" E.g. --desktop=mutter-with-dbus" \
++"-d, --session=SESSION Run SESSION. The default is ${command}.\n" \
++" Suffix '-with-dbus' can run SESSION with dbus session.\n" \
++" E.g. --session=${command}-with-dbus\n" \
++"-l, --lang=LANG Run SESSION with LANG\n" \
+ "-t, --tests=\"TESTS...\" Run TESTS programs which is separated by space\n" \
+ "-r, --runner=RUNNER Run TESTS programs with a test RUNNER.\n" \
+-" RUNNDER = gnome or default.\n" \
+-" default is an embedded runner.\n" \
++" RUNNDER = 'gnome' or 'default'.\n" \
++" 'default' is an embedded runner.\n" \
++"-i, --no-systemd Run gnome-seesion directly withoout systemd\n" \
++" and login manager for legacy GNOME and this\n" \
++" mode does not support Wayland.\n" \
+ "-T, --timeout=TIMEOUT Set timeout (default TIMEOUT is 300 sec).\n" \
+-"-o, --output=OUTPUT_FILE OUtput the log to OUTPUT_FILE\n" \
+-"-O, --result=RESULT_FILE OUtput the result to RESULT_FILE\n" \
+-"-S, --screendump=DUMP_FILE OUtput the screen to DUMP_FILE ('STDOUT' can be stdout)\n" \
++"-o, --output=OUTPUT_FILE Output the log to OUTPUT_FILE\n" \
++" default is $TEST_LOG\n" \
++"-O, --result=RESULT_FILE Output the result to RESULT_FILE\n" \
++" default is stdout\n" \
++"-S, --screendump=DUMP_FILE Output the screen to DUMP_FILE ('STDOUT' can be stdout)\n" \
++"-D, --delete-tests Delete test enviroments and user $TEST_USER\n" \
+ ""
+ }
+
+
+-parse_args()
+-{
+- # This is GNU getopt. "sudo port getopt" in BSD?
+- ARGS=`getopt -o hvb:s:cVd:t:r:T:o:O:S: --long \
+- help,version,builddir:,srcdir:,no-graphics,verbose,desktop:,tests:,runner:,timeout:,output:,result:,screendump:\
+- -- "$@"`;
+- eval set -- "$ARGS"
+- while [ 1 ] ; do
+- case "$1" in
+- -h | --help ) usage; exit 0;;
+- -v | --version ) $ECHO -e "$VERSION"; exit 0;;
+- -b | --builddir ) BUILDDIR="$2"; shift 2;;
+- -s | --srcdir ) SRCDIR="$2"; shift 2;;
+- -c | --no-graphics ) HAVE_GRAPHICS=0; shift;;
+- -V | --verbose ) VERBOSE=1; shift;;
+- -d | --desktop ) DESKTOP_COMMAND="$2"; shift 2;;
+- -t | --tests ) TESTS="$2"; shift 2;;
+- -r | --runner ) TESTING_RUNNER="$2"; shift 2;;
+- -T | --timeout ) TIMEOUT="$2"; shift 2;;
+- -o | --output ) TEST_LOG="$2"; shift 2;;
+- -O | --result ) RESULT_LOG="$2"; shift 2;;
+- -S | --screendump ) SCREEN_LOG="$2"; shift 2;;
+- -- ) shift; break;;
+- * ) usage; exit 1;;
+- esac
+- done
+- DL='$'
+- echo "$DESKTOP_COMMAND" | grep "\-with\-dbus$DL" > /dev/null
+- HAS_DBUS_SUFFIX=$?
+- if [ $HAS_DBUS_SUFFIX -eq 0 ] ; then
+- DESKTOP_COMMAND=`echo "$DESKTOP_COMMAND" | sed -e 's/-with-dbus$//'`
+- DESKTOP_COMMAND="dbus-launch --exit-with-session $DESKTOP_COMMAND"
+- fi
+-}
+-
+-
+-init_desktop()
+-{
+- if [ "$RESULT_LOG" != "" ] ; then
+- if [ -f $RESULT_LOG ] ; then
+- rm $RESULT_LOG
+- fi
+- fi
+- echo "$TEST_LOG" | grep ':stdout' > /dev/null
+- HAS_STDOUT=$?
+- if [ $HAS_STDOUT -eq 0 ] ; then
+- TEST_LOG=`echo "$TEST_LOG" | sed -e 's|:stdout||'`
+- TEST_LOG_STDOUT=1
+- fi
+- if [ "$TEST_LOG" = "" ] ; then
+- print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: a log file is required to get return value with 'read' command"
+- exit 255
+- elif [ -f $TEST_LOG ] ; then
+- rm $TEST_LOG
+- fi
+- if [ x$FORCE_TEST != x ] ; then
+- RUN_ARGS="$RUN_ARGS --force"
+- fi
+-
+- if [ ! -f $HOME/.config/gnome-initial-setup-done ] ; then
+- IS_SYSTEM_ACCOUNT=false
+- if [ "$USER" = "root" ] ; then
+- IS_SYSTEM_ACCOUNT=true
+- fi
+- if test ! -f /var/lib/AccountsService/users/$USER ; then
+- mkdir -p /var/lib/AccountsService/users
+- cat >> /var/lib/AccountsService/users/$USER << _EOF
+-[User]
+-Language=ja_JP.UTF-8
+-XSession=gnome
+-SystemAccount=$IS_SYSTEM_ACCOUNT
+-_EOF
+- fi
+- mkdir -p $HOME/.config
+- touch $HOME/.config/gnome-initial-setup-done
+- fi
+-
+- # Prevent from launching a XDG dialog
+- XDG_LOCALE_FILE="$HOME/.config/user-dirs.locale"
+- if [ -f $XDG_LOCALE_FILE ] ; then
+- XDG_LANG_ORIG=`cat $XDG_LOCALE_FILE`
+- XDG_LANG_NEW=`echo $LANG | sed -e 's/\(.*\)\..*/\1/'`
+- if [ "$XDG_LANG_ORIG" != "$XDG_LANG_NEW" ] ; then
+- echo "# Overriding XDG locale $XDG_LANG_ORIG with $XDG_LANG_NEW"
+- echo "$XDG_LANG_NEW" > $XDG_LOCALE_FILE
+- fi
+- fi
+- # `su` command does not run loginctl
+- export XDG_SESSION_TYPE='x11'
+- export XDG_SESSION_CLASS=user
+- # `su` command does not get focus in events without this variable.
+- # Need to restart sshd after set "PermitRootLogin yes" in sshd_config
+- if [ "x$XDG_RUNTIME_DIR" = x ] ; then
+- export XDG_RUNTIME_DIR="/run/user/$UID"
+- is_root_login=`grep "^PermitRootLogin" /etc/ssh/sshd_config | grep yes`
+- if [ "x$ANSIBLE" != x ] && [ "x$is_root_login" = x ] ; then
+- print_log -e "${RED}FAIL${NC}: No permission to get focus-in events in GtkWindow with ansible"
+- echo "su command does not configure necessary login info " \
+- "with systemd and GtkWindow cannot receive focus-events " \
+- "when ibus-desktop-testing-runner is executed by " \
+- "ansible-playbook." >> $TEST_LOG
+- echo "Enabling root login via sshd, restarting sshd, set " \
+- "XDG_RUNTIME_DIR can resolve the problem under " \
+- "ansible-playbook." >> $TEST_LOG
+- exit 255
+- fi
+- fi
+- # Do we need XDG_SESSION_ID and XDG_SEAT?
+- #export XDG_CONFIG_DIRS=/etc/xdg
+- #export XDG_SESSION_ID=10
+- #export XDG_SESSION_DESKTOP=gnome
+- #export XDG_SEAT=seat0
+-}
+-
+-
+-run_dbus_daemon()
+-{
+- # Use dbus-launch --exit-with-session later instead of --sh-syntax
+- # GNOME uses a unix:abstract address and it effects gsettings set values
+- # in each test case.
+- # TODO: Should we comment out this line?
+- export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$UID/bus"
+-}
+-
+-
+-init_gnome()
+-{
+- # gsettings set command needs dconf-service with the same $DISPLAY
+- pkill dconf-service
+- # G_MESSAGES_DEBUG=all or G_MESSAGES_DEBUG=GLib-GIO-DEBUG would append
+- # debug messages to gsettings output and could not get the result correctly.
+- backup_G_MESSAGES_DEBUG="$G_MESSAGES_DEBUG"
+- unset G_MESSAGES_DEBUG
+- # Disable Tour dialog to get focus
+- V=`gsettings get org.gnome.shell welcome-dialog-last-shown-version`
+- if [ x"$V" = x"''" ] ; then
+- gsettings set org.gnome.shell welcome-dialog-last-shown-version '100'
+- fi
+- # gnome-shell now starts overview mode by login.
+- # https://extensions.gnome.org/extension/4099/no-overview/
+- NO_SYS_DIR=/usr/share/gnome-shell/extensions/no-overview@fthx
+- NO_USER_DIR=$HOME/.local/share/gnome-shell/extensions/no-overview@fthx
+- if [ ! -d $NO_SYS_DIR ] && [ ! -d $NO_USER_DIR ] ; then
+- mkdir -p "`dirname $NO_USER_DIR`"
+- cp -R "no-overview@fthx" "`dirname $NO_USER_DIR`"
+- fi
+- V=`gsettings get org.gnome.shell disable-user-extensions`
+- if [ x"$V" = x"true" ] ; then
+- gsettings set org.gnome.shell disable-user-extensions false
+- fi
+- V=`gsettings get org.gnome.shell enabled-extensions`
+- echo "$V" | grep "no-overview" > /dev/null
+- V2=$?
+- if [ $V2 -ne 0 ] ; then
+- V3=`echo "$V" | sed -e 's/@as //' -e 's/\[//' -e 's/\]//'`
+- if [ x"$V3" = x"''" ] || [ x"$V3" = x"" ]; then
+- V4="['no-overview@fthx']"
+- else
+- V4="[$V3, 'no-overview@fthx']"
+- fi
+- gsettings set org.gnome.shell enabled-extensions "$V4"
+- fi
+- if [ x"$backup_G_MESSAGES_DEBUG" != x ] ; then
+- export G_MESSAGES_DEBUG="$backup_G_MESSAGES_DEBUG"
+- fi
+-}
+-
+-
+-run_desktop()
+-{
+- echo "$DESKTOP_COMMAND" | grep gnome-session > /dev/null
+- HAS_GNOME=$?
+- export DISPLAY=$DISPLAY
+- if test $HAVE_GRAPHICS -eq 1 ; then
+- /usr/libexec/Xorg.wrap -noreset +extension GLX +extension RANDR +extension RENDER -logfile ./xorg.log -config ./xorg.conf -configdir . $DISPLAY &
+- else
+- /usr/bin/Xvfb $DISPLAY -noreset +extension GLX +extension RANDR +extension RENDER -screen 0 1280x1024x24 &
+- fi
+- PID_XORG=$!
+- sleep 1
+- # init_gnome need to be called with $DISPLAY before gnome-session is called
+- if [ $HAS_GNOME -eq 0 ] ; then
+- init_gnome
+- fi
+- echo "Running $DESKTOP_COMMAND with $USER in `tty`"
+- $DESKTOP_COMMAND &
+- PID_GNOME_SESSION=$!
+- sleep 30
+-
+- IBUS_ARGS="--verbose --panel disable"
+- # gnome-shell 42 checks if org.freedesktop.IBus.session.GNOME.service
+- # systemd file is available with org.freedesktop.systemd1.Manager.GetUnit
+- # D-Bus method, which is provided by IBus 1.5.26, and if the file
+- # is available, gnome-shell no longer launch ibus-daemon
+- # because gnome-shell assumes gnome-session would launch ibus-daemon
+- # with org.freedesktop.systemd1.Manager.StartUnit D-Bus method.
+- # But actually gnome-session failed to launch ibus-daemon
+- # because the IBus systemd file depends on gnome-session.target
+- # but this CI launches gnome-session directly.
+- #
+- # So ibus-dameon is now always called here after gnome-shell fails to
+- # launch ibus-daemon.
+- # It may be better this CI launches GDM autologin to run gnome-session
+- # with gnome-session.target systemd file.
+- # But `systemctl start gdm` terminates the parent script forcibly
+- # and the script cannot get the CI result.
+- if test $VERBOSE -eq 1 ; then
+- ibus-daemon $IBUS_ARGS &
+- else
+- ibus-daemon $IBUS_ARGS --daemonize
+- fi
+- sleep 3
+- if test $VERBOSE -eq 1 ; then
+- ps -ef | grep ibus
+- fi
+-}
+-
+-
+-count_case_result()
+-{
+- retval=$1
+- pass=$2
+- fail=$3
+-
+- if test $retval -eq 0 ; then
+- pass=`expr $pass + 1`
+- else
+- fail=`expr $fail + 1`
+- fi
+- echo $pass $fail
+-}
+-
+-
+-echo_case_result()
+-{
+- retval=$1
+- tst=$2
+- subtst=${3:-''}
+-
+- if test $retval -eq 0 ; then
+- echo "PASS: $tst $subtst" >>$TEST_LOG
+- else
+- echo "FAIL: $tst $subtst" >>$TEST_LOG
+- fi
+-}
+-
+-
+-run_direct_test_cases()
+-{
+- pass=0
+- fail=0
+- for tst in $TESTS; do
+- ENVS=
+- if test -f $SRCDIR/${tst}.env ; then
+- ENVS="`cat $SRCDIR/${tst}.env`"
+- fi
+- if test x"$ENVS" = x ; then
+- $BUILDDIR/$tst $SRCDIR 2>>$TEST_LOG 1>>$TEST_LOG
+- retval=$?
+- read pass fail << EOF_COUNT
+- `count_case_result $retval $pass $fail`
+-EOF_COUNT
+- echo_case_result $retval $tst
+- CACHE_FILES=`ls *.cache`
+- if [ x"$CACHE_FILES" != x ] ; then
+- echo "# Clean $CACHE_FILES" >>$TEST_LOG
+- rm $CACHE_FILES
+- fi
+- else
+- i=1
+- # Deleted for var in "$ENVS" because IFS=$'\n' is not supported
+- # in POSIX sh
+- while read e ; do
+- first=`echo "$e" | grep '^#'`
+- if test x"$first" = x"#" ; then
+- continue
+- fi
+- echo "# Starting $e $BUILDDIR/$tst $SRCDIR" >>$TEST_LOG
+- env $e $BUILDDIR/$tst $SRCDIR 2>>$TEST_LOG 1>>$TEST_LOG
+- retval=$?
+- echo "# Finished $e $BUILDDIR/$tst $SRCDIR with $retval" >>$TEST_LOG
+- read pass fail << EOF_COUNT
+- `count_case_result $retval $pass $fail`
+-EOF_COUNT
+- echo_case_result $retval $tst $e
+- CACHE_FILES=`ls *.cache`
+- if [ x"$CACHE_FILES" != x ] ; then
+- echo "# Clean $CACHE_FILES" >>$TEST_LOG
+- rm $CACHE_FILES
+- fi
+- i=`expr $i + 1`
+- done << EOF_ENVS
+- `echo "$ENVS"`
+-EOF_ENVS
+- fi
+- done
+- echo $pass $fail
+-}
+-
+-
+-run_gnome_desktop_testing_runner()
+-{
+- pass=0
+- fail=0
+- if [ x"$TESTS" = x ] ; then
+- TESTS='ibus'
+- fi
+- for tst in $TESTS; do
+- tst_dir="@INSTALLEDDIR@/$tst"
+- if [ ! -d "$tst_dir" ] ; then
+- print_log -e "${RED}FAIL${NC}: Not found %tst_dir"
+- fail=1
+- continue
+- fi
+- gnome-desktop-testing-runner --timeout=$TIMEOUT $tst \
+- 2>>$TEST_LOG 1>>$TEST_LOG
+- retval=$?
+- read pass fail << EOF
+- `count_case_result $retval $pass $fail`
+-EOF
+- done
+- child_pass=`grep '^PASS:' $TEST_LOG | wc -l`
+- child_fail=`grep '^FAIL:' $TEST_LOG | wc -l`
+- if [ $child_pass -ne 0 ] || [ $child_fail -ne 0 ] ; then
+- pass=$child_pass
+- if [ $child_fail -ne 0 ] ; then
+- fail=`expr $child_fail / 2`
+- else
+- fail=0
+- fi
+- fi
+- echo $pass $fail
+-}
+-
+-
+-run_test_suite()
+-{
+- pass=0
+- fail=0
+- export GTK_IM_MODULE=ibus
+- export IBUS_COMPOSE_CACHE_DIR=$PWD
+- if [ x"$TESTING_RUNNER" = x ] ; then
+- TESTING_RUNNER="default"
+- fi
+- case $TESTING_RUNNER in
+- default)
+- # Get only the last value with do-while.
+- read pass fail << EOF_RUNNER
+- `run_direct_test_cases`
+-EOF_RUNNER
+- ;;
+- gnome)
+- read pass fail << EOF_RUNNER
+- `run_gnome_desktop_testing_runner`
+-EOF_RUNNER
+- ;;
+- esac
+- echo ""
+- # Fedora CI assumes the test is failed even if $fail is 0.
+- if [ $pass -ne 0 ] ; then
+- print_log -e "${GREEN}PASS${NC}: $pass"
+- fi
+- if [ $fail -ne 0 ] ; then
+- print_log -e "${RED}FAIL${NC}: $fail"
+- fi
+- echo ""
+- if [ $TEST_LOG_STDOUT -eq 1 ] ; then
+- cat $TEST_LOG
+- else
+- echo "# See $TEST_LOG"
+- fi
+-}
+-
+-
+-finit()
+-{
+- echo "# Killing left gnome-session and Xorg"
+- kill $PID_GNOME_SESSION $PID_XORG
+- ibus exit
+- SUSER=`echo "$USER" | cut -c 1-7`
+- LEFT_CALENDAR=`ps -ef | grep gnome-shell-calendar-server | grep $SUSER | grep -v grep`
+- if [ x"$LEFT_CALENDAR" != x ] ; then
+- echo "# Killing left gnome-shell-calendar-server"
+- echo "$LEFT_CALENDAR"
+- echo "$LEFT_CALENDAR" | awk '{print $2}' | xargs kill
+- fi
+-
+- echo "# Finished $PROGNAME testing"
+-}
+-
+-
+ main()
+ {
+ parse_args "$@"
+- init_desktop
++ init_session
+ run_dbus_daemon 2>>$TEST_LOG 1>>$TEST_LOG
+- run_desktop 2>>$TEST_LOG 1>>$TEST_LOG
+- if [ x"$SCREEN_LOG" != x ] ; then
+- SCREEN_PNG="`date '+%Y%m%d%H%M%S'`.png"
+- gnome-screenshot --file=$SCREEN_PNG
+- if [ x"$SCREEN_LOG" = xSTDOUT ] ; then
+- base64 $SCREEN_PNG
+- else
+- base64 $SCREEN_PNG > $SCREEN_LOG
+- fi
+- fi
++ run_session 2>>$TEST_LOG 1>>$TEST_LOG
++ save_screen
+ run_test_suite
+ finit
+ }
+diff --git a/src/tests/ibus-desktop-testing.desktop.in b/src/tests/ibus-desktop-testing.desktop.in
+index 1b815345..e91900ed 100644
+--- a/src/tests/ibus-desktop-testing.desktop.in
++++ b/src/tests/ibus-desktop-testing.desktop.in
+@@ -2,7 +2,7 @@
+ Name=IBus Desktop Testing Runner
+ GenericName=Input Method Desktop Testing Runner
+ Comment=Test plugin for IBus Desktop Testing
+-Exec=@libexecdir@/ibus-desktop-testing-autostart /var/tmp/ibus-ci-autostart.log
++Exec=sh -c 'exec @libexecdir@/ibus-desktop-testing-autostart --envcheck --output $HOME/test-autostart.log --result $HOME/test.log --runner gnome --screendump $HOME/screen.log --tests ibus'
+ Terminal=false
+ Type=Application
+ Encoding=UTF-8
+--
+2.45.0
+
+From 039fcb16f18d341a244362c3e797eeaa5c51010e Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Sat, 27 Jul 2024 19:02:09 +0900
+Subject: [PATCH 2/6] Fix tests cases to be run in Wayland
+
+- Fix ibus-bus since ibus_bus_exit_async() does not work ibus-daemon
+ with systemd and run `ibus restart` instead.
+- Fix ibus-compose-locales to wait for 1 sec between key event test cases
+ to reset gnome-shell/mutter.
+- Fix ibus-compose to wait for commit-text event since the gnome-shell/mutter
+ process is a bit slow and can reset the previous commit-text events
+ before the previous events are not committed.
+- Fix counts in ibus-engine-switch.
+- Unref IBusEngineDesc in ibus-engine-switch.
+- Fix ibusimpl not to change the engine of the context when global-engine
+ is enabled.
+- Check DISPLAY and setxkbmap in xkb-latin-layouts for Wayland
+
+BUG=https://github.com/ibus/ibus/pull/2657
+---
+ bus/ibusimpl.c | 8 ++
+ bus/ibusimpl.h | 3 +-
+ bus/inputcontext.c | 9 +++
+ src/ibusshare.c | 2 +-
+ src/tests/ibus-bus.c | 92 +++++++++++++++++++---
+ src/tests/ibus-compose.c | 139 ++++++++++++++++++++++++---------
+ src/tests/ibus-engine-switch.c | 45 ++++++++++-
+ src/tests/xkb-latin-layouts | 9 +++
+ 8 files changed, 254 insertions(+), 53 deletions(-)
+
+diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
+index 445c062b..4bed9bc0 100644
+--- a/bus/ibusimpl.c
++++ b/bus/ibusimpl.c
+@@ -2463,6 +2463,14 @@ bus_ibus_impl_is_embed_preedit_text (BusIBusImpl *ibus)
+ return ibus->embed_preedit_text;
+ }
+
++gboolean
++bus_ibus_impl_is_use_global_engine (BusIBusImpl *ibus)
++{
++ g_assert (BUS_IS_IBUS_IMPL (ibus));
++
++ return ibus->use_global_engine;
++}
++
+ BusInputContext *
+ bus_ibus_impl_get_focused_input_context (BusIBusImpl *ibus)
+ {
+diff --git a/bus/ibusimpl.h b/bus/ibusimpl.h
+index e3b43f87..428b773b 100644
+--- a/bus/ibusimpl.h
++++ b/bus/ibusimpl.h
+@@ -2,7 +2,7 @@
+ /* vim:set et sts=4: */
+ /* bus - The Input Bus
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+- * Copyright (C) 2022-2023 Takao Fujiwara <takao.fujiwara1@gmail.com>
++ * Copyright (C) 2022-2024 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2022 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+@@ -94,6 +94,7 @@ BusComponent *bus_ibus_impl_lookup_component_by_name
+ gboolean bus_ibus_impl_is_use_sys_layout (BusIBusImpl *ibus);
+ gboolean bus_ibus_impl_is_embed_preedit_text
+ (BusIBusImpl *ibus);
++gboolean bus_ibus_impl_is_use_global_engine (BusIBusImpl *ibus);
+ BusInputContext *bus_ibus_impl_get_focused_input_context
+ (BusIBusImpl *ibus);
+ GHashTable *bus_ibus_impl_get_engine_focus_id_table
+diff --git a/bus/inputcontext.c b/bus/inputcontext.c
+index 1e795733..85358241 100644
+--- a/bus/inputcontext.c
++++ b/bus/inputcontext.c
+@@ -1289,6 +1289,15 @@ _ic_set_engine (BusInputContext *context,
+ GDBusMethodInvocation *invocation)
+ {
+ gchar *engine_name = NULL;
++ BusIBusImpl *ibus = bus_ibus_impl_get_default ();
++
++ if (bus_ibus_impl_is_use_global_engine (ibus)) {
++ g_dbus_method_invocation_return_error (invocation,
++ G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
++ "Cannot set engines when use-global-engine is enabled.");
++ return;
++ }
++
+ g_variant_get (parameters, "(&s)", &engine_name);
+
+ if (!bus_input_context_has_focus (context)) {
+diff --git a/src/ibusshare.c b/src/ibusshare.c
+index 5ab6e889..57e3ef14 100644
+--- a/src/ibusshare.c
++++ b/src/ibusshare.c
+@@ -2,7 +2,7 @@
+ /* vim:set et sts=4: */
+ /* ibus - The Input Bus
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
+- * Copyright (C) 2015-2023 Takao Fujiwara <takao.fujiwara1@gmail.com>
++ * Copyright (C) 2015-2024 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+diff --git a/src/tests/ibus-bus.c b/src/tests/ibus-bus.c
+index d6b105cf..76120354 100644
+--- a/src/tests/ibus-bus.c
++++ b/src/tests/ibus-bus.c
+@@ -802,20 +802,29 @@ start_set_preload_engines_async (void)
+ NULL); /* user_data */
+ }
+
++typedef struct _ExitAsyncData {
++ gboolean has_socket_path;
++ gboolean exited;
++ guint timeout_id;
++} ExitAsyncData;
++
+ static void
+ _socket_changed_cb (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+- IBusBus *bus)
++ ExitAsyncData *data)
+ {
+ switch (event_type) {
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ g_debug ("IBus socket file is changed");
+ call_next_async_function ();
++ data->exited = TRUE;
+ g_signal_handlers_disconnect_by_func (monitor,
+ G_CALLBACK (_socket_changed_cb),
+- NULL);
++ data);
++ if (data->timeout_id)
++ g_source_remove (data->timeout_id);
+ g_object_unref (monitor);
+ break;
+ case G_FILE_MONITOR_EVENT_CREATED:
+@@ -829,6 +838,33 @@ _socket_changed_cb (GFileMonitor *monitor,
+ }
+ }
+
++static gboolean
++_exit_timeout (gpointer user_data)
++{
++ g_error ("start_exit_async() is timeout. You might run ibus-daemon " \
++ "with systemd under GNOME and the exit API does not work. " \
++ "You need to export IBUS_DAEMON_WITH_SYSTEMD=1 .\n");
++ return G_SOURCE_REMOVE;
++}
++
++static void
++finish_ibus_restart_async (GPid pid,
++ gint status,
++ gpointer *user_data)
++{
++ ExitAsyncData *data = (ExitAsyncData *)user_data;
++ g_spawn_close_pid (pid);
++ if (data->has_socket_path == FALSE) {
++ g_debug ("ibus_bus_exit_finish: OK socket file: none");
++ g_usleep (G_USEC_PER_SEC);
++ call_next_async_function ();
++ } else {
++ g_debug ("ibus_bus_exit_finish: OK socket file: monitored");
++ if (!data->exited)
++ data->timeout_id = g_timeout_add_seconds (10, _exit_timeout, NULL);
++ }
++}
++
+ static void
+ finish_exit_async (GObject *source_object,
+ GAsyncResult *res,
+@@ -838,25 +874,32 @@ finish_exit_async (GObject *source_object,
+ gboolean result = ibus_bus_exit_async_finish (bus,
+ res,
+ &error);
+- gboolean has_socket_path = GPOINTER_TO_INT (user_data);
++ ExitAsyncData *data = (ExitAsyncData *)user_data;
+ if (error) {
+ g_warning ("Failed to ibus_bus_exit(): %s", error->message);
+ g_error_free (error);
+ }
+ g_assert (result);
+- if (has_socket_path == FALSE) {
++ g_assert (data);
++ if (data->has_socket_path == FALSE) {
+ g_debug ("ibus_bus_exit_finish: OK socket file: none");
+ g_usleep (G_USEC_PER_SEC);
+ call_next_async_function ();
+ } else {
+ g_debug ("ibus_bus_exit_finish: OK socket file: monitored");
++ if (!data->exited)
++ data->timeout_id = g_timeout_add_seconds (10, _exit_timeout, NULL);
+ }
+ }
+
+ static void
+ start_exit_async (void)
+ {
+- gboolean has_socket_path = FALSE;
++ static ExitAsyncData data = {
++ .has_socket_path = FALSE,
++ .exited = FALSE,
++ .timeout_id = 0
++ };
+ /* When `./runtest ibus-bus` runs, ibus-daemon sometimes failed to
+ * restart because closing a file descriptor was failed in
+ * bus/server.c:_restart_server() with a following error:
+@@ -879,7 +922,7 @@ start_exit_async (void)
+ g_assert (address_path);
+ file = g_file_new_for_path (address_path);
+ g_assert (file);
+- has_socket_path = TRUE;
++ data.has_socket_path = TRUE;
+ monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, &error);
+ if (error) {
+ g_warning ("Failed to monitor socket file: %s", error->message);
+@@ -887,15 +930,38 @@ start_exit_async (void)
+ }
+ g_assert (monitor);
+ g_signal_connect (monitor, "changed",
+- G_CALLBACK (_socket_changed_cb), NULL);
++ G_CALLBACK (_socket_changed_cb),
++ &data);
+ g_object_unref (file);
+ }
+- ibus_bus_exit_async (bus,
+- TRUE, /* restart */
+- -1, /* timeout */
+- NULL, /* cancellable */
+- finish_exit_async,
+- GINT_TO_POINTER (has_socket_path)); /* user_data */
++ /* When ibus-daemon runs with systemd, restarting the daemon with
++ * ibus_bus_exit_async() does not work so runs `ibus restart` command
++ * with IBUS_DAEMON_WITH_SYSTEMD variable instead.
++ */
++ if (g_getenv ("IBUS_DAEMON_WITH_SYSTEMD")) {
++ gchar *argv[] = { "ibus", "restart", NULL };
++ GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD \
++ | G_SPAWN_SEARCH_PATH \
++ | G_SPAWN_STDOUT_TO_DEV_NULL \
++ | G_SPAWN_STDERR_TO_DEV_NULL;
++ GPid pid = 0;
++ GError *error = NULL;
++ g_spawn_async (NULL, argv, NULL, flags, NULL, NULL, &pid, &error);
++ if (error) {
++ g_warning ("Failed to call ibus restart: %s", error->message);
++ g_error_free (error);
++ }
++ g_child_watch_add (pid,
++ (GChildWatchFunc)finish_ibus_restart_async,
++ &data);
++ } else {
++ ibus_bus_exit_async (bus,
++ TRUE, /* restart */
++ -1, /* timeout */
++ NULL, /* cancellable */
++ finish_exit_async,
++ &data); /* user_data */
++ }
+ }
+
+ static gboolean
+diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c
+index 21de7a22..660aee7f 100644
+--- a/src/tests/ibus-compose.c
++++ b/src/tests/ibus-compose.c
+@@ -7,19 +7,28 @@
+ #define RED "\033[0;31m"
+ #define NC "\033[0m"
+
+-IBusBus *m_bus;
+-gchar *m_compose_file;
+-IBusComposeTableEx *m_compose_table;
+-IBusEngine *m_engine;
+-gchar *m_srcdir;
+-
+-guint ibus_compose_key_flag (guint key);
+-
++static IBusBus *m_bus;
++static gchar *m_compose_file;
++static IBusComposeTableEx *m_compose_table;
++static IBusEngine *m_engine;
++static gchar *m_srcdir;
++static GMainLoop *m_loop;
++
++typedef enum {
++ TEST_CREATE_ENGINE,
++ TEST_COMMIT_TEXT
++} TestIDleCategory;
++
++typedef struct _TestIdleData {
++ TestIDleCategory category;
++ guint idle_id;
++} TestIdleData;
++
++extern guint ibus_compose_key_flag (guint key);
+ static gboolean window_focus_in_event_cb (GtkWidget *entry,
+ GdkEventFocus *event,
+ gpointer data);
+
+-
+ static gchar *
+ get_compose_path ()
+ {
+@@ -51,17 +60,50 @@ get_compose_path ()
+ }
+
+
++gboolean
++idle_cb (gpointer user_data)
++{
++ TestIdleData *data = (TestIdleData *)user_data;
++ g_assert (data);
++ switch (data->category) {
++ case TEST_CREATE_ENGINE:
++ g_test_fail_printf ("\"create-engine\" signal is timeout.");
++ break;
++ case TEST_COMMIT_TEXT:
++ if (data->idle_id)
++ g_test_fail_printf ("Commiting composed chars is timeout.");
++ if (m_loop) {
++ if (g_main_loop_is_running (m_loop))
++ g_main_loop_quit (m_loop);
++ g_clear_pointer (&m_loop, g_main_loop_unref);
++ gtk_main_quit ();
++ }
++ data->idle_id = 0;
++ break;
++ default:
++ g_test_fail_printf ("Idle func is called by wrong category:%d.",
++ data->category);
++ break;
++ }
++ return G_SOURCE_REMOVE;
++}
++
++
+ static IBusEngine *
+ create_engine_cb (IBusFactory *factory,
+ const gchar *name,
+- gpointer data)
++ gpointer user_data)
+ {
+ static int i = 1;
+ gchar *engine_path =
+ g_strdup_printf ("/org/freedesktop/IBus/engine/simpletest/%d",
+ i++);
+ gchar *compose_path;
++ TestIdleData *data = (TestIdleData *)user_data;
+
++ g_assert (data);
++ /* Don't reset idle_id to avoid duplicated register_ibus_engine(). */
++ g_source_remove (data->idle_id);
+ m_engine = ibus_engine_new_with_type (IBUS_TYPE_ENGINE_SIMPLE,
+ name,
+ engine_path,
+@@ -75,28 +117,33 @@ create_engine_cb (IBusFactory *factory,
+ ibus_engine_simple_add_compose_file (IBUS_ENGINE_SIMPLE (m_engine),
+ compose_path);
+ m_compose_table = ibus_compose_table_load_cache (compose_path);
+- if (m_compose_table == NULL)
+- g_warning ("Your locale uses en_US compose table.");
+ }
+ g_free (compose_path);
+ return m_engine;
+ }
+
++
+ static gboolean
+ register_ibus_engine ()
+ {
++ static TestIdleData data = { .category = TEST_CREATE_ENGINE, .idle_id = 0 };
+ IBusFactory *factory;
+ IBusComponent *component;
+ IBusEngineDesc *desc;
+
++ if (data.idle_id) {
++ g_test_incomplete ("Test is called twice due to a timeout.");
++ return TRUE;
++ }
+ m_bus = ibus_bus_new ();
+ if (!ibus_bus_is_connected (m_bus)) {
+- g_critical ("ibus-daemon is not running.");
++ g_test_fail_printf ("ibus-daemon is not running.");
+ return FALSE;
+ }
+ factory = ibus_factory_new (ibus_bus_get_connection (m_bus));
++ data.idle_id = g_timeout_add_seconds (20, idle_cb, &data);
+ g_signal_connect (factory, "create-engine",
+- G_CALLBACK (create_engine_cb), NULL);
++ G_CALLBACK (create_engine_cb), &data);
+
+ component = ibus_component_new (
+ "org.freedesktop.IBus.SimpleTest",
+@@ -122,34 +169,29 @@ register_ibus_engine ()
+ return TRUE;
+ }
+
+-static gboolean
+-finit (gpointer data)
+-{
+- g_test_incomplete ("time out");
+- gtk_main_quit ();
+- return FALSE;
+-}
+
+ static void
+-set_engine_cb (GObject *object, GAsyncResult *res, gpointer data)
++set_engine_cb (GObject *object,
++ GAsyncResult *res,
++ gpointer user_data)
+ {
+ IBusBus *bus = IBUS_BUS (object);
+- GtkWidget *entry = GTK_WIDGET (data);
++ GtkWidget *entry = GTK_WIDGET (user_data);
+ GError *error = NULL;
++ static TestIdleData data = { .category = TEST_COMMIT_TEXT, .idle_id = 0 };
+ int i, j;
+ int index_stride;
+ IBusComposeTablePrivate *priv;
+
+ if (!ibus_bus_set_global_engine_async_finish (bus, res, &error)) {
+- gchar *msg = g_strdup_printf ("set engine failed: %s", error->message);
+- g_test_incomplete (msg);
+- g_free (msg);
++ g_test_fail_printf ("set engine failed: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ if (m_compose_table == NULL) {
+- gtk_main_quit ();
++ g_test_skip ("Your locale uses en_US compose table.");
++ idle_cb (&data);
+ return;
+ }
+
+@@ -157,6 +199,7 @@ set_engine_cb (GObject *object, GAsyncResult *res, gpointer data)
+ for (i = 0;
+ i < (m_compose_table->n_seqs * index_stride);
+ i += index_stride) {
++ data.idle_id = g_timeout_add_seconds (20, idle_cb, &data);
+ for (j = i; j < i + (index_stride - 2); j++) {
+ guint keyval = m_compose_table->data[j];
+ guint keycode = 0;
+@@ -172,12 +215,22 @@ set_engine_cb (GObject *object, GAsyncResult *res, gpointer data)
+ g_signal_emit_by_name (m_engine, "process-key-event",
+ keyval, keycode, modifiers, &retval);
+ }
++ /* Need to wait for calling window_inserted_text_cb() with
++ * g_main_loop_run() because the commit-text event could be cancelled
++ * by the next commit-text event with gnome-shell in Wayland.
++ */
++ g_main_loop_run (m_loop);
++ if (data.idle_id) {
++ g_source_remove (data.idle_id);
++ data.idle_id = 0;
++ }
+ }
+ priv = m_compose_table->priv;
+ if (priv) {
+ for (i = 0;
+ i < (priv->first_n_seqs * index_stride);
+ i += index_stride) {
++ data.idle_id = g_timeout_add_seconds (20, idle_cb, &data);
+ for (j = i; j < i + (index_stride - 2); j++) {
+ guint keyval = priv->data_first[j];
+ guint keycode = 0;
+@@ -193,13 +246,18 @@ set_engine_cb (GObject *object, GAsyncResult *res, gpointer data)
+ g_signal_emit_by_name (m_engine, "process-key-event",
+ keyval, keycode, modifiers, &retval);
+ }
++ g_main_loop_run (m_loop);
++ if (data.idle_id) {
++ g_source_remove (data.idle_id);
++ data.idle_id = 0;
++ }
+ }
+ }
+
+ g_signal_handlers_disconnect_by_func (entry,
+ G_CALLBACK (window_focus_in_event_cb),
+ NULL);
+- g_timeout_add_seconds (10, finit, NULL);
++ data.idle_id = g_timeout_add_seconds (10, idle_cb, &data);
+ }
+
+ static gboolean
+@@ -215,12 +273,13 @@ window_focus_in_event_cb (GtkWidget *entry, GdkEventFocus *event, gpointer data)
+ return FALSE;
+ }
+
++
+ static void
+ window_inserted_text_cb (GtkEntryBuffer *buffer,
+ guint position,
+ const gchar *chars,
+ guint nchars,
+- gpointer data)
++ gpointer user_data)
+ {
+ /* https://gitlab.gnome.org/GNOME/gtk/commit/9981f46e0b
+ * The latest GTK does not emit "inserted-text" when the text is "".
+@@ -234,8 +293,9 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
+ int seq;
+ gunichar code = g_utf8_get_char (chars);
+ const gchar *test;
+- GtkEntry *entry = GTK_ENTRY (data);
++ GtkEntry *entry = GTK_ENTRY (user_data);
+ IBusComposeTablePrivate *priv;
++ static TestIdleData data = { .category = TEST_COMMIT_TEXT, .idle_id = 0 };
+
+ g_assert (m_compose_table != NULL);
+
+@@ -302,21 +362,26 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
+ stride = 0;
+ seq = 0;
+ } else {
+- gtk_main_quit ();
++ /* Finish tests */
++ idle_cb (&data);
+ return;
+ }
+ }
+ if (enable_32bit && seq == priv->first_n_seqs) {
+- gtk_main_quit ();
++ /* Finish tests */
++ idle_cb (&data);
+ return;
+ }
+
+ #if !GTK_CHECK_VERSION (3, 22, 16)
+ n_loop++;
+ #endif
++
+ gtk_entry_set_text (entry, "");
++ g_main_loop_quit (m_loop);
+ }
+
++
+ static void
+ create_window ()
+ {
+@@ -335,14 +400,13 @@ create_window ()
+ gtk_widget_show_all (window);
+ }
+
++
+ static void
+ test_compose (void)
+ {
+ GLogLevelFlags flags;
+- if (!register_ibus_engine ()) {
+- g_test_fail ();
++ if (!register_ibus_engine ())
+ return;
+- }
+
+ create_window ();
+ /* FIXME:
+@@ -357,6 +421,7 @@ test_compose (void)
+ g_log_set_always_fatal (flags);
+ }
+
++
+ int
+ main (int argc, char *argv[])
+ {
+@@ -380,10 +445,12 @@ main (int argc, char *argv[])
+ #else
+ test_name = g_strdup (g_getenv ("LANG"));
+ #endif
+- if (!test_name || !g_ascii_strncasecmp (test_name, "en_US", 5)) {
++ if (m_compose_file &&
++ (!test_name || !g_ascii_strncasecmp (test_name, "en_US", 5))) {
+ g_free (test_name);
+ test_name = g_path_get_basename (m_compose_file);
+ }
++ m_loop = g_main_loop_new (NULL, TRUE);
+ test_path = g_build_filename ("/ibus-compose", test_name, NULL);
+ g_test_add_func (test_path, test_compose);
+ g_free (test_path);
+diff --git a/src/tests/ibus-engine-switch.c b/src/tests/ibus-engine-switch.c
+index a1eeba2a..b50bac59 100644
+--- a/src/tests/ibus-engine-switch.c
++++ b/src/tests/ibus-engine-switch.c
+@@ -1,6 +1,7 @@
+ /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+
+ #include <string.h>
++#include <unistd.h>
+ #include "ibus.h"
+
+ static IBusBus *bus;
+@@ -47,6 +48,7 @@ change_context_engine (IBusInputContext *context)
+ g_assert_cmpstr (ibus_engine_desc_get_name (engine_desc),
+ ==,
+ engine_names[i]);
++ g_object_unref (engine_desc);
+ }
+ }
+
+@@ -61,7 +63,7 @@ static void
+ global_engine_changed_cb (IBusBus *bus, gchar *name, gpointer user_data)
+ {
+ GlobalEngineChangedData *data = (GlobalEngineChangedData *) user_data;
+- if (data->count++ == 0)
++ if (data->count++ == 1)
+ ibus_quit ();
+ }
+
+@@ -84,6 +86,35 @@ change_global_engine_cb (gpointer user_data)
+ return FALSE;
+ }
+
++gboolean
++_wait_for_key_release_cb (gpointer user_data)
++{
++ GMainLoop *loop = (GMainLoop *)user_data;
++ /* If this program is invoked by manual with Enter key in GNOME
++ * Wayland session, ibus_input_context_focus_in() can be called in
++ * test_context_engine_set_by_global() before the key release of
++ * the Enter key so ibus/bus/inputcontext.c:_ic_process_key_event()
++ * could call another bus_input_context_focus_in() in that test case
++ * and fail.
++ */
++ g_test_message ("Wait for 3 seconds for key release event");
++ g_main_loop_quit (loop);
++ return G_SOURCE_REMOVE;
++}
++
++static void
++test_init (void)
++{
++ char *tty_name = ttyname (STDIN_FILENO);
++ GMainLoop *loop = g_main_loop_new (NULL, TRUE);
++ g_test_message ("Test on %s", tty_name ? tty_name : "(null)");
++ if (tty_name && g_strstr_len (tty_name, -1, "pts")) {
++ g_timeout_add_seconds (3, _wait_for_key_release_cb, loop);
++ g_main_loop_run (loop);
++ }
++ g_main_loop_unref (loop);
++}
++
+ static void
+ test_global_engine (void)
+ {
+@@ -105,6 +136,10 @@ test_global_engine (void)
+ } else {
+ data.reverse = FALSE;
+ }
++ g_test_message ("Initial engine name: %s",
++ desc ? ibus_engine_desc_get_name (desc) : "(null)");
++ if (desc)
++ g_object_unref (desc);
+
+ data.count = 0;
+
+@@ -112,7 +147,7 @@ test_global_engine (void)
+ "global-engine-changed",
+ G_CALLBACK (global_engine_changed_cb),
+ &data);
+- data.timeout_id = g_timeout_add_seconds (1, timeout_cb, &data);
++ data.timeout_id = g_timeout_add_seconds (3, timeout_cb, &data);
+ data.idle_id = g_idle_add ((GSourceFunc) change_global_engine_cb, &data);
+
+ ibus_main ();
+@@ -144,6 +179,7 @@ test_context_engine (void)
+ change_context_engine (context);
+ engine_desc = ibus_input_context_get_engine (context);
+ g_assert_cmpstr (ibus_engine_desc_get_name (engine_desc), ==, AFTER_ENGINE);
++ g_object_unref (engine_desc);
+
+ g_object_unref (context);
+ }
+@@ -171,6 +207,7 @@ test_context_engine_set_by_global (void)
+
+ engine_desc = ibus_input_context_get_engine (context);
+ g_assert_cmpstr (ibus_engine_desc_get_name (engine_desc), ==, AFTER_ENGINE);
++ g_object_unref (engine_desc);
+
+ g_object_unref (context);
+ }
+@@ -199,9 +236,11 @@ test_context_engine_set_by_focus (void)
+
+ engine_desc = ibus_input_context_get_engine (context);
+ g_assert_cmpstr (ibus_engine_desc_get_name (engine_desc), ==, "dummy");
++ g_object_unref (engine_desc);
+
+ engine_desc = ibus_input_context_get_engine (another_context);
+ g_assert_cmpstr (ibus_engine_desc_get_name (engine_desc), ==, AFTER_ENGINE);
++ g_object_unref (engine_desc);
+
+ g_object_unref (context);
+ g_object_unref (another_context);
+@@ -220,6 +259,8 @@ main (gint argc,
+
+ ibus_bus_set_watch_ibus_signal (bus, TRUE);
+
++ g_test_add_func ("/ibus/engine-switch/test-init",
++ test_init);
+ g_test_add_func ("/ibus/engine-switch/global-engine",
+ test_global_engine);
+ g_test_add_func ("/ibus/engine-switch/context-engine",
+diff --git a/src/tests/xkb-latin-layouts b/src/tests/xkb-latin-layouts
+index 92464234..45c99358 100755
+--- a/src/tests/xkb-latin-layouts
++++ b/src/tests/xkb-latin-layouts
+@@ -120,6 +120,15 @@ EOF_READ_XKB
+
+ main()
+ {
++ if [ x"$DISPLAY" = x ] ; then
++ echo "skip: No display. Maybe headless mode."
++ exit 77
++ fi
++ if ! which setxkbmap > /dev/null ; then
++ echo "skip: No setxkbmap"
++ exit 77
++ fi
++
+ parse_args "$@"
+
+ if [ x"$INSTALLED_SCHEMAS_DIR" != x ] ; then
+--
+2.45.0
+
+From 44f9a5957e4c53b4a6e6b3f42b56f2d20d58a21c Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Sat, 27 Jul 2024 19:04:39 +0900
+Subject: [PATCH 3/6] src/tests: Enable GTK4
+
+Seems GTK3 does not work in GNOME Wayland headless session to get
+GdkMonitor in gtk_init() and trying to migrate the test cases to
+GTK4.
+Calling ibus_init() twice with g_static_resource_init() causes a
+memory error and fix it.
+
+BUG=https://github.com/ibus/ibus/pull/2657
+---
+ src/tests/Makefile.am | 8 +--
+ src/tests/ibus-compose.c | 147 ++++++++++++++++++++++++++++++++------
+ src/tests/ibus-keypress.c | 146 ++++++++++++++++++++++++++++++-------
+ 3 files changed, 251 insertions(+), 50 deletions(-)
+
+diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
+index 6c4c86cf..10acd0a7 100644
+--- a/src/tests/Makefile.am
++++ b/src/tests/Makefile.am
+@@ -182,8 +182,8 @@ ibus_bus_SOURCES = ibus-bus.c
+ ibus_bus_LDADD = $(prog_ldadd)
+
+ ibus_compose_SOURCES = ibus-compose.c
+-ibus_compose_CFLAGS = @GTK3_CFLAGS@
+-ibus_compose_LDADD = $(prog_ldadd) @GTK3_LIBS@
++ibus_compose_CFLAGS = @GTK4_CFLAGS@
++ibus_compose_LDADD = $(prog_ldadd) @GTK4_LIBS@
+
+ ibus_config_SOURCES = ibus-config.c
+ ibus_config_LDADD = $(prog_ldadd)
+@@ -207,8 +207,8 @@ ibus_keynames_SOURCES = ibus-keynames.c
+ ibus_keynames_LDADD = $(prog_ldadd)
+
+ ibus_keypress_SOURCES = ibus-keypress.c
+-ibus_keypress_CFLAGS = @GTK3_CFLAGS@ @XTEST_CFLAGS@
+-ibus_keypress_LDADD = $(prog_ldadd) @GTK3_LIBS@ @XTEST_LIBS@
++ibus_keypress_CFLAGS = @GTK4_CFLAGS@ @XTEST_CFLAGS@
++ibus_keypress_LDADD = $(prog_ldadd) @GTK4_LIBS@ @XTEST_LIBS@
+
+ ibus_registry_SOURCES = ibus-registry.c
+ ibus_registry_LDADD = $(prog_ldadd)
+diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c
+index 660aee7f..57851b0a 100644
+--- a/src/tests/ibus-compose.c
++++ b/src/tests/ibus-compose.c
+@@ -13,6 +13,9 @@ static IBusComposeTableEx *m_compose_table;
+ static IBusEngine *m_engine;
+ static gchar *m_srcdir;
+ static GMainLoop *m_loop;
++#if GTK_CHECK_VERSION (4, 0, 0)
++static gboolean m_list_toplevel;
++#endif
+
+ typedef enum {
+ TEST_CREATE_ENGINE,
+@@ -25,9 +28,16 @@ typedef struct _TestIdleData {
+ } TestIdleData;
+
+ extern guint ibus_compose_key_flag (guint key);
++
++#if GTK_CHECK_VERSION (4, 0, 0)
++static void event_controller_enter_cb (GtkEventController *controller,
++ gpointer user_data);
++#else
+ static gboolean window_focus_in_event_cb (GtkWidget *entry,
+ GdkEventFocus *event,
+ gpointer data);
++#endif
++
+
+ static gchar *
+ get_compose_path ()
+@@ -76,7 +86,11 @@ idle_cb (gpointer user_data)
+ if (g_main_loop_is_running (m_loop))
+ g_main_loop_quit (m_loop);
+ g_clear_pointer (&m_loop, g_main_loop_unref);
++#if GTK_CHECK_VERSION (4, 0, 0)
++ m_list_toplevel = FALSE;
++#else
+ gtk_main_quit ();
++#endif
+ }
+ data->idle_id = 0;
+ break;
+@@ -170,13 +184,28 @@ register_ibus_engine ()
+ }
+
+
++static void
++window_destroy_cb (void)
++{
++#if GTK_CHECK_VERSION (4, 0, 0)
++ m_list_toplevel = FALSE;
++#else
++ gtk_main_quit ();
++#endif
++}
++
++
+ static void
+ set_engine_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+ {
+ IBusBus *bus = IBUS_BUS (object);
++#if GTK_CHECK_VERSION (4, 0, 0)
++ GtkEventController *controller = GTK_EVENT_CONTROLLER (user_data);
++#else
+ GtkWidget *entry = GTK_WIDGET (user_data);
++#endif
+ GError *error = NULL;
+ static TestIdleData data = { .category = TEST_COMMIT_TEXT, .idle_id = 0 };
+ int i, j;
+@@ -254,24 +283,55 @@ set_engine_cb (GObject *object,
+ }
+ }
+
++#if GTK_CHECK_VERSION (4, 0, 0)
++ g_signal_handlers_disconnect_by_func (
++ controller,
++ G_CALLBACK (event_controller_enter_cb),
++ NULL);
++#else
+ g_signal_handlers_disconnect_by_func (entry,
+ G_CALLBACK (window_focus_in_event_cb),
+ NULL);
++#endif
+ data.idle_id = g_timeout_add_seconds (10, idle_cb, &data);
+ }
+
+-static gboolean
+-window_focus_in_event_cb (GtkWidget *entry, GdkEventFocus *event, gpointer data)
++
++static void
++set_engine (gpointer user_data)
+ {
++ g_test_message ("set_engine() is calling");
+ g_assert (m_bus != NULL);
+ ibus_bus_set_global_engine_async (m_bus,
+ "xkbtest:us::eng",
+ -1,
+ NULL,
+ set_engine_cb,
+- entry);
++ user_data);
++}
++
++
++#if GTK_CHECK_VERSION (4, 0, 0)
++static void
++event_controller_enter_cb (GtkEventController *controller,
++ gpointer user_data)
++{
++ g_test_message ("EventController emits \"enter\" signal");
++ set_engine (controller);
++}
++
++#else
++
++static gboolean
++window_focus_in_event_cb (GtkWidget *entry,
++ GdkEventFocus *event,
++ gpointer data)
++{
++ g_test_message ("Entry emits \"focus-in-event\" signal");
++ set_engine (entry);
+ return FALSE;
+ }
++#endif
+
+
+ static void
+@@ -293,7 +353,9 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
+ int seq;
+ gunichar code = g_utf8_get_char (chars);
+ const gchar *test;
++#if ! GTK_CHECK_VERSION (4, 0, 0)
+ GtkEntry *entry = GTK_ENTRY (user_data);
++#endif
+ IBusComposeTablePrivate *priv;
+ static TestIdleData data = { .category = TEST_COMMIT_TEXT, .idle_id = 0 };
+
+@@ -306,6 +368,10 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
+ n_loop = 0;
+ return;
+ }
++#endif
++#if GTK_CHECK_VERSION (4, 0, 0)
++ if (code == 0)
++ return;
+ #endif
+ i = stride + (m_compose_table->max_seq_len + 2) - 2;
+ seq = (i + 2) / (m_compose_table->max_seq_len + 2);
+@@ -318,12 +384,12 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
+ test = RED "FAIL" NC;
+ g_test_fail ();
+ }
+- g_print ("%05d/%05d %s expected: %04X typed: %04X\n",
+- seq,
+- m_compose_table->n_seqs,
+- test,
+- m_compose_table->data[i],
+- code);
++ g_test_message ("%05d/%05d %s expected: %04X typed: %04X",
++ seq,
++ m_compose_table->n_seqs,
++ test,
++ m_compose_table->data[i],
++ code);
+ } else {
+ const gchar *p = chars;
+ guint num = priv->data_first[i];
+@@ -344,14 +410,14 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
+ test = RED "FAIL" NC;
+ g_test_fail ();
+ }
+- g_print ("%05d/%05ld %s expected: %04X[%d] typed: %04X\n",
+- seq,
+- priv->first_n_seqs,
+- test,
+- valid_output ? priv->data_second[index]
+- : priv->data_second[index + j],
+- valid_output ? index + num : index + j,
+- valid_output ? g_utf8_get_char (chars) : code);
++ g_test_message ("%05d/%05ld %s expected: %04X[%d] typed: %04X",
++ seq,
++ priv->first_n_seqs,
++ test,
++ valid_output ? priv->data_second[index]
++ : priv->data_second[index + j],
++ valid_output ? index + num : index + j,
++ valid_output ? g_utf8_get_char (chars) : code);
+ }
+
+ stride += m_compose_table->max_seq_len + 2;
+@@ -377,7 +443,11 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
+ n_loop++;
+ #endif
+
++#if GTK_CHECK_VERSION (4, 0, 0)
++ gtk_entry_buffer_set_text (buffer, "", 0);
++#else
+ gtk_entry_set_text (entry, "");
++#endif
+ g_main_loop_quit (m_loop);
+ }
+
+@@ -385,19 +455,43 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
+ static void
+ create_window ()
+ {
+- GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+- GtkWidget *entry = gtk_entry_new ();
++ GtkWidget *window;
++ GtkWidget *entry;
+ GtkEntryBuffer *buffer;
++#if GTK_CHECK_VERSION (4, 0, 0)
++ GtkEventController *controller;
++ GtkEditable *text;
++
++ window = gtk_window_new ();
++#else
++ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
++#endif
++ entry = gtk_entry_new ();
+
+ g_signal_connect (window, "destroy",
+- G_CALLBACK (gtk_main_quit), NULL);
++ G_CALLBACK (window_destroy_cb), NULL);
++#if GTK_CHECK_VERSION (4, 0, 0)
++ controller = gtk_event_controller_focus_new ();
++ text = gtk_editable_get_delegate (GTK_EDITABLE (entry));
++ g_signal_connect (controller, "enter",
++ G_CALLBACK (event_controller_enter_cb), NULL);
++ gtk_widget_add_controller (GTK_WIDGET (text), controller);
++#else
+ g_signal_connect (entry, "focus-in-event",
+ G_CALLBACK (window_focus_in_event_cb), NULL);
++#endif
+ buffer = gtk_entry_get_buffer (GTK_ENTRY (entry));
+ g_signal_connect (buffer, "inserted-text",
+ G_CALLBACK (window_inserted_text_cb), entry);
++
++#if GTK_CHECK_VERSION (4, 0, 0)
++ gtk_window_set_child (GTK_WINDOW (window), entry);
++ gtk_window_set_focus (GTK_WINDOW (window), entry);
++ gtk_window_present (GTK_WINDOW (window));
++#else
+ gtk_container_add (GTK_CONTAINER (window), entry);
+ gtk_widget_show_all (window);
++#endif
+ }
+
+
+@@ -408,6 +502,9 @@ test_compose (void)
+ if (!register_ibus_engine ())
+ return;
+
++#if GTK_CHECK_VERSION (4, 0, 0)
++ m_list_toplevel = TRUE;
++#endif
+ create_window ();
+ /* FIXME:
+ * IBusIMContext opens GtkIMContextSimple as the slave and
+@@ -417,7 +514,13 @@ test_compose (void)
+ " "GTK+ supports to output one char only: "
+ */
+ flags = g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
++#if GTK_CHECK_VERSION (4, 0, 0)
++ gtk_window_list_toplevels ();
++ while (m_list_toplevel)
++ g_main_context_iteration (NULL, TRUE);
++#else
+ gtk_main ();
++#endif
+ g_log_set_always_fatal (flags);
+ }
+
+@@ -435,7 +538,11 @@ main (int argc, char *argv[])
+ if (!g_setenv ("NO_AT_BRIDGE", "1", TRUE))
+ g_message ("Failed setenv NO_AT_BRIDGE\n");
+ g_test_init (&argc, &argv, NULL);
++#if GTK_CHECK_VERSION (4, 0, 0)
++ gtk_init ();
++#else
+ gtk_init (&argc, &argv);
++#endif
+
+ m_srcdir = (argc > 1 && strlen (argv[1]) < FILENAME_MAX)
+ ? g_strdup (argv[1]) : g_strdup (".");
+diff --git a/src/tests/ibus-keypress.c b/src/tests/ibus-keypress.c
+index d44f39b2..a9288260 100644
+--- a/src/tests/ibus-keypress.c
++++ b/src/tests/ibus-keypress.c
+@@ -1,12 +1,16 @@
+ #include <gtk/gtk.h>
++#if GTK_CHECK_VERSION (4, 0, 0)
++#include <gdk/x11/gdkx.h>
++#else
+ #include <gdk/gdkx.h>
++#endif
+ #include "ibus.h"
+ #include <stdlib.h>
+ #include <X11/Xlib.h>
+ #include <X11/extensions/XTest.h>
+
+ #ifdef GDK_WINDOWING_WAYLAND
+-#if GTK_CHECK_VERSION (3, 98, 4)
++#if GTK_CHECK_VERSION (4, 0, 0)
+ #include <gdk/wayland/gdkwayland.h>
+ #else
+ #include <gdk/gdkwayland.h>
+@@ -51,12 +55,18 @@ static const gunichar test_results[][60] = {
+ };
+
+
+-IBusBus *m_bus;
+-IBusEngine *m_engine;
++static IBusBus *m_bus;
++static IBusEngine *m_engine;
++#if GTK_CHECK_VERSION (4, 0, 0)
++static gboolean m_list_toplevel;
+
++static gboolean event_controller_enter_cb (GtkEventController *controller,
++ gpointer user_data);
++#else
+ static gboolean window_focus_in_event_cb (GtkWidget *entry,
+ GdkEventFocus *event,
+ gpointer data);
++#endif
+
+ static IBusEngine *
+ create_engine_cb (IBusFactory *factory, const gchar *name, gpointer data)
+@@ -118,7 +128,11 @@ static gboolean
+ finit (gpointer data)
+ {
+ g_critical ("time out");
++#if GTK_CHECK_VERSION (4, 0, 0)
++ m_list_toplevel = FALSE;
++#else
+ gtk_main_quit ();
++#endif
+ return FALSE;
+ }
+
+@@ -173,27 +187,41 @@ send_key_event (Display *xdisplay,
+ }
+ }
+
++static void
++window_destroy_cb (void)
++{
++#if GTK_CHECK_VERSION (4, 0, 0)
++ m_list_toplevel = FALSE;
++#else
++ gtk_main_quit ();
++#endif
++}
++
+ static void
+ set_engine_cb (GObject *object,
+ GAsyncResult *res,
+- gpointer data)
++ gpointer user_data)
+ {
+ IBusBus *bus = IBUS_BUS (object);
+- GtkWidget *entry = GTK_WIDGET (data);
++#if ! GTK_CHECK_VERSION (4, 0, 0)
++ GtkWidget *entry = GTK_WIDGET (user_data);
++#endif
+ GdkDisplay *display;
+ Display *xdisplay = NULL;
+ GError *error = NULL;
+ int i, j;
+
+- g_assert (GTK_IS_ENTRY (entry));
+-
+ if (!ibus_bus_set_global_engine_async_finish (bus, res, &error)) {
+ g_critical ("set engine failed: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
++#if GTK_CHECK_VERSION (4, 0, 0)
++ display = gdk_display_get_default ();
++#else
+ display = gtk_widget_get_display (entry);
++#endif
+ g_assert (GDK_IS_X11_DISPLAY (display));
+ xdisplay = gdk_x11_display_get_xdisplay (display);
+ g_return_if_fail (xdisplay);
+@@ -210,8 +238,8 @@ set_engine_cb (GObject *object,
+ g_timeout_add_seconds (10, finit, NULL);
+ }
+
+-static gboolean
+-window_focus_in_event_cb (GtkWidget *entry, GdkEventFocus *event, gpointer data)
++static void
++set_engine (gpointer user_data)
+ {
+ g_assert (m_bus != NULL);
+ ibus_bus_set_global_engine_async (m_bus,
+@@ -219,18 +247,40 @@ window_focus_in_event_cb (GtkWidget *entry, GdkEventFocus *event, gpointer data)
+ -1,
+ NULL,
+ set_engine_cb,
+- entry);
++ user_data);
++}
++
++#if GTK_CHECK_VERSION (4, 0, 0)
++static gboolean
++event_controller_enter_cb (GtkEventController *controller,
++ gpointer user_data)
++{
++ set_engine (controller);
++ return FALSE;
++}
++
++#else
++
++static gboolean
++window_focus_in_event_cb (GtkWidget *entry,
++ GdkEventFocus *event,
++ gpointer user_data)
++{
++ set_engine (entry);
+ return FALSE;
+ }
++#endif
+
+ static void
+ window_inserted_text_cb (GtkEntryBuffer *buffer,
+ guint position,
+ const gchar *chars,
+ guint nchars,
+- gpointer data)
++ gpointer user_data)
+ {
+- GtkWidget *entry = data;
++#if ! GTK_CHECK_VERSION (4, 0, 0)
++ GtkWidget *entry = user_data;
++#endif
+ static int i = 0;
+ static int j = 0;
+
+@@ -242,10 +292,19 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
+ g_print ("\n");
+ i++;
+ j = 0;
+- if (test_results[i][0] == 0)
++ if (test_results[i][0] == 0) {
++#if GTK_CHECK_VERSION (4, 0, 0)
++ m_list_toplevel = FALSE;
++#else
+ gtk_main_quit ();
+- else
++#endif
++ } else {
++#if GTK_CHECK_VERSION (4, 0, 0)
++ gtk_entry_buffer_set_text (buffer, "", 1);
++#else
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
++#endif
++ }
+ return;
+ }
+ g_assert (g_utf8_get_char (chars) == test_results[i][j]);
+@@ -255,19 +314,39 @@ window_inserted_text_cb (GtkEntryBuffer *buffer,
+ static void
+ create_window ()
+ {
+- GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
++ GtkWidget *window;
+ GtkWidget *entry = gtk_entry_new ();
+ GtkEntryBuffer *buffer;
++#if GTK_CHECK_VERSION (4, 0, 0)
++ GtkEventController *controller;
++
++ window = gtk_window_new ();
++#else
++ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
++#endif
+
+ g_signal_connect (window, "destroy",
+- G_CALLBACK (gtk_main_quit), NULL);
++ G_CALLBACK (window_destroy_cb), NULL);
++#if GTK_CHECK_VERSION (4, 0, 0)
++ controller = gtk_event_controller_focus_new ();
++ g_signal_connect (controller, "enter",
++ G_CALLBACK (event_controller_enter_cb), NULL);
++ gtk_widget_add_controller (window, controller);
++#else
+ g_signal_connect (entry, "focus-in-event",
+ G_CALLBACK (window_focus_in_event_cb), NULL);
++#endif
+ buffer = gtk_entry_get_buffer (GTK_ENTRY (entry));
+ g_signal_connect (buffer, "inserted-text",
+ G_CALLBACK (window_inserted_text_cb), entry);
++#if GTK_CHECK_VERSION (4, 0, 0)
++ gtk_window_set_child (GTK_WINDOW (window), entry);
++ gtk_window_set_focus (GTK_WINDOW (window), entry);
++ gtk_window_present (GTK_WINDOW (window));
++#else
+ gtk_container_add (GTK_CONTAINER (window), entry);
+ gtk_widget_show_all (window);
++#endif
+ }
+
+ static void
+@@ -277,6 +356,16 @@ test_keypress (void)
+ int status = 0;
+ GError *error = NULL;
+
++#ifdef GDK_WINDOWING_WAYLAND
++ {
++ GdkDisplay *display = gdk_display_get_default ();
++ if (GDK_IS_WAYLAND_DISPLAY (display)) {
++ g_test_skip_printf ("setxkbmap and XTEST do not work in Wayland.");
++ return;
++ }
++ }
++#endif
++
+ /* localectl does not change the session keymap. */
+ path = g_find_program_in_path ("setxkbmap");
+ if (path) {
+@@ -287,33 +376,38 @@ test_keypress (void)
+ g_free (path);
+ g_assert (register_ibus_engine ());
+
++#if GTK_CHECK_VERSION (4, 0, 0)
++ m_list_toplevel = TRUE;
++#endif
+ create_window ();
++#if GTK_CHECK_VERSION (4, 0, 0)
++ while (m_list_toplevel)
++ g_main_context_iteration (NULL, TRUE);
++#else
+ gtk_main ();
++#endif
+ }
+
+ int
+ main (int argc, char *argv[])
+ {
+- ibus_init ();
++ /* ibus_init() should not be called here because
++ * ibus_init() is called from IBus Gtk4 IM module even if
++ * GTK_IM_MODULE=wayland is exported.
++ */
+ /* Avoid a warning of "AT-SPI: Could not obtain desktop path or name"
+ * with gtk_main().
+ */
+ if (!g_setenv ("NO_AT_BRIDGE", "1", TRUE))
+ g_message ("Failed setenv NO_AT_BRIDGE\n");
+ g_test_init (&argc, &argv, NULL);
++#if GTK_CHECK_VERSION (4, 0, 0)
++ gtk_init ();
++#else
+ gtk_init (&argc, &argv);
+-#ifdef GDK_WINDOWING_WAYLAND
+- {
+- GdkDisplay *display = gdk_display_get_default ();
+- if (GDK_IS_WAYLAND_DISPLAY (display)) {
+- g_print ("setxkbmap and XTEST do not work in Wayland.\n");
+- return 0;
+- }
+- }
+ #endif
+
+ g_test_add_func ("/ibus/keyrepss", test_keypress);
+
+-
+ return g_test_run ();
+ }
+--
+2.45.0
+
+From a2689c4d66d1f5ae73d2ddbbb94374c98914a029 Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Sat, 27 Jul 2024 19:07:58 +0900
+Subject: [PATCH 4/6] src/tests: Fix test cases in GNOME Xorg in ibus-compose
+
+"focus-in" signal is sent to IBus GtkIMModule with a delay in GNOME
+desktop session and the signal order is not fixed with GTK_PHASE_TARGET
+also "focus-in" signal is also sent with GtkText "realize"' signal.
+Now the test cases wait for GtkText 'realize' signal.
+This fixes the test cases in GNOME Xorg but there are still sone issues
+in GNOME Wayland.
+
+BUG=https://github.com/ibus/ibus/pull/2657
+---
+ src/tests/ibus-compose.c | 71 ++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 68 insertions(+), 3 deletions(-)
+
+diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c
+index 57851b0a..e9f102a1 100644
+--- a/src/tests/ibus-compose.c
++++ b/src/tests/ibus-compose.c
+@@ -39,6 +39,23 @@ static gboolean window_focus_in_event_cb (GtkWidget *entry,
+ #endif
+
+
++gboolean
++_wait_for_key_release_cb (gpointer user_data)
++{
++ GMainLoop *loop = (GMainLoop *)user_data;
++ /* If this program is invoked by manual with Enter key in GNOME
++ * Wayland session, ibus_input_context_focus_in() can be called in
++ * test_context_engine_set_by_global() before the key release of
++ * the Enter key so ibus/bus/inputcontext.c:_ic_process_key_event()
++ * could call another bus_input_context_focus_in() in that test case
++ * and fail.
++ */
++ g_test_message ("Wait for 3 seconds for key release event");
++ g_main_loop_quit (loop);
++ return G_SOURCE_REMOVE;
++}
++
++
+ static gchar *
+ get_compose_path ()
+ {
+@@ -312,12 +329,45 @@ set_engine (gpointer user_data)
+
+
+ #if GTK_CHECK_VERSION (4, 0, 0)
++static gboolean
++event_controller_enter_delay (gpointer user_data)
++{
++ GtkEventController *controller = (GtkEventController *)user_data;
++ GtkWidget *text = gtk_event_controller_get_widget (controller);
++ static int i = 0;
++
++ /* Wait for gtk_text_realize() which calls gtk_text_im_set_focus_in()
++ * while gtk_text_focus_changed() also calls gtk_text_im_set_focus_in()
++ * in GNOME Xorg.
++ */
++ if (gtk_widget_get_realized (text)) {
++ set_engine (user_data);
++ return G_SOURCE_REMOVE;
++ }
++ if (i++ == 10) {
++ g_test_fail_printf ("Window is not realized with %d times", i);
++ return G_SOURCE_REMOVE;
++ }
++ g_test_message ("event_controller_enter_delay %d", i);
++ return G_SOURCE_CONTINUE;
++}
++
++
+ static void
+ event_controller_enter_cb (GtkEventController *controller,
+ gpointer user_data)
+ {
++ static guint id = 0;
++
+ g_test_message ("EventController emits \"enter\" signal");
+- set_engine (controller);
++ /* Call an idle function because gtk_widget_add_controller()
++ * calls g_list_prepend() for event_controllers and this controller is
++ * always called before "gtk-text-focus-controller"
++ * is caleld and the IM context does not receive the focus-in yet.
++ */
++ if (id)
++ return;
++ id = g_idle_add (event_controller_enter_delay, controller);
+ }
+
+ #else
+@@ -473,8 +523,9 @@ create_window ()
+ #if GTK_CHECK_VERSION (4, 0, 0)
+ controller = gtk_event_controller_focus_new ();
+ text = gtk_editable_get_delegate (GTK_EDITABLE (entry));
+- g_signal_connect (controller, "enter",
+- G_CALLBACK (event_controller_enter_cb), NULL);
++ gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
++ g_signal_connect_after (controller, "enter",
++ G_CALLBACK (event_controller_enter_cb), NULL);
+ gtk_widget_add_controller (GTK_WIDGET (text), controller);
+ #else
+ g_signal_connect (entry, "focus-in-event",
+@@ -495,6 +546,19 @@ create_window ()
+ }
+
+
++static void
++test_init (void)
++{
++ char *tty_name = ttyname (STDIN_FILENO);
++ GMainLoop *loop = g_main_loop_new (NULL, TRUE);
++ g_test_message ("Test on %s", tty_name ? tty_name : "(null)");
++ if (tty_name && g_strstr_len (tty_name, -1, "pts")) {
++ g_timeout_add_seconds (3, _wait_for_key_release_cb, loop);
++ g_main_loop_run (loop);
++ }
++ g_main_loop_unref (loop);
++}
++
+ static void
+ test_compose (void)
+ {
+@@ -557,6 +621,7 @@ main (int argc, char *argv[])
+ g_free (test_name);
+ test_name = g_path_get_basename (m_compose_file);
+ }
++ g_test_add_func ("/ibus-compose/test-init", test_init);
+ m_loop = g_main_loop_new (NULL, TRUE);
+ test_path = g_build_filename ("/ibus-compose", test_name, NULL);
+ g_test_add_func (test_path, test_compose);
+--
+2.45.0
+
+From e65110a9bed03c981884e28ff44e2ac1f639df45 Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Sat, 27 Jul 2024 19:09:10 +0900
+Subject: [PATCH 5/6] src/tests: Fix ibus-compose for GNOME Wayland
+
+mutter calls meta_wayland_text_input_set_focus() after meta_window_show()
+and the delayed focus-in/out events are sent to IBusEngine.
+Now sleep() is added in ibus-compose because MetaWaylandInputMethod
+cannot know the application status while GTK application is already
+realized.
+
+Also GTK4 compose table supports 16bit compose keys only and it
+causes a warning with pt-BR and fi-FI compose tables but the warning
+is treated as a failure with g_test_init().
+Set LANG=en_US.UTF-8 for thw workaround to test pt-BR and fi-FI IBus
+compose tables.
+
+BUG=https://github.com/ibus/ibus/pull/2657
+---
+ src/tests/ibus-compose.c | 223 ++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 195 insertions(+), 28 deletions(-)
+
+diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c
+index e9f102a1..0679c259 100644
+--- a/src/tests/ibus-compose.c
++++ b/src/tests/ibus-compose.c
+@@ -7,19 +7,24 @@
+ #define RED "\033[0;31m"
+ #define NC "\033[0m"
+
++static gchar *m_test_name;
++static gchar *m_session_name;
+ static IBusBus *m_bus;
+ static gchar *m_compose_file;
+ static IBusComposeTableEx *m_compose_table;
+ static IBusEngine *m_engine;
+ static gchar *m_srcdir;
++static gboolean m_is_gtk_32bit_compose_error;
+ static GMainLoop *m_loop;
++static char *m_engine_is_focused;
+ #if GTK_CHECK_VERSION (4, 0, 0)
+ static gboolean m_list_toplevel;
+ #endif
+
+ typedef enum {
++ TEST_COMMIT_TEXT,
+ TEST_CREATE_ENGINE,
+- TEST_COMMIT_TEXT
++ TEST_DELAYED_FOCUS_IN
+ } TestIDleCategory;
+
+ typedef struct _TestIdleData {
+@@ -39,6 +44,19 @@ static gboolean window_focus_in_event_cb (GtkWidget *entry,
+ #endif
+
+
++gboolean
++is_integrated_desktop ()
++{
++ if (!m_session_name)
++ m_session_name = g_strdup (g_getenv ("XDG_SESSION_DESKTOP"));
++ if (!m_session_name)
++ return FALSE;
++ if (!g_ascii_strncasecmp (m_session_name, "gnome", strlen ("gnome")))
++ return TRUE;
++ return FALSE;
++}
++
++
+ gboolean
+ _wait_for_key_release_cb (gpointer user_data)
+ {
+@@ -63,11 +81,15 @@ get_compose_path ()
+ const gchar * const *l;
+ gchar *compose_path = NULL;
+
++ if (m_is_gtk_32bit_compose_error)
++ g_assert (g_setenv ("LANG", m_test_name, TRUE));
+ #if GLIB_CHECK_VERSION (2, 58, 0)
+ langs = g_get_language_names_with_category ("LC_CTYPE");
+ #else
+ langs = g_get_language_names ();
+ #endif
++ if (m_is_gtk_32bit_compose_error)
++ g_assert (g_setenv ("LANG", "en_US.UTF-8", TRUE));
+ for (l = langs; *l; l++) {
+ if (g_str_has_prefix (*l, "en_US"))
+ break;
+@@ -91,6 +113,9 @@ gboolean
+ idle_cb (gpointer user_data)
+ {
+ TestIdleData *data = (TestIdleData *)user_data;
++ static int n = 0;
++ gboolean terminate_program = FALSE;
++
+ g_assert (data);
+ switch (data->category) {
+ case TEST_CREATE_ENGINE:
+@@ -103,23 +128,75 @@ idle_cb (gpointer user_data)
+ if (g_main_loop_is_running (m_loop))
+ g_main_loop_quit (m_loop);
+ g_clear_pointer (&m_loop, g_main_loop_unref);
+-#if GTK_CHECK_VERSION (4, 0, 0)
+- m_list_toplevel = FALSE;
+-#else
+- gtk_main_quit ();
+-#endif
++ terminate_program = TRUE;
+ }
+ data->idle_id = 0;
+ break;
++ case TEST_DELAYED_FOCUS_IN:
++ if (m_engine_is_focused) {
++ data->idle_id = 0;
++ n = 0;
++ g_main_loop_quit (m_loop);
++ return G_SOURCE_REMOVE;
++ }
++ if (n++ < 10) {
++ g_test_message ("Waiting for \"focus-in\" signal %dth times", n);
++ return G_SOURCE_CONTINUE;
++ }
++ g_test_fail_printf ("\"focus-in\" signal is timeout.");
++ g_main_loop_quit (m_loop);
++ terminate_program = TRUE;
++ n = 0;
++ break;
+ default:
+ g_test_fail_printf ("Idle func is called by wrong category:%d.",
+ data->category);
+ break;
+ }
++ if (terminate_program) {
++#if GTK_CHECK_VERSION (4, 0, 0)
++ m_list_toplevel = FALSE;
++#else
++ gtk_main_quit ();
++#endif
++ }
+ return G_SOURCE_REMOVE;
+ }
+
+
++static void
++engine_focus_in_cb (IBusEngine *engine,
++#ifdef IBUS_FOCUS_IN_ID
++ gchar *object_path,
++ gchar *client,
++#endif
++ gpointer user_data)
++{
++#ifdef IBUS_FOCUS_IN_ID
++ g_test_message ("engine_focus_in_cb %s %s", object_path, client);
++ m_engine_is_focused = g_strdup (client);
++#else
++ g_test_message ("engine_focus_in_cb");
++ m_engine_is_focused = g_strdup ("No named");
++#endif
++}
++
++static void
++engine_focus_out_cb (IBusEngine *engine,
++#ifdef IBUS_FOCUS_IN_ID
++ gchar *object_path,
++#endif
++ gpointer user_data)
++{
++#ifdef IBUS_FOCUS_IN_ID
++ g_test_message ("engine_focus_out_cb %s", object_path);
++#else
++ g_test_message ("engine_focus_out_cb");
++#endif
++ g_clear_pointer (&m_engine_is_focused, g_free);
++}
++
++
+ static IBusEngine *
+ create_engine_cb (IBusFactory *factory,
+ const gchar *name,
+@@ -135,11 +212,30 @@ create_engine_cb (IBusFactory *factory,
+ g_assert (data);
+ /* Don't reset idle_id to avoid duplicated register_ibus_engine(). */
+ g_source_remove (data->idle_id);
+- m_engine = ibus_engine_new_with_type (IBUS_TYPE_ENGINE_SIMPLE,
+- name,
+- engine_path,
+- ibus_bus_get_connection (m_bus));
++ m_engine = (IBusEngine *)g_object_new (
++ IBUS_TYPE_ENGINE_SIMPLE,
++ "engine-name", name,
++ "object-path", engine_path,
++ "connection", ibus_bus_get_connection (m_bus),
++#ifdef IBUS_FOCUS_IN_ID
++ "has-focus-id", TRUE,
++#endif
++ NULL);
+ g_free (engine_path);
++
++ m_engine_is_focused = NULL;
++#ifdef IBUS_FOCUS_IN_ID
++ g_signal_connect (m_engine, "focus-in-id",
++#else
++ g_signal_connect (m_engine, "focus-in",
++#endif
++ G_CALLBACK (engine_focus_in_cb), NULL);
++#ifdef IBUS_FOCUS_IN_ID
++ g_signal_connect (m_engine, "focus-out-id",
++#else
++ g_signal_connect (m_engine, "focus-out",
++#endif
++ G_CALLBACK (engine_focus_out_cb), NULL);
+ if (m_compose_file)
+ compose_path = g_build_filename (m_srcdir, m_compose_file, NULL);
+ else
+@@ -235,6 +331,13 @@ set_engine_cb (GObject *object,
+ return;
+ }
+
++ /* ibus_im_context_focus_in() is called after GlboalEngine is set. */
++ if (is_integrated_desktop () && !m_engine_is_focused) {
++ data.category = TEST_DELAYED_FOCUS_IN;
++ data.idle_id = g_timeout_add_seconds (1, idle_cb, &data);
++ g_main_loop_run (m_loop);
++ if (data.idle_id != 0)
++ return;
+ if (m_compose_table == NULL) {
+ g_test_skip ("Your locale uses en_US compose table.");
+ idle_cb (&data);
+@@ -319,6 +422,7 @@ set_engine (gpointer user_data)
+ {
+ g_test_message ("set_engine() is calling");
+ g_assert (m_bus != NULL);
++
+ ibus_bus_set_global_engine_async (m_bus,
+ "xkbtest:us::eng",
+ -1,
+@@ -346,6 +450,11 @@ event_controller_enter_delay (gpointer user_data)
+ }
+ if (i++ == 10) {
+ g_test_fail_printf ("Window is not realized with %d times", i);
++#if GTK_CHECK_VERSION (4, 0, 0)
++ m_list_toplevel = FALSE;
++#else
++ gtk_main_quit ();
++#endif
+ return G_SOURCE_REMOVE;
+ }
+ g_test_message ("event_controller_enter_delay %d", i);
+@@ -360,16 +469,43 @@ event_controller_enter_cb (GtkEventController *controller,
+ static guint id = 0;
+
+ g_test_message ("EventController emits \"enter\" signal");
+- /* Call an idle function because gtk_widget_add_controller()
+- * calls g_list_prepend() for event_controllers and this controller is
+- * always called before "gtk-text-focus-controller"
+- * is caleld and the IM context does not receive the focus-in yet.
+- */
+ if (id)
+ return;
+- id = g_idle_add (event_controller_enter_delay, controller);
++ if (is_integrated_desktop ()) {
++ /* Wait for 3 seconds in GNOME Wayland because there is a long time lag
++ * between the "enter" signal on the event controller in GtkText
++ * and the "FocusIn" D-Bus signal in BusInputContext of ibus-daemon
++ * because mutter/core/window.c:meta_window_show() calls
++ * mutter/core/window.c:meta_window_focus() ->
++ * mutter/wayland/meta-wayland-text-input.c:
++ * meta_wayland_text_input_set_focus() ->
++ * mutter/clutter/clutter/clutter-input-method.c:
++ * clutter_input_method_focus_out()
++ * I.e. "FocusOut" and "FocusIn" D-Bus methods are always delayed
++ * against the window present in GNOME Wayland.
++ * If "FocusOut" and "FocusIn" D-Bus signals would be called after
++ * "SetGlobalEngine" D-BUs signal was called in ibus-daemon,
++ * the following functions could be called:
++ * engine_focus_out_cb() for the "gnome-shell" context
++ * engine_focus_in_cb() for the "fake" context
++ * engine_focus_out_cb() for the "fake" context
++ * engine_focus_in_cb() for the "gnome-shell" context
++ * and ibus_engine_commit_text() would not work.
++ * This assume the focus-in/out signals are called within the timeout
++ * seconds.
++ */
++ id = g_timeout_add_seconds (3,
++ event_controller_enter_delay,
++ controller);
++ } else {
++ /* Call an idle function in Xorg because gtk_widget_add_controller()
++ * calls g_list_prepend() for event_controllers and this controller is
++ * always called before "gtk-text-focus-controller"
++ * is caleld and the IM context does not receive the focus-in yet.
++ */
++ id = g_idle_add (event_controller_enter_delay, controller);
++ }
+ }
+-
+ #else
+
+ static gboolean
+@@ -550,10 +686,18 @@ static void
+ test_init (void)
+ {
+ char *tty_name = ttyname (STDIN_FILENO);
+- GMainLoop *loop = g_main_loop_new (NULL, TRUE);
++ GMainLoop *loop;
++ static guint idle_id = 0;
++
++ if (idle_id) {
++ g_test_incomplete ("Test is called twice due to a timeout.");
++ return;
++ }
++
++ loop = g_main_loop_new (NULL, TRUE);
+ g_test_message ("Test on %s", tty_name ? tty_name : "(null)");
+ if (tty_name && g_strstr_len (tty_name, -1, "pts")) {
+- g_timeout_add_seconds (3, _wait_for_key_release_cb, loop);
++ idle_id = g_timeout_add_seconds (3, _wait_for_key_release_cb, loop);
+ g_main_loop_run (loop);
+ }
+ g_main_loop_unref (loop);
+@@ -586,14 +730,16 @@ test_compose (void)
+ gtk_main ();
+ #endif
+ g_log_set_always_fatal (flags);
++ g_clear_pointer (&m_engine_is_focused, g_free);
++ g_clear_pointer (&m_session_name, g_free);
+ }
+
+
+ int
+ main (int argc, char *argv[])
+ {
+- gchar *test_name;
+ gchar *test_path;
++ int retval;
+
+ ibus_init ();
+ /* Avoid a warning of "AT-SPI: Could not obtain desktop path or name"
+@@ -612,21 +758,42 @@ main (int argc, char *argv[])
+ ? g_strdup (argv[1]) : g_strdup (".");
+ m_compose_file = g_strdup (g_getenv ("COMPOSE_FILE"));
+ #if GLIB_CHECK_VERSION (2, 58, 0)
+- test_name = g_strdup (g_get_language_names_with_category ("LC_CTYPE")[0]);
++ m_test_name = g_strdup (g_get_language_names_with_category ("LC_CTYPE")[0]);
+ #else
+- test_name = g_strdup (g_getenv ("LANG"));
++ m_test_name = g_strdup (g_getenv ("LANG"));
+ #endif
+ if (m_compose_file &&
+- (!test_name || !g_ascii_strncasecmp (test_name, "en_US", 5))) {
+- g_free (test_name);
+- test_name = g_path_get_basename (m_compose_file);
++ (!m_test_name || !g_ascii_strncasecmp (m_test_name, "en_US", 5))) {
++ g_free (m_test_name);
++ m_test_name = g_path_get_basename (m_compose_file);
++ }
++ /* The parent of GtkIMContextWayland is GtkIMContextSimple and
++ * it outputs a warning of "Can't handle >16bit keyvals" in
++ * gtk/gtkcomposetable.c:parse_compose_sequence() in pt-BR locales
++ * and any warnings are treated as errors with g_test_run()
++ * So export LANG=en_US.UTF-8 for GNOME Wayland as a workaround.
++ */
++ if (m_test_name && (!g_ascii_strncasecmp (m_test_name, "pt_BR", 5) ||
++ !g_ascii_strncasecmp (m_test_name, "fi_FI", 5)
++ )) {
++ m_is_gtk_32bit_compose_error = TRUE;
++ }
++ if (m_is_gtk_32bit_compose_error) {
++#if 1
++ g_assert (g_setenv ("LANG", "en_US.UTF-8", TRUE));
++#else
++ /* FIXME: Use expected_messages in g_log_structured() */
++ g_test_expect_message ("Gtk", G_LOG_LEVEL_WARNING,
++ "Can't handle >16bit keyvals");
++#endif
+ }
+ g_test_add_func ("/ibus-compose/test-init", test_init);
+ m_loop = g_main_loop_new (NULL, TRUE);
+- test_path = g_build_filename ("/ibus-compose", test_name, NULL);
++ test_path = g_build_filename ("/ibus-compose", m_test_name, NULL);
+ g_test_add_func (test_path, test_compose);
+ g_free (test_path);
+- g_free (test_name);
+
+- return g_test_run ();
++ retval = g_test_run ();
++ g_free (m_test_name);
++ return retval;
+ }
+--
+2.45.0
+
+From b485ef777352f2e4f0b1ef458826a0aff0c8d136 Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Sat, 27 Jul 2024 19:19:43 +0900
+Subject: [PATCH 6/6] src/tests: Fix some CI issues with busy TMT virtual
+ session
+
+- Increase waiting time in ibus-compose-locales.
+- Wait for 3 secs after set-engine in ibus-compose to wait for the delayed
+ focus-in/out events.
+- delete screendump option in ibus-desktop-testing.desktop not to
+ support no display.
+- setlocale in ibus-engine-switch to get UTF-8 warnings.
+- Quote file names as shell syntax as much as possible.
+- Check file existent and do not use "rm -f" as much as possible.
+- Do not set GTK_IM_MODULE=ibus for Wayland.
+
+BUG=https://github.com/ibus/ibus/pull/2657
+---
+ src/tests/ibus-compose-locales.in | 4 +-
+ src/tests/ibus-compose.c | 23 ++++--
+ src/tests/ibus-desktop-testing-autostart.in | 1 +
+ src/tests/ibus-desktop-testing-module | 79 ++++++++++++++++-----
+ src/tests/ibus-desktop-testing.desktop.in | 2 +-
+ src/tests/ibus-engine-switch.c | 3 +
+ 6 files changed, 85 insertions(+), 27 deletions(-)
+
+diff --git a/src/tests/ibus-compose-locales.in b/src/tests/ibus-compose-locales.in
+index 7a133ce0..485204c0 100755
+--- a/src/tests/ibus-compose-locales.in
++++ b/src/tests/ibus-compose-locales.in
+@@ -15,8 +15,8 @@ do
+ if [ "x$IS_COMMENT" != x ] ; then
+ continue
+ fi
+- while [ x"$IBUS_DAEMON_WITH_SYSTEMD" != x ] && [ $INITED -lt 6 ] ; do
+- echo "Waiting for ${INITED}0 secs till 60 secs"
++ while [ x"$IBUS_DAEMON_WITH_SYSTEMD" != x ] && [ $INITED -lt 12 ] ; do
++ echo "Waiting for ${INITED}0 secs till 120 secs"
+ sleep 10
+ INITED=`expr $INITED + 1`
+ done
+diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c
+index 0679c259..326d3b90 100644
+--- a/src/tests/ibus-compose.c
++++ b/src/tests/ibus-compose.c
+@@ -331,13 +331,22 @@ set_engine_cb (GObject *object,
+ return;
+ }
+
+- /* ibus_im_context_focus_in() is called after GlboalEngine is set. */
+- if (is_integrated_desktop () && !m_engine_is_focused) {
+- data.category = TEST_DELAYED_FOCUS_IN;
+- data.idle_id = g_timeout_add_seconds (1, idle_cb, &data);
+- g_main_loop_run (m_loop);
+- if (data.idle_id != 0)
+- return;
++ /* ibus_im_context_focus_in() is called after GlboalEngine is set.
++ * The focus-in/out events happen more slowly in a busy system
++ * likes with a TMT tool.
++ */
++ if (is_integrated_desktop () && g_getenv ("IBUS_DAEMON_WITH_SYSTEMD")) {
++ g_test_message ("Start tiny \"focus-in\" signal test");
++ for (i = 0; i < 3; i++) {
++ data.category = TEST_DELAYED_FOCUS_IN;
++ data.idle_id = g_timeout_add_seconds (1, idle_cb, &data);
++ g_main_loop_run (m_loop);
++ if (data.idle_id != 0)
++ return;
++ }
++ g_test_message ("End tiny \"focus-in\" signal test");
++ data.category = TEST_COMMIT_TEXT;
++ }
+ if (m_compose_table == NULL) {
+ g_test_skip ("Your locale uses en_US compose table.");
+ idle_cb (&data);
+diff --git a/src/tests/ibus-desktop-testing-autostart.in b/src/tests/ibus-desktop-testing-autostart.in
+index d50354df..9ecc8c27 100755
+--- a/src/tests/ibus-desktop-testing-autostart.in
++++ b/src/tests/ibus-desktop-testing-autostart.in
+@@ -73,6 +73,7 @@ main()
+ parse_args "$@"
+ init_session
+ check_env
++ #run_monitor
+ save_screen
+ run_test_suite
+ finit
+diff --git a/src/tests/ibus-desktop-testing-module b/src/tests/ibus-desktop-testing-module
+index 2d686813..e576df87 100755
+--- a/src/tests/ibus-desktop-testing-module
++++ b/src/tests/ibus-desktop-testing-module
+@@ -63,8 +63,9 @@ pwd
+ pstree -asp $$
+ gsettings list-recursively org.gnome.shell
+ rpm -q gnome-shell-extension-no-overview gnome-shell gnome-session
+-ps -ef | grep ibus | grep -v grep
++ps -ef | grep ibus | grep -v TMT | grep -v grep
+ ibus address
++locale
+ env
+ #dbus-send --session --print-reply --dest=org.gnome.Shell.Introspect /org/gnome/Shell/Introspect org.gnome.Shell.Introspect.GetWindows
+ '
+@@ -133,7 +134,8 @@ check_tty()
+ TTY=`tty`
+ if echo $PROGNAME | grep -q runner ; then
+ if [ $ENABLED_SYSTEMD -eq 1 ] && [ $SESSION_IS_GNOME -eq 1 ] ; then
+- if echo "$TTY" | grep -E 'tty|console' ; then
++ # "not a tty" is correct with TMT tool
++ if echo "$TTY" | grep -E 'tty|console' | grep -v "not a tty" ; then
+ print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: Changing runlevel does not support console. Please log into the host with ssh."
+ exit 1
+ fi
+@@ -143,7 +145,7 @@ check_tty()
+ print_log -e "Running session with ssh. It might be good to use console instead."
+ fi
+ fi
+- SESSION=`ps -ef | grep session | grep -v grep`
++ SESSION=`ps -ef | grep session | grep -v TMT | grep -v grep`
+ if [ x"$SESSION" != x ] ; then
+ print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: Session is running: $SESSION"
+ exit 1
+@@ -254,7 +256,8 @@ create_xdg_autostart()
+ exit 1
+ fi
+ mkdir -p "$TEST_USER_HOME/.config/autostart"
+- cp "$desktop_file" "$TEST_USER_HOME/.config/autostart"
++ sed -e "s/\(^Exec=.*\)tests ibus\(.*\)/\1tests $TESTS\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"
+ chown -R "$TEST_USER" "$TEST_USER_HOME/.config"
+@@ -327,6 +330,9 @@ init_session()
+
+ LOGIN_USER=$USER
+ LOGIN_HOME=$HOME
++ if [ x"$TESTS" = x ] ; then
++ TESTS='ibus'
++ fi
+ check_tty
+ if [ $ENABLED_SYSTEMD -eq 1 ] && [ $SESSION_IS_GNOME -eq 1 ] ; then
+ SESSION_FILE1="/usr/lib/systemd/system/gnome-headless-session@.service"
+@@ -482,9 +488,25 @@ init_gnome()
+ chown -R $LOGIN_USER $TEST_USER_HOME/.local
+ fi
+ fi
++
++ ## Use gnome-headless-session for the no-graphics option because currently
++ ## GDM itself cannot run the login screen(greeter) without a display so
++ ## the no-graphics option does not work with GDM and the TMT tool
++ ## while GDM can invoke the headless GNOME Wayland sessions.
++ ##
++ ## Use GNOME_SHELL_WAYLAND_COMMAND for the no-graphics option to add a
++ ## virtual monitor since gnome-headless-session provides a headless mode
++ ## but no monitor and IBus focus-in/out events does not work without
++ ## any monitors.
++ ##
++ ## Use the systemd locale configuration for the no-graphcis mode since
++ ## gnome-headless-session does not pull LANG from AccountsService.
++ ##
+ if [ $LOGIN_USER != $USER ] ; then
+ SHELL_SERVICE_FILE="org.gnome.Shell@wayland.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 test $HAVE_GRAPHICS -ne 1 ; then
+ if test ! -f "$SYSTEMD_USER_DIR/$SHELL_SERVICE_FILE" ; then
+ mkdir -p "$SYSTEMD_USER_DIR"
+@@ -494,12 +516,19 @@ init_gnome()
+ > $SHELL_SERVICE_FILE
+ diff $SYSTEMD_SYSTEM_DIR/$SHELL_SERVICE_FILE $SHELL_SERVICE_FILE
+ popd
+- chown -R $LOGIN_USER "$TEST_USER_HOME/.config"
+ fi
++ mkdir -p "$ENV_USER_DIR"
++ cat > "$LOCALE_CONF" << _EOF_LOCALE_CONF
++LANG=$SESSION_LANG
++_EOF_LOCALE_CONF
++ chown -R $LOGIN_USER "$TEST_USER_HOME/.config"
+ else
+ if test -f "$SYSTEMD_USER_DIR/$SHELL_SERVICE_FILE" ; then
+ rm "$SYSTEMD_USER_DIR/$SHELL_SERVICE_FILE"
+ fi
++ if test -f "$LOCALE_CONF" ; then
++ rm "$LOCALE_CONF"
++ fi
+ fi
+ fi
+ GET_DISABLE_USER_EX="gsettings get org.gnome.shell disable-user-extensions"
+@@ -556,7 +585,7 @@ operate_desktop_with_systemd()
+ SESSION=gnome-headless-session
+ COMMAND="$1"
+
+- #if test $HAVE_GRAPHICS -eq 1 ; then
++ if test $HAVE_GRAPHICS -eq 1 ; then
+ case "$COMMAND" in
+ "start") systemctl isolate graphical.target
+ echo ""
+@@ -565,22 +594,24 @@ operate_desktop_with_systemd()
+ "") print_log -e "${RED}FAIL${NC}: ${RED}ERROR${NC}: Wrong command $COMMAND"
+ exit 1;;
+ esac
+- #else
+- # setenforce 0
+- # systemctl $COMMAND ${SESSION}@${TEST_USER}
+- #fi
++ else
++ setenforce 0
++ systemctl $COMMAND ${SESSION}@${TEST_USER}
++ fi
+ case "$COMMAND" in
+ "start") sleep 30;;
+ "") ;;
+ esac
+- #if test $HAVE_GRAPHICS -eq 1 ; then
++ if test $HAVE_GRAPHICS -eq 1 ; then
+ systemctl status --no-pager graphical.target
+- #else
+- # systemctl status --no-pager ${SESSION}@${TEST_USER}
+- #fi
++ else
++ systemctl status --no-pager ${SESSION}@${TEST_USER}
++ fi
+ ps -ef | grep X
+ ps -ef | grep session
+ ps -ef | grep ibus
++ SUSER=`echo "$LOGIN_USER" | cut -c 1-7`
++ ps -ef | grep $SUSER
+ }
+
+
+@@ -639,6 +670,23 @@ run_session()
+ }
+
+
++run_monitor()
++{
++ if ! which gnome-monitor-config > /dev/null ; then
++ print_log -e "${RED}FAIL${NC}: No gnome-monitor-config"
++ return
++ fi
++ if [ $ENABLED_SYSTEMD -ne 1 ] || [ $SESSION_IS_GNOME -ne 1 ] \
++ || [ $HAVE_GRAPHICS -ne 1 ] ; then
++ return
++ fi
++ /usr/libexec/gnome-screen-cast.py -v 1024 768 &
++ sleep 3
++ gnome-monitor-config list
++ #gnome-monitor-config set -LpM Virtual-1 -t normal -m 1024x768@60.004
++}
++
++
+ count_case_result()
+ {
+ retval=$1
+@@ -758,9 +806,6 @@ run_gnome_desktop_testing_runner()
+ {
+ pass=0
+ fail=0
+- if [ x"$TESTS" = x ] ; then
+- TESTS='ibus'
+- fi
+ if echo $PROGNAME | grep -q autostart ; then
+ export IBUS_DAEMON_WITH_SYSTEMD=1
+ fi
+diff --git a/src/tests/ibus-desktop-testing.desktop.in b/src/tests/ibus-desktop-testing.desktop.in
+index e91900ed..fe9356ad 100644
+--- a/src/tests/ibus-desktop-testing.desktop.in
++++ b/src/tests/ibus-desktop-testing.desktop.in
+@@ -2,7 +2,7 @@
+ Name=IBus Desktop Testing Runner
+ GenericName=Input Method Desktop Testing Runner
+ Comment=Test plugin for IBus Desktop Testing
+-Exec=sh -c 'exec @libexecdir@/ibus-desktop-testing-autostart --envcheck --output $HOME/test-autostart.log --result $HOME/test.log --runner gnome --screendump $HOME/screen.log --tests ibus'
++Exec=sh -c 'exec @libexecdir@/ibus-desktop-testing-autostart --envcheck --output $HOME/test-autostart.log --result $HOME/test.log --runner gnome --tests ibus'
+ Terminal=false
+ Type=Application
+ Encoding=UTF-8
+diff --git a/src/tests/ibus-engine-switch.c b/src/tests/ibus-engine-switch.c
+index b50bac59..7359e125 100644
+--- a/src/tests/ibus-engine-switch.c
++++ b/src/tests/ibus-engine-switch.c
+@@ -1,5 +1,6 @@
+ /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+
++#include <locale.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include "ibus.h"
+@@ -251,6 +252,8 @@ main (gint argc,
+ gchar **argv)
+ {
+ gint result;
++ /* To get UTF-8 error messages with glib2 */
++ setlocale (LC_ALL, "");
+ ibus_init ();
+ g_test_init (&argc, &argv, NULL);
+ bus = ibus_bus_new ();
+--
+2.45.0
+
diff --git a/ibus.spec b/ibus.spec
index d28f3d1..63425ea 100644
--- a/ibus.spec
+++ b/ibus.spec
@@ -62,7 +62,7 @@
Name: ibus
Version: 1.5.31~beta1
# https://github.com/fedora-infra/rpmautospec/issues/101
-Release: 9%{?dist}
+Release: 10%{?dist}
Summary: Intelligent Input Bus for Linux OS
License: LGPL-2.1-or-later
URL: https://github.com/ibus/%name/wiki
@@ -609,6 +609,7 @@ dconf update || :
%{_bindir}/ibus-desktop-testing-runner
%{_datadir}/ibus/tests
%{_libexecdir}/ibus-desktop-testing-autostart
+%{_libexecdir}/ibus-desktop-testing-module
%files tests
%dir %{_libexecdir}/installed-tests
@@ -617,6 +618,9 @@ dconf update || :
%{_datadir}/installed-tests/ibus
%changelog
+* Sat Jul 27 2024 Takao Fujiwara <tfujiwar@redhat.com> - 1.5.31~beta1-10
+- Replace GNOME Xorg with GNOME Wayland in CI
+
* Sat Jul 27 2024 Takao Fujiwara <tfujiwar@redhat.com> - 1.5.31~beta1-9
- Update CI for RHEL packages
reply other threads:[~2026-05-31 2:08 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=178019331746.1.10463635213017488872.rpms-ibus-cb19883e9b52@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