From 89bcda34d6998e698a39be8e37df93ef4ec514c1 Mon Sep 17 00:00:00 2001 From: Renbo Date: Mon, 18 Nov 2024 15:13:30 +0800 Subject: [PATCH 1/2] [BA] update to ibus-1.5.25-5.src.rpm to #IB53LH update to ibus-1.5.25-5.src.rpm Signed-off-by: Renbo --- dist | 1 + download | 3 +- ibus-1385349-segv-bus-proxy.patch | 499 +- ibus-1470673-emoji-warn-instead-assert.patch | 48 - ibus-1616-gtk4-sync.patch | 3286 + ibus-1682157-ci.patch | 2639 - ibus-1713606-hangul-with-mouse.patch | 1424 - ibus-1750836-server-auth-observer.patch | 179 - ibus-1897548-emoji-unicode.patch | 347 - ibus-2076-fix-16-candidates.patch | 26 - ibus-HEAD.patch | 1036 +- ...inter-in-GList.SList-for-vala-0.43.4.patch | 193861 --------------- ibus-xx-desktop-testing-mutter.patch | 37 + ibus-xx-emoji-compose.patch | 134 - ibus-xx-setup-env.patch | 60 - ibus.spec | 479 +- 16 files changed, 4144 insertions(+), 199915 deletions(-) create mode 100644 dist delete mode 100644 ibus-1470673-emoji-warn-instead-assert.patch create mode 100644 ibus-1616-gtk4-sync.patch delete mode 100644 ibus-1682157-ci.patch delete mode 100644 ibus-1713606-hangul-with-mouse.patch delete mode 100644 ibus-1750836-server-auth-observer.patch delete mode 100644 ibus-1897548-emoji-unicode.patch delete mode 100644 ibus-2076-fix-16-candidates.patch delete mode 100644 ibus-delete-weak-pointer-in-GList.SList-for-vala-0.43.4.patch create mode 100644 ibus-xx-desktop-testing-mutter.patch delete mode 100644 ibus-xx-emoji-compose.patch delete mode 100644 ibus-xx-setup-env.patch diff --git a/dist b/dist new file mode 100644 index 0000000..89c1faf --- /dev/null +++ b/dist @@ -0,0 +1 @@ +an9 diff --git a/download b/download index 4271991..c4357d8 100644 --- a/download +++ b/download @@ -1,2 +1 @@ -a2be6f200dd9ada2501474a6877a73ef ibus-1.5.19.tar.gz -2bc557e62cc599992812460e3e054bd9 ibus-po-1.5.19-20210706.tar.gz +c1670d622c555aca804b0d6a074ce93e ibus-1.5.25.tar.gz diff --git a/ibus-1385349-segv-bus-proxy.patch b/ibus-1385349-segv-bus-proxy.patch index f206eda..91ca4a7 100644 --- a/ibus-1385349-segv-bus-proxy.patch +++ b/ibus-1385349-segv-bus-proxy.patch @@ -1,108 +1,119 @@ -From 865b204f1c06b782cf7b4a479b358e76f4b3dfee Mon Sep 17 00:00:00 2001 +From 41c325dfb32269c9aadfeedb4df44656aac4d883 Mon Sep 17 00:00:00 2001 From: fujiwarat -Date: Tue, 17 Jul 2018 13:39:30 +0900 -Subject: [PATCH] bus: Fix SEGV in bus_panel_proxy_focus_in() +Date: Fri, 20 Nov 2020 09:53:54 +0900 +Subject: [PATCH] Fix SEGV in bus_panel_proxy_focus_in() + +rhbz#1350291 SEGV in BUS_IS_CONNECTION(skip_connection) in +bus_dbus_impl_dispatch_message_by_rule() +check if dbus_connection is closed in bus_dbus_impl_connection_filter_cb(). + +rhbz#1767976 SEGV in assert(connection != NULL) in +bus_dbus_impl_connection_filter_cb() +call bus_connection_set_filter() in bus_dbus_impl_destroy(). + +rhbz#1601577 rhbz#1797726 SEGV in ibus_engine_desc_get_layout() in +bus_engine_proxy_new_internal() +WIP: Added a GError to get the error message to check why the SEGV happened. + +rhbz#1663528 SEGV in g_mutex_clear() in bus_dbus_impl_destroy() +If the mutex is not unlocked, g_mutex_clear() causes assert. + +rhbz#1767691 SEGV in client/x11/main.c:_sighandler(). +Do not call atexit functions in _sighandler(). + +rhbz#1795499 SEGV in ibus_bus_get_bus_address() because of no _bus->priv. +_changed_cb() should not be called after ibus_bus_destroy() is called. + +rhbz#1771238 SEGV in assert(m_loop == null) in switcher.vala. +Grabbing keyboard could be failed and switcher received the keyboard +events and m_loop was not released. + +rhbz#1797120 SEGV in assert(bus.is_connected()) in panel_binding_construct() +Check m_ibus in extension.vala:bus_name_acquired_cb() -BUG=rhbz#1349148 -BUG=rhbz#1385349 BUG=rhbz#1350291 -BUG=rhbz#1406699 -BUG=rhbz#1432252 BUG=rhbz#1601577 +BUG=rhbz#1663528 +BUG=rhbz#1767691 +BUG=rhbz#1795499 +BUG=rhbz#1771238 +BUG=rhbz#1767976 +BUG=rhbz#1797120 --- - bus/dbusimpl.c | 38 ++++++++++++++++++++++++++++++++------ - bus/engineproxy.c | 5 ++++- - bus/ibusimpl.c | 21 ++++++++++++++++++--- - 3 files changed, 54 insertions(+), 10 deletions(-) + bus/dbusimpl.c | 47 ++++++++++++++++++++++++--- + bus/engineproxy.c | 51 ++++++++++++++++++++++------- + client/x11/main.c | 8 ++++- + src/ibusbus.c | 5 +++ + ui/gtk3/extension.vala | 4 +++ + ui/gtk3/switcher.vala | 73 +++++++++++++++++++++++++----------------- + 6 files changed, 141 insertions(+), 47 deletions(-) diff --git a/bus/dbusimpl.c b/bus/dbusimpl.c -index b54ef817..e4dd8683 100644 +index 59787a80..af2fbde2 100644 --- a/bus/dbusimpl.c +++ b/bus/dbusimpl.c -@@ -2,7 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2008-2013 Red Hat, Inc. -+ * Copyright (C) 2015-2017 Takao Fujiwara -+ * Copyright (C) 2008-2017 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -344,6 +345,8 @@ bus_name_service_set_primary_owner (BusNameService *service, - BusConnectionOwner *owner, - BusDBusImpl *dbus) +@@ -610,6 +610,7 @@ static void + bus_dbus_impl_destroy (BusDBusImpl *dbus) { -+ gboolean has_old_owner = FALSE; -+ - g_assert (service != NULL); - g_assert (owner != NULL); - g_assert (dbus != NULL); -@@ -351,6 +354,13 @@ bus_name_service_set_primary_owner (BusNameService *service, - BusConnectionOwner *old = service->owners != NULL ? - (BusConnectionOwner *)service->owners->data : NULL; - -+ /* rhbz#1432252 If bus_connection_get_unique_name() == NULL, -+ * "Hello" method is not received yet. -+ */ -+ if (old != NULL && bus_connection_get_unique_name (old->conn) != NULL) { -+ has_old_owner = TRUE; + GList *p; ++ int i; + + for (p = dbus->objects; p != NULL; p = p->next) { + IBusService *object = (IBusService *) p->data; +@@ -633,6 +634,10 @@ bus_dbus_impl_destroy (BusDBusImpl *dbus) + + for (p = dbus->connections; p != NULL; p = p->next) { + BusConnection *connection = BUS_CONNECTION (p->data); ++ /* rhbz#1767976 Fix connection == NULL in ++ * bus_dbus_impl_connection_filter_cb() ++ */ ++ bus_connection_set_filter (connection, NULL, NULL, NULL); + g_signal_handlers_disconnect_by_func (connection, + bus_dbus_impl_connection_destroy_cb, dbus); + ibus_object_destroy (IBUS_OBJECT (connection)); +@@ -647,12 +652,39 @@ bus_dbus_impl_destroy (BusDBusImpl *dbus) + dbus->unique_names = NULL; + dbus->names = NULL; + ++ for (i = 0; g_idle_remove_by_data (dbus); i++) { ++ if (i > 1000) { ++ g_warning ("Too many idle threads were generated by " \ ++ "bus_dbus_impl_forward_message_idle_cb and " \ ++ "bus_dbus_impl_dispatch_message_by_rule_idle_cb"); ++ break; ++ } + } + g_list_free_full (dbus->start_service_calls, + (GDestroyNotify) bus_method_call_free); + dbus->start_service_calls = NULL; + +- g_mutex_clear (&dbus->dispatch_lock); +- g_mutex_clear (&dbus->forward_lock); ++ /* rhbz#1663528 Call g_mutex_trylock() before g_mutex_clear() ++ * because if the mutex is not unlocked, g_mutex_clear() causes assert. ++ */ ++#define BUS_DBUS_MUTEX_SAFE_CLEAR(mtex) { \ ++ int count = 0; \ ++ while (!g_mutex_trylock ((mtex))) { \ ++ g_usleep (1); \ ++ if (count > 60) { \ ++ g_warning (#mtex " is dead lock"); \ ++ break; \ ++ } \ ++ ++count; \ ++ } \ ++ g_mutex_unlock ((mtex)); \ ++ g_mutex_clear ((mtex)); \ ++} + - if (old != NULL) { - g_signal_emit (dbus, - dbus_signals[NAME_LOST], -@@ -370,7 +380,8 @@ bus_name_service_set_primary_owner (BusNameService *service, - 0, - owner->conn, - service->name, -- old != NULL ? bus_connection_get_unique_name (old->conn) : "", -+ has_old_owner ? bus_connection_get_unique_name (old->conn) : -+ "", - bus_connection_get_unique_name (owner->conn)); - - if (old != NULL && old->do_not_queue != 0) { -@@ -427,6 +438,7 @@ bus_name_service_remove_owner (BusNameService *service, - BusDBusImpl *dbus) - { - GSList *owners; -+ gboolean has_new_owner = FALSE; - - g_assert (service != NULL); - g_assert (owner != NULL); -@@ -439,6 +451,13 @@ bus_name_service_remove_owner (BusNameService *service, - BusConnectionOwner *_new = NULL; - if (owners->next != NULL) { - _new = (BusConnectionOwner *)owners->next->data; -+ /* rhbz#1406699 If bus_connection_get_unique_name() == NULL, -+ * "Hello" method is not received yet. -+ */ -+ if (_new != NULL && -+ bus_connection_get_unique_name (_new->conn) != NULL) { -+ has_new_owner = TRUE; -+ } - } - - if (dbus != NULL) { -@@ -447,7 +466,7 @@ bus_name_service_remove_owner (BusNameService *service, - 0, - owner->conn, - service->name); -- if (_new != NULL) { -+ if (has_new_owner) { - g_signal_emit (dbus, - dbus_signals[NAME_ACQUIRED], - 0, -@@ -460,7 +479,7 @@ bus_name_service_remove_owner (BusNameService *service, - _new != NULL ? _new->conn : NULL, - service->name, - bus_connection_get_unique_name (owner->conn), -- _new != NULL ? bus_connection_get_unique_name (_new->conn) : ""); -+ has_new_owner ? bus_connection_get_unique_name (_new->conn) : ""); - - } - } -@@ -1464,13 +1483,20 @@ bus_dbus_impl_connection_filter_cb (GDBusConnection *dbus_connection, ++ BUS_DBUS_MUTEX_SAFE_CLEAR (&dbus->dispatch_lock); ++ BUS_DBUS_MUTEX_SAFE_CLEAR (&dbus->forward_lock); ++ ++#undef BUS_DBUS_MUTEX_SAFE_CLEAR + + /* FIXME destruct _lock and _queue members. */ + IBUS_OBJECT_CLASS(bus_dbus_impl_parent_class)->destroy ((IBusObject *) dbus); +@@ -1483,13 +1515,20 @@ bus_dbus_impl_connection_filter_cb (GDBusConnection *dbus_connection, gboolean incoming, gpointer user_data) { @@ -126,89 +137,267 @@ index b54ef817..e4dd8683 100644 if (incoming) { /* is incoming message */ diff --git a/bus/engineproxy.c b/bus/engineproxy.c -index 2d98995c..d661673a 100644 +index 2d98995c..bbbe5532 100644 --- a/bus/engineproxy.c +++ b/bus/engineproxy.c -@@ -665,6 +665,7 @@ bus_engine_proxy_new_internal (const gchar *path, +@@ -660,20 +660,33 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy, + g_return_if_reached (); + } + ++#pragma GCC optimize ("O0") + static BusEngineProxy * + bus_engine_proxy_new_internal (const gchar *path, IBusEngineDesc *desc, - GDBusConnection *connection) +- GDBusConnection *connection) ++ GDBusConnection *connection, ++ GError **error) { -+ GError *error = NULL; ++ GDBusProxyFlags flags; ++ BusEngineProxy *engine; ++ g_assert (path); g_assert (IBUS_IS_ENGINE_DESC (desc)); g_assert (G_IS_DBUS_CONNECTION (connection)); -@@ -673,7 +674,7 @@ bus_engine_proxy_new_internal (const gchar *path, - BusEngineProxy *engine = ++ g_assert (error && *error == NULL); + +- GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START; +- BusEngineProxy *engine = ++ /* rhbz#1601577 engine == NULL if connection is closed. */ ++ if (g_dbus_connection_is_closed (connection)) { ++ *error = g_error_new (G_DBUS_ERROR, ++ G_DBUS_ERROR_FAILED, ++ "Connection is closed."); ++ return NULL; ++ } ++ flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START; ++ engine = (BusEngineProxy *) g_initable_new (BUS_TYPE_ENGINE_PROXY, NULL, - NULL, -+ &error, ++ error, "desc", desc, "g-connection", connection, "g-interface-name", IBUS_INTERFACE_ENGINE, -@@ -681,6 +682,8 @@ bus_engine_proxy_new_internal (const gchar *path, +@@ -681,12 +694,19 @@ bus_engine_proxy_new_internal (const gchar *path, "g-default-timeout", g_gdbus_timeout, "g-flags", flags, NULL); + /* FIXME: rhbz#1601577 */ -+ g_assert_no_error (error); ++ if (!engine) { ++ /* show abrt local variable */ ++ gchar *message = g_strdup ((*error)->message); ++ g_error ("%s", message); ++ } const gchar *layout = ibus_engine_desc_get_layout (desc); if (layout != NULL && layout[0] != '\0') { engine->keymap = ibus_keymap_get (layout); -diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c -index ec1caea8..9ae3751b 100644 ---- a/bus/ibusimpl.c -+++ b/bus/ibusimpl.c -@@ -484,13 +484,16 @@ _dbus_name_owner_changed_cb (BusDBusImpl *dbus, - else if (!g_strcmp0 (name, IBUS_SERVICE_PANEL_EXTENSION_EMOJI)) - panel_type = PANEL_TYPE_EXTENSION_EMOJI; - -- if (panel_type != PANEL_TYPE_NONE) { -+ do { -+ if (panel_type == PANEL_TYPE_NONE) -+ break; - if (g_strcmp0 (new_name, "") != 0) { - /* a Panel process is started. */ - BusConnection *connection; - BusInputContext *context = NULL; - BusPanelProxy **panel = (panel_type == PANEL_TYPE_PANEL) ? - &ibus->panel : &ibus->emoji_extension; -+ GDBusConnection *dbus_connection = NULL; - - if (*panel != NULL) { - ibus_proxy_destroy ((IBusProxy *)(*panel)); -@@ -499,9 +502,21 @@ _dbus_name_owner_changed_cb (BusDBusImpl *dbus, - g_assert (*panel == NULL); - } - -- connection = bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, new_name); -+ connection = bus_dbus_impl_get_connection_by_name (BUS_DEFAULT_DBUS, -+ new_name); - g_return_if_fail (connection != NULL); - -+ dbus_connection = bus_connection_get_dbus_connection (connection); -+ /* rhbz#1349148 rhbz#1385349 -+ * Avoid SEGV of BUS_IS_PANEL_PROXY (ibus->panel) -+ * This function is called during destroying the connection -+ * in this case? */ -+ if (dbus_connection == NULL || -+ g_dbus_connection_is_closed (dbus_connection)) { -+ new_name = ""; -+ break; -+ } + } + return engine; + } ++#pragma GCC reset_options + + typedef struct { + GTask *task; +@@ -748,23 +768,30 @@ create_engine_ready_cb (BusFactoryProxy *factory, + GAsyncResult *res, + EngineProxyNewData *data) + { ++ GError *error = NULL; ++ gchar *path; ++ BusEngineProxy *engine; + - *panel = bus_panel_proxy_new (connection, panel_type); - if (panel_type == PANEL_TYPE_EXTENSION_EMOJI) - ibus->enable_emoji_extension = FALSE; -@@ -555,7 +570,7 @@ _dbus_name_owner_changed_cb (BusDBusImpl *dbus, - } - } - } -- } -+ } while (0); - - bus_ibus_impl_component_name_owner_changed (ibus, name, old_name, new_name); + g_return_if_fail (data->task != NULL); + +- GError *error = NULL; +- gchar *path = bus_factory_proxy_create_engine_finish (factory, +- res, +- &error); ++ path = bus_factory_proxy_create_engine_finish (factory, res, &error); + if (path == NULL) { + g_task_return_error (data->task, error); + engine_proxy_new_data_free (data); + return; + } + +- BusEngineProxy *engine = +- bus_engine_proxy_new_internal (path, +- data->desc, +- g_dbus_proxy_get_connection ((GDBusProxy *)data->factory)); ++ engine = bus_engine_proxy_new_internal ( ++ path, ++ data->desc, ++ g_dbus_proxy_get_connection ((GDBusProxy *)data->factory), ++ &error); + g_free (path); ++ if (!engine) { ++ g_task_return_error (data->task, error); ++ engine_proxy_new_data_free (data); ++ return; ++ } + + /* FIXME: set destroy callback ? */ + g_task_return_pointer (data->task, engine, NULL); +diff --git a/client/x11/main.c b/client/x11/main.c +index c9ee174d..768b91f0 100644 +--- a/client/x11/main.c ++++ b/client/x11/main.c +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + + #include + +@@ -1104,7 +1105,12 @@ _atexit_cb () + static void + _sighandler (int sig) + { +- exit(EXIT_FAILURE); ++ /* rhbz#1767691 _sighandler() is called with SIGTERM ++ * and exit() causes SEGV during calling atexit functions. ++ * _atexit_cb() might be broken. _exit() does not call ++ * atexit functions. ++ */ ++ _exit(EXIT_FAILURE); } + + static void +diff --git a/src/ibusbus.c b/src/ibusbus.c +index b7ffbb47..668c8a26 100644 +--- a/src/ibusbus.c ++++ b/src/ibusbus.c +@@ -689,6 +689,11 @@ ibus_bus_destroy (IBusObject *object) + _bus = NULL; + + if (bus->priv->monitor) { ++ /* rhbz#1795499 _changed_cb() causes SEGV because of no bus->priv ++ * after ibus_bus_destroy() is called. ++ */ ++ g_signal_handlers_disconnect_by_func (bus->priv->monitor, ++ (GCallback) _changed_cb, bus); + g_object_unref (bus->priv->monitor); + bus->priv->monitor = NULL; + } +diff --git a/ui/gtk3/extension.vala b/ui/gtk3/extension.vala +index a6f2e8e6..b7a04081 100644 +--- a/ui/gtk3/extension.vala ++++ b/ui/gtk3/extension.vala +@@ -73,6 +73,10 @@ class ExtensionGtk : Gtk.Application { + string signal_name, + Variant parameters) { + debug("signal_name = %s", signal_name); ++ /* rhbz#1797120 Fix assert(bus.is_connected()) in ++ * panel_binding_construct() ++ */ ++ return_if_fail(m_bus.is_connected()); + m_panel = new PanelBinding(m_bus, this); + m_panel.load_settings(); + } +diff --git a/ui/gtk3/switcher.vala b/ui/gtk3/switcher.vala +index a4529c88..29a70dd5 100644 +--- a/ui/gtk3/switcher.vala ++++ b/ui/gtk3/switcher.vala +@@ -140,8 +140,8 @@ class Switcher : Gtk.Window { + IBus.EngineDesc[] engines, + int index, + string input_context_path) { +- assert (m_loop == null); +- assert (index < engines.length); ++ assert(m_loop == null); ++ assert(index < engines.length); + + m_is_running = true; + m_keyval = keyval; +@@ -198,16 +198,18 @@ class Switcher : Gtk.Window { + null, + event, + null); +- if (status != Gdk.GrabStatus.SUCCESS) ++ if (status != Gdk.GrabStatus.SUCCESS) { + warning("Grab keyboard failed! status = %d", status); +- status = seat.grab(get_window(), +- Gdk.SeatCapabilities.POINTER, +- true, +- null, +- event, +- null); +- if (status != Gdk.GrabStatus.SUCCESS) +- warning("Grab pointer failed! status = %d", status); ++ } else { ++ status = seat.grab(get_window(), ++ Gdk.SeatCapabilities.POINTER, ++ true, ++ null, ++ event, ++ null); ++ if (status != Gdk.GrabStatus.SUCCESS) ++ warning("Grab pointer failed! status = %d", status); ++ } + #else + Gdk.Device device = event.get_device(); + if (device == null) { +@@ -243,30 +245,41 @@ class Switcher : Gtk.Window { + Gdk.EventMask.KEY_RELEASE_MASK, + null, + Gdk.CURRENT_TIME); +- if (status != Gdk.GrabStatus.SUCCESS) ++ if (status != Gdk.GrabStatus.SUCCESS) { + warning("Grab keyboard failed! status = %d", status); +- // Grab all pointer events +- status = pointer.grab(get_window(), +- Gdk.GrabOwnership.NONE, +- true, +- Gdk.EventMask.BUTTON_PRESS_MASK | +- Gdk.EventMask.BUTTON_RELEASE_MASK, +- null, +- Gdk.CURRENT_TIME); +- if (status != Gdk.GrabStatus.SUCCESS) +- warning("Grab pointer failed! status = %d", status); ++ } else { ++ // Grab all pointer events ++ status = pointer.grab(get_window(), ++ Gdk.GrabOwnership.NONE, ++ true, ++ Gdk.EventMask.BUTTON_PRESS_MASK | ++ Gdk.EventMask.BUTTON_RELEASE_MASK, ++ null, ++ Gdk.CURRENT_TIME); ++ if (status != Gdk.GrabStatus.SUCCESS) ++ warning("Grab pointer failed! status = %d", status); ++ } + #endif + +- // Probably we can delete m_popup_delay_time in 1.6 +- pointer.get_position_double(null, +- out m_mouse_init_x, +- out m_mouse_init_y); +- m_mouse_moved = false; ++ /* Fix RHBZ #1771238 assert(m_loop == null) ++ * Grabbing keyboard can be failed when the second Super-e is typed ++ * before Switcher dialog is focused. And m_loop could not be released ++ * if the failed Super-e would call m_loop.run() below and could not ++ * call key_release_event(). And m_loop == null would be false in the ++ * third Super-e. ++ */ ++ if (status == Gdk.GrabStatus.SUCCESS) { ++ // Probably we can delete m_popup_delay_time in 1.6 ++ pointer.get_position_double(null, ++ out m_mouse_init_x, ++ out m_mouse_init_y); ++ m_mouse_moved = false; + + +- m_loop = new GLib.MainLoop(); +- m_loop.run(); +- m_loop = null; ++ m_loop = new GLib.MainLoop(); ++ m_loop.run(); ++ m_loop = null; ++ } + + #if VALA_0_34 + seat.ungrab(); -- -2.17.1 +2.24.1 diff --git a/ibus-1470673-emoji-warn-instead-assert.patch b/ibus-1470673-emoji-warn-instead-assert.patch deleted file mode 100644 index 35710f8..0000000 --- a/ibus-1470673-emoji-warn-instead-assert.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0f5084e07c215d74adc4eeeda40b374855cce59a Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 11 Jan 2019 12:56:42 +0900 -Subject: [PATCH] src/ibuscomposetable: Replace assert with warning for - .XCompose - -BUG=rhbz#1470673 ---- - src/ibuscomposetable.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c -index b843e7e1..1c0ece41 100644 ---- a/src/ibuscomposetable.c -+++ b/src/ibuscomposetable.c -@@ -1,7 +1,7 @@ - /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ - /* ibus - The Input Bus - * Copyright (C) 2013-2014 Peng Huang -- * Copyright (C) 2013-2018 Takao Fujiwara -+ * Copyright (C) 2013-2019 Takao Fujiwara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -98,14 +98,16 @@ parse_compose_value (IBusComposeData *compose_data, - uch = words[1][1]; - - /* The escaped string "\"" is separated with '\\' and '"'. */ -- if (uch == '\0' && words[2][0] == '"') -+ if (uch == '\0' && words[2][0] == '"') { - uch = '"'; - /* The escaped octal */ -- else if (uch >= '0' && uch <= '8') -+ } else if (uch >= '0' && uch <= '8') { - uch = g_ascii_strtoll(words[1] + 1, NULL, 8); - /* If we need to handle other escape sequences. */ -- else if (uch != '\\') -- g_assert_not_reached (); -+ } else if (uch != '\\') { -+ g_warning ("Invalid backslash: %s: %s", val, line); -+ goto fail; -+ } - } - - if (g_utf8_get_char (g_utf8_next_char (words[1])) > 0) { --- -2.21.0 - diff --git a/ibus-1616-gtk4-sync.patch b/ibus-1616-gtk4-sync.patch new file mode 100644 index 0000000..ebead81 --- /dev/null +++ b/ibus-1616-gtk4-sync.patch @@ -0,0 +1,3286 @@ +From 5cfe838715097d61b50da55f80bcff2c698ca885 Mon Sep 17 00:00:00 2001 +From: Changwoo Ryu +Date: Fri, 18 Feb 2022 09:07:02 +0900 +Subject: [PATCH] client/gtk2/ibusimcontext: Fix forward key keycode for GTK4 + +When a keycode is provided (!= 0) for a forwarded key event, convert it to a +GTK keycode before passing it to gtk_im_context_filter_key(). + +Also free GdkKeymapKey after gdk_display_map_keyval() is called. + +BUG=https://github.com/ibus/ibus/issues/2380 +BUG=https://github.com/ibus/ibus/issues/2382 +--- + client/gtk2/ibusimcontext.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c +index c2df3a87..a5e5e792 100644 +--- a/client/gtk2/ibusimcontext.c ++++ b/client/gtk2/ibusimcontext.c +@@ -1945,7 +1945,9 @@ _ibus_context_forward_key_event_cb (IBusInputContext *ibuscontext, + #if GTK_CHECK_VERSION (3, 98, 4) + int group = 0; + g_return_if_fail (GTK_IS_IM_CONTEXT (ibusimcontext)); +- if (keycode == 0 && ibusimcontext->client_window) { ++ if (keycode != 0) { ++ keycode += 8; // to GTK keycode ++ } else if (ibusimcontext->client_window) { + GdkDisplay *display = + gtk_widget_get_display (ibusimcontext->client_window); + GdkKeymapKey *keys = NULL; +@@ -1953,6 +1955,7 @@ _ibus_context_forward_key_event_cb (IBusInputContext *ibuscontext, + if (gdk_display_map_keyval (display, keyval, &keys, &n_keys)) { + keycode = keys->keycode; + group = keys->group; ++ g_free (keys); + } else { + g_warning ("Failed to parse keycode from keyval %x", keyval); + } +-- +2.37.3 + +From 8711dc83225a7fade3ba67ab796ecb03b38406ff Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Fri, 20 May 2022 20:54:58 +0900 +Subject: [PATCH] client/gtk2/ibusimcontext: keycode - 8 for gtk3 keycode + generation + +Since IBus keycode subtracts 8 from Linux keycode, keycodes from +gdk_keymap_get_entries_for_keyval() also have to be subtracted 8. +The keycodes will add 8 when they bring back the GDK event loop. +--- + client/gtk2/ibusimcontext.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c +index a5e5e792..07835a24 100644 +--- a/client/gtk2/ibusimcontext.c ++++ b/client/gtk2/ibusimcontext.c +@@ -2,8 +2,8 @@ + /* vim:set et sts=4: */ + /* ibus - The Input Bus + * Copyright (C) 2008-2013 Peng Huang +- * Copyright (C) 2015-2021 Takao Fujiwara +- * Copyright (C) 2008-2021 Red Hat, Inc. ++ * Copyright (C) 2015-2022 Takao Fujiwara ++ * Copyright (C) 2008-2022 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -1980,6 +1980,9 @@ _ibus_context_forward_key_event_cb (IBusInputContext *ibuscontext, + keycode = keys->keycode; + else + g_warning ("Failed to parse keycode from keyval %x", keyval); ++ /* _create_gdk_event() will add 8 to keycode. */ ++ if (keycode != 0) ++ keycode -= 8; + } + GdkEventKey *event = _create_gdk_event (ibusimcontext, keyval, keycode, state); + gdk_event_put ((GdkEvent *)event); +-- +2.37.3 + +From 3e5fab4991f4e2e22b56cf57d4dfb779a1d1977c Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Fri, 20 May 2022 20:54:59 +0900 +Subject: [PATCH] client/gtk2: Revert CCedilla change for pt-BR + +gtk_im_context_simple_add_table() is deprecated in GTK4. +I decide to delete gtk_im_context_simple_add_table() here because +the change 03c9e591430c62354bbf26ef7bd4a2e6acfb7c8f is no longer needed +because IBusEngineSimple has implemented to load pt_br compose key +by locale. + +Fixes: 03c9e591430c62354bbf26ef7bd4a2e6acfb7c8f + +BUG=chromium-os:11421 +BUG=http://codereview.appspot.com/3989060 +--- + client/gtk2/ibusimcontext.c | 31 ------------------------------- + 1 file changed, 31 deletions(-) + +diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c +index 07835a24..c7f23293 100644 +--- a/client/gtk2/ibusimcontext.c ++++ b/client/gtk2/ibusimcontext.c +@@ -874,33 +874,6 @@ ibus_im_context_class_fini (IBusIMContextClass *class) + g_bus_unwatch_name (_daemon_name_watch_id); + } + +-/* Copied from gtk+2.0-2.20.1/modules/input/imcedilla.c to fix crosbug.com/11421. +- * Overwrite the original Gtk+'s compose table in gtk+-2.x.y/gtk/gtkimcontextsimple.c. */ +- +-/* The difference between this and the default input method is the handling +- * of C+acute - this method produces C WITH CEDILLA rather than C WITH ACUTE. +- * For languages that use CCedilla and not acute, this is the preferred mapping, +- * and is particularly important for pt_BR, where the us-intl keyboard is +- * used extensively. +- */ +-static guint16 cedilla_compose_seqs[] = { +-#ifdef DEPRECATED_GDK_KEYSYMS +- GDK_dead_acute, GDK_C, 0, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */ +- GDK_dead_acute, GDK_c, 0, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */ +- GDK_Multi_key, GDK_apostrophe, GDK_C, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */ +- GDK_Multi_key, GDK_apostrophe, GDK_c, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */ +- GDK_Multi_key, GDK_C, GDK_apostrophe, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */ +- GDK_Multi_key, GDK_c, GDK_apostrophe, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */ +-#else +- GDK_KEY_dead_acute, GDK_KEY_C, 0, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */ +- GDK_KEY_dead_acute, GDK_KEY_c, 0, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */ +- GDK_KEY_Multi_key, GDK_KEY_apostrophe, GDK_KEY_C, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */ +- GDK_KEY_Multi_key, GDK_KEY_apostrophe, GDK_KEY_c, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */ +- GDK_KEY_Multi_key, GDK_KEY_C, GDK_KEY_apostrophe, 0, 0, 0x00C7, /* LATIN_CAPITAL_LETTER_C_WITH_CEDILLA */ +- GDK_KEY_Multi_key, GDK_KEY_c, GDK_KEY_apostrophe, 0, 0, 0x00E7, /* LATIN_SMALL_LETTER_C_WITH_CEDILLA */ +-#endif +-}; +- + static void + ibus_im_context_init (GObject *obj) + { +@@ -936,10 +909,6 @@ ibus_im_context_init (GObject *obj) + + // Create slave im context + ibusimcontext->slave = gtk_im_context_simple_new (); +- gtk_im_context_simple_add_table (GTK_IM_CONTEXT_SIMPLE (ibusimcontext->slave), +- cedilla_compose_seqs, +- 4, +- G_N_ELEMENTS (cedilla_compose_seqs) / (4 + 2)); + + g_signal_connect (ibusimcontext->slave, + "commit", +-- +2.37.3 + +From b94f0c1cea5d0e423fef3bcc13b23f212f04c930 Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Thu, 7 Jul 2022 08:13:57 +0900 +Subject: [PATCH] src: Add IBUS_CAP_OSK to IBusCapabilite + +Some IMEs' behavior is different between the on-screen keyboard and +the direct physical keyboard and this flag is useful for the IMEs. + +Also fix src/ibusaccelgroup.c for gtkdoc-mkhtml. +If the API comment of IBusCapabilite is updated, XML & HTML files +are rebuilt and gtk-doc-1.33.2 no longer accepts HTML tags in +the comments. + +diff --git a/src/ibusaccelgroup.c b/src/ibusaccelgroup.c +index ef2d3976..aec1c7e4 100644 +--- a/src/ibusaccelgroup.c ++++ b/src/ibusaccelgroup.c +@@ -267,14 +267,14 @@ is_keycode (const gchar *string) + * modifier mask, %NULL + * + * Parses a string representing an accelerator. The format looks like +- * “a” or “F1” or “z” (the last one is +- * for key release). ++ * “<Control>a” or “<Shift><Alt>F1” or “<Release%gt;z” ++ * (the last one is for key release). + * + * The parser is fairly liberal and allows lower or upper case, and also +- * abbreviations such as “” and “”. Key names are parsed using +- * gdk_keyval_from_name(). For character keys the name is not the symbol, +- * but the lowercase name, e.g. one would use “minus” instead of +- * “-”. ++ * abbreviations such as “<Ctl>” and “<Ctrl>”. Key names are ++ * parsed using gdk_keyval_from_name(). For character keys the name is not the ++ * symbol, but the lowercase name, e.g. one would use “<Ctrl>minus” ++ * instead of “<Ctrl>-”. + * + * If the parse fails, @accelerator_key and @accelerator_mods will + * be set to 0 (zero). +@@ -403,7 +403,7 @@ out: + * + * Converts an accelerator keyval and modifier mask into a string + * parseable by gtk_accelerator_parse(). For example, if you pass in +- * #IBUS_KEY_q and #IBUS_CONTROL_MASK, this function returns “q”. ++ * #IBUS_KEY_q and #IBUS_CONTROL_MASK, this function returns “<Control>q”. + * + * If you need to display accelerators in the user interface, + * see gtk_accelerator_get_label(). +diff --git a/src/ibustypes.h b/src/ibustypes.h +index 990659ac..60bcb92b 100644 +--- a/src/ibustypes.h ++++ b/src/ibustypes.h +@@ -108,6 +108,7 @@ typedef enum + * @IBUS_CAP_PROPERTY: UI is capable to have property. + * @IBUS_CAP_SURROUNDING_TEXT: Client can provide surround text, + * or IME can handle surround text. ++ * @IBUS_CAP_OSK: UI is owned by on-screen keyboard. + * + * Capability flags of UI. + */ +@@ -118,6 +119,7 @@ typedef enum { + IBUS_CAP_FOCUS = 1 << 3, + IBUS_CAP_PROPERTY = 1 << 4, + IBUS_CAP_SURROUNDING_TEXT = 1 << 5, ++ IBUS_CAP_OSK = 1 << 6, + } IBusCapabilite; + + /** +-- +2.37.3 + +From c957c5f6ba07074a8fb56c978c27873c1cfe0783 Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Tue, 19 Jul 2022 22:58:24 +0900 +Subject: [PATCH] client/gtk2: Implement new process_key_event for GTK4 + + +diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c +index c7f23293..bc14df00 100644 +--- a/client/gtk2/ibusimcontext.c ++++ b/client/gtk2/ibusimcontext.c +@@ -111,13 +111,13 @@ static guint _signal_delete_surrounding_id = 0; + static guint _signal_retrieve_surrounding_id = 0; + + #if GTK_CHECK_VERSION (3, 98, 4) +-static gboolean _use_sync_mode = TRUE; ++static char _use_sync_mode = 2; + #else + static const gchar *_no_snooper_apps = NO_SNOOPER_APPS; + static gboolean _use_key_snooper = ENABLE_SNOOPER; + static guint _key_snooper_id = 0; + +-static gboolean _use_sync_mode = FALSE; ++static char _use_sync_mode = 0; + #endif + + static const gchar *_discard_password_apps = ""; +@@ -375,12 +375,15 @@ ibus_im_context_commit_event (IBusIMContext *ibusimcontext, + return FALSE; + } + +-struct _ProcessKeyEventData { ++typedef struct { + GdkEvent *event; + IBusIMContext *ibusimcontext; +-}; ++} ProcessKeyEventData; + +-typedef struct _ProcessKeyEventData ProcessKeyEventData; ++typedef struct { ++ GMainLoop *loop; ++ gboolean retval; ++} ProcessKeyEventReplyData; + + static void + _process_key_event_done (GObject *object, +@@ -395,12 +398,12 @@ _process_key_event_done (GObject *object, + IBusIMContext *ibusimcontext = data->ibusimcontext; + #endif + GError *error = NULL; ++ gboolean retval; + + g_slice_free (ProcessKeyEventData, data); +- gboolean retval = ibus_input_context_process_key_event_async_finish ( +- context, +- res, +- &error); ++ retval = ibus_input_context_process_key_event_async_finish (context, ++ res, ++ &error); + + if (error != NULL) { + g_warning ("Process Key Event failed: %s.", error->message); +@@ -431,6 +434,27 @@ _process_key_event_done (GObject *object, + #endif + } + ++static void ++_process_key_event_reply_done (GObject *object, ++ GAsyncResult *res, ++ gpointer user_data) ++{ ++ IBusInputContext *context = (IBusInputContext *)object; ++ ProcessKeyEventReplyData *data = (ProcessKeyEventReplyData *)user_data; ++ GError *error = NULL; ++ gboolean retval = ibus_input_context_process_key_event_async_finish ( ++ context, ++ res, ++ &error); ++ if (error != NULL) { ++ g_warning ("Process Key Event failed: %s.", error->message); ++ g_error_free (error); ++ } ++ g_return_if_fail (data); ++ data->retval = retval; ++ g_main_loop_quit (data->loop); ++} ++ + static gboolean + _process_key_event (IBusInputContext *context, + #if GTK_CHECK_VERSION (3, 98, 4) +@@ -462,13 +486,45 @@ _process_key_event (IBusInputContext *context, + #endif + keycode = hardware_keycode; + +- if (_use_sync_mode) { ++ switch (_use_sync_mode) { ++ case 1: { + retval = ibus_input_context_process_key_event (context, ++ keyval, ++ keycode - 8, ++ state); ++ break; ++ } ++ case 2: { ++ GMainLoop *loop = g_main_loop_new (NULL, TRUE); ++ ProcessKeyEventReplyData *data = NULL; ++ ++ if (loop) ++ data = g_slice_new0 (ProcessKeyEventReplyData); ++ if (!data) { ++ g_warning ("Cannot wait for the reply of the process key event."); ++ retval = ibus_input_context_process_key_event (context, ++ keyval, ++ keycode - 8, ++ state); ++ if (loop) ++ g_main_loop_quit (loop); ++ break; ++ } ++ data->loop = loop; ++ ibus_input_context_process_key_event_async (context, + keyval, + keycode - 8, +- state); ++ state, ++ -1, ++ NULL, ++ _process_key_event_reply_done, ++ data); ++ g_main_loop_run (loop); ++ retval = data->retval; ++ g_slice_free (ProcessKeyEventReplyData, data); ++ break; + } +- else { ++ default: { + ProcessKeyEventData *data = g_slice_new0 (ProcessKeyEventData); + #if GTK_CHECK_VERSION (3, 98, 4) + data->event = gdk_event_ref (event); +@@ -487,6 +543,7 @@ _process_key_event (IBusInputContext *context, + + retval = TRUE; + } ++ } + + /* GTK4 does not provide gtk_key_snooper_install() and also + * GtkIMContextClass->filter_keypress() cannot send the updated +@@ -676,24 +733,47 @@ _key_snooper_cb (GtkWidget *widget, + #endif + + static gboolean +-_get_boolean_env(const gchar *name, +- gboolean defval) ++_get_boolean_env (const gchar *name, ++ gboolean defval) + { + const gchar *value = g_getenv (name); + + if (value == NULL) +- return defval; ++ return defval; + + if (g_strcmp0 (value, "") == 0 || + g_strcmp0 (value, "0") == 0 || + g_strcmp0 (value, "false") == 0 || + g_strcmp0 (value, "False") == 0 || +- g_strcmp0 (value, "FALSE") == 0) +- return FALSE; ++ g_strcmp0 (value, "FALSE") == 0) { ++ return FALSE; ++ } + + return TRUE; + } + ++static char ++_get_char_env (const gchar *name, ++ char defval) ++{ ++ const gchar *value = g_getenv (name); ++ ++ if (value == NULL) ++ return defval; ++ ++ if (g_strcmp0 (value, "") == 0 || ++ g_strcmp0 (value, "0") == 0 || ++ g_strcmp0 (value, "false") == 0 || ++ g_strcmp0 (value, "False") == 0 || ++ g_strcmp0 (value, "FALSE") == 0) { ++ return 0; ++ } else if (!g_strcmp0 (value, "2")) { ++ return 2; ++ } ++ ++ return 1; ++} ++ + static void + daemon_name_appeared (GDBusConnection *connection, + const gchar *name, +@@ -777,11 +857,11 @@ ibus_im_context_class_init (IBusIMContextClass *class) + g_assert (_signal_retrieve_surrounding_id != 0); + + #if GTK_CHECK_VERSION (3, 98, 4) +- _use_sync_mode = _get_boolean_env ("IBUS_ENABLE_SYNC_MODE", TRUE); ++ _use_sync_mode = _get_char_env ("IBUS_ENABLE_SYNC_MODE", 2); + #else + _use_key_snooper = !_get_boolean_env ("IBUS_DISABLE_SNOOPER", + !(ENABLE_SNOOPER)); +- _use_sync_mode = _get_boolean_env ("IBUS_ENABLE_SYNC_MODE", FALSE); ++ _use_sync_mode = (char)_get_char_env ("IBUS_ENABLE_SYNC_MODE", 0); + #endif + _use_discard_password = _get_boolean_env ("IBUS_DISCARD_PASSWORD", FALSE); + +@@ -904,6 +984,8 @@ ibus_im_context_init (GObject *obj) + #else + ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS; + #endif ++ if (_use_sync_mode != 1) ++ ibusimcontext->caps |= IBUS_CAP_SYNC_PROCESS_KEY; + + ibusimcontext->events_queue = g_queue_new (); + +@@ -1246,7 +1328,7 @@ ibus_im_context_reset (GtkIMContext *context) + * IBus uses button-press-event instead until GTK is fixed. + * https://gitlab.gnome.org/GNOME/gtk/issues/1534 + */ +- if (_use_sync_mode) ++ if (_use_sync_mode == 1) + ibus_im_context_clear_preedit_text (ibusimcontext); + ibus_input_context_reset (ibusimcontext->ibuscontext); + } +@@ -1361,7 +1443,7 @@ ibus_im_context_set_client_window (GtkIMContext *context, + + if (ibusimcontext->client_window) { + #if !GTK_CHECK_VERSION (3, 98, 4) +- if (ibusimcontext->use_button_press_event && !_use_sync_mode) ++ if (ibusimcontext->use_button_press_event && _use_sync_mode != 1) + _connect_button_press_event (ibusimcontext, FALSE); + #endif + g_object_unref (ibusimcontext->client_window); +@@ -1371,7 +1453,7 @@ ibus_im_context_set_client_window (GtkIMContext *context, + if (client != NULL) { + ibusimcontext->client_window = g_object_ref (client); + #if !GTK_CHECK_VERSION (3, 98, 4) +- if (!ibusimcontext->use_button_press_event && !_use_sync_mode) ++ if (!ibusimcontext->use_button_press_event && _use_sync_mode != 1) + _connect_button_press_event (ibusimcontext, TRUE); + #endif + } +@@ -1993,7 +2075,7 @@ _ibus_context_update_preedit_text_cb (IBusInputContext *ibuscontext, + #if !GTK_CHECK_VERSION (3, 98, 4) + if (!ibusimcontext->use_button_press_event && + mode == IBUS_ENGINE_PREEDIT_COMMIT && +- !_use_sync_mode) { ++ _use_sync_mode != 1) { + if (ibusimcontext->client_window) { + _connect_button_press_event (ibusimcontext, TRUE); + } +@@ -2200,6 +2282,8 @@ _create_input_context_done (IBusBus *bus, + static void + _create_input_context (IBusIMContext *ibusimcontext) + { ++ gchar *prgname = g_strdup (g_get_prgname()); ++ gchar *client_name; + IDEBUG ("%s", __FUNCTION__); + + g_assert (ibusimcontext->ibuscontext == NULL); +@@ -2208,11 +2292,24 @@ _create_input_context (IBusIMContext *ibusimcontext) + + ibusimcontext->cancellable = g_cancellable_new (); + ++ if (!prgname) ++ prgname = g_strdup_printf ("(%d)", getpid ()); ++ client_name = g_strdup_printf ("%s:%s", ++#if GTK_CHECK_VERSION (3, 98, 4) ++ "gtk4-im", ++#elif GTK_CHECK_VERSION (2, 91, 0) ++ "gtk3-im", ++#else ++ "gtk-im", ++#endif ++ prgname); ++ g_free (prgname); + ibus_bus_create_input_context_async (_bus, +- "gtk-im", -1, ++ client_name, -1, + ibusimcontext->cancellable, + (GAsyncReadyCallback)_create_input_context_done, + g_object_ref (ibusimcontext)); ++ g_free (client_name); + } + + /* Callback functions for slave context */ +@@ -2329,6 +2426,8 @@ _create_fake_input_context_done (IBusBus *bus, + NULL); + + guint32 caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT; ++ if (_use_sync_mode != 1) ++ caps |= IBUS_CAP_SYNC_PROCESS_KEY; + ibus_input_context_set_capabilities (_fake_context, caps); + + /* focus in/out the fake context */ +diff --git a/src/ibustypes.h b/src/ibustypes.h +index 60bcb92b..a8eee319 100644 +--- a/src/ibustypes.h ++++ b/src/ibustypes.h +@@ -109,6 +109,9 @@ typedef enum + * @IBUS_CAP_SURROUNDING_TEXT: Client can provide surround text, + * or IME can handle surround text. + * @IBUS_CAP_OSK: UI is owned by on-screen keyboard. ++ * @IBUS_CAP_SYNC_PROCESS_KEY: Asynchronous process key events are not ++ * supported and the ibus_engine_forward_key_event() should not be ++ * used for the return value of #IBusEngine::process_key_event(). + * + * Capability flags of UI. + */ +@@ -120,6 +123,7 @@ typedef enum { + IBUS_CAP_PROPERTY = 1 << 4, + IBUS_CAP_SURROUNDING_TEXT = 1 << 5, + IBUS_CAP_OSK = 1 << 6, ++ IBUS_CAP_SYNC_PROCESS_KEY = 1 << 7, + } IBusCapabilite; + + /** +-- +2.41.0 + +From 506ac9993d5166196b7c4e9bfa9fb0f9d3792ffa Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Thu, 10 Nov 2022 18:38:05 +0900 +Subject: [PATCH] client/x11: Implement new process_key_event for ibus-x11 + +The new process_key_event is ported from GTK4 to X11 because +hangul maintainers wish to delete forward_key_event as much as possible +and currently we could apply forward_key_event to the sync mode only +and the new process_key_event is a new async key event process in X11 +and hangul might disable forward_key_event by default. + +Now the definition of IBUS_CAP_SYNC_PROCESS_KEY_V2 capability is changed +to set only if the sync mode. + +Also switch a heavy GMainLoop to the light GSource. + +Fixes: https://github.com/ibus/ibus/commit/c957c5f +--- + client/gtk2/ibusimcontext.c | 61 ++++++++++---- + client/x11/main.c | 157 +++++++++++++++++++++++++++++++----- + src/ibustypes.h | 1 + + 3 files changed, 184 insertions(+), 35 deletions(-) + +diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c +index 6e338157..1f3723e6 100644 +--- a/client/gtk2/ibusimcontext.c ++++ b/client/gtk2/ibusimcontext.c +@@ -382,8 +382,9 @@ typedef struct { + } ProcessKeyEventData; + + typedef struct { +- GMainLoop *loop; +- gboolean retval; ++ int count; ++ guint count_cb_id; ++ gboolean retval; + } ProcessKeyEventReplyData; + + static void +@@ -453,7 +454,23 @@ _process_key_event_reply_done (GObject *object, + } + g_return_if_fail (data); + data->retval = retval; +- g_main_loop_quit (data->loop); ++ data->count = 0; ++ g_source_remove (data->count_cb_id); ++} ++ ++static gboolean ++_process_key_event_count_cb (gpointer user_data) ++{ ++ ProcessKeyEventReplyData *data = (ProcessKeyEventReplyData *)user_data; ++ g_return_val_if_fail (data, G_SOURCE_REMOVE); ++ if (!data->count) ++ return G_SOURCE_REMOVE; ++ /* Wait for about 10 secs. */ ++ if (data->count++ == 10000) { ++ data->count = 0; ++ return G_SOURCE_REMOVE; ++ } ++ return G_SOURCE_CONTINUE; + } + + static gboolean +@@ -496,10 +513,10 @@ _process_key_event (IBusInputContext *context, + break; + } + case 2: { +- GMainLoop *loop = g_main_loop_new (NULL, TRUE); ++ GSource *source = g_timeout_source_new (1); + ProcessKeyEventReplyData *data = NULL; + +- if (loop) ++ if (source) + data = g_slice_new0 (ProcessKeyEventReplyData); + if (!data) { + g_warning ("Cannot wait for the reply of the process key event."); +@@ -507,11 +524,14 @@ _process_key_event (IBusInputContext *context, + keyval, + keycode - 8, + state); +- if (loop) +- g_main_loop_quit (loop); ++ if (source) ++ g_source_destroy (source); + break; + } +- data->loop = loop; ++ data->count = 1; ++ g_source_attach (source, NULL); ++ g_source_unref (source); ++ data->count_cb_id = g_source_get_id (source); + ibus_input_context_process_key_event_async (context, + keyval, + keycode - 8, +@@ -520,7 +540,14 @@ _process_key_event (IBusInputContext *context, + NULL, + _process_key_event_reply_done, + data); +- g_main_loop_run (loop); ++ g_source_set_callback (source, _process_key_event_count_cb, data, NULL); ++ while (data->count) ++ g_main_context_iteration (NULL, TRUE); ++ if (source->ref_count > 0) { ++ /* g_source_get_id() could causes a SEGV */ ++ g_info ("Broken GSource.ref_count and maybe a timing issue in %p.", ++ source); ++ } + retval = data->retval; + g_slice_free (ProcessKeyEventReplyData, data); + break; +@@ -994,8 +1021,8 @@ ibus_im_context_init (GObject *obj) + #else + ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS; + #endif +- if (_use_sync_mode != 1) +- ibusimcontext->caps |= IBUS_CAP_SYNC_PROCESS_KEY; ++ if (_use_sync_mode == 1) ++ ibusimcontext->caps |= IBUS_CAP_SYNC_PROCESS_KEY_V2; + + ibusimcontext->events_queue = g_queue_new (); + +@@ -1338,7 +1365,7 @@ ibus_im_context_reset (GtkIMContext *context) + * IBus uses button-press-event instead until GTK is fixed. + * https://gitlab.gnome.org/GNOME/gtk/issues/1534 + */ +- if (_use_sync_mode == 1) ++ if (_use_sync_mode != 0) + ibus_im_context_clear_preedit_text (ibusimcontext); + ibus_input_context_reset (ibusimcontext->ibuscontext); + } +@@ -1453,7 +1480,7 @@ ibus_im_context_set_client_window (GtkIMContext *context, + + if (ibusimcontext->client_window) { + #if !GTK_CHECK_VERSION (3, 98, 4) +- if (ibusimcontext->use_button_press_event && _use_sync_mode != 1) ++ if (ibusimcontext->use_button_press_event && _use_sync_mode == 0) + _connect_button_press_event (ibusimcontext, FALSE); + #endif + g_object_unref (ibusimcontext->client_window); +@@ -1463,7 +1490,7 @@ ibus_im_context_set_client_window (GtkIMContext *context, + if (client != NULL) { + ibusimcontext->client_window = g_object_ref (client); + #if !GTK_CHECK_VERSION (3, 98, 4) +- if (!ibusimcontext->use_button_press_event && _use_sync_mode != 1) ++ if (!ibusimcontext->use_button_press_event && _use_sync_mode == 0) + _connect_button_press_event (ibusimcontext, TRUE); + #endif + } +@@ -2085,7 +2112,7 @@ _ibus_context_update_preedit_text_cb (IBusInputContext *ibuscontext, + #if !GTK_CHECK_VERSION (3, 98, 4) + if (!ibusimcontext->use_button_press_event && + mode == IBUS_ENGINE_PREEDIT_COMMIT && +- _use_sync_mode != 1) { ++ _use_sync_mode == 0) { + if (ibusimcontext->client_window) { + _connect_button_press_event (ibusimcontext, TRUE); + } +@@ -2459,8 +2486,8 @@ _create_fake_input_context_done (IBusBus *bus, + NULL); + + guint32 caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT; +- if (_use_sync_mode != 1) +- caps |= IBUS_CAP_SYNC_PROCESS_KEY; ++ if (_use_sync_mode == 1) ++ caps |= IBUS_CAP_SYNC_PROCESS_KEY_V2; + ibus_input_context_set_capabilities (_fake_context, caps); + + /* focus in/out the fake context */ +diff --git a/client/x11/main.c b/client/x11/main.c +index 6057cc03..905fd251 100644 +--- a/client/x11/main.c ++++ b/client/x11/main.c +@@ -124,7 +124,7 @@ static gint g_debug_level = 0; + + static IBusBus *_bus = NULL; + +-static gboolean _use_sync_mode = TRUE; ++static char _use_sync_mode = 2; + + static void + _xim_preedit_start (XIMS xims, const X11IC *x11ic) +@@ -331,6 +331,7 @@ xim_create_ic (XIMS xims, IMChangeICStruct *call_data) + { + static int base_icid = 1; + X11IC *x11ic; ++ guint32 capabilities = IBUS_CAP_FOCUS; + + call_data->icid = base_icid ++; + +@@ -375,12 +376,11 @@ xim_create_ic (XIMS xims, IMChangeICStruct *call_data) + G_CALLBACK (_context_disabled_cb), x11ic); + + +- if (x11ic->input_style & XIMPreeditCallbacks) { +- ibus_input_context_set_capabilities (x11ic->context, IBUS_CAP_FOCUS | IBUS_CAP_PREEDIT_TEXT); +- } +- else { +- ibus_input_context_set_capabilities (x11ic->context, IBUS_CAP_FOCUS); +- } ++ if (x11ic->input_style & XIMPreeditCallbacks) ++ capabilities |= IBUS_CAP_PREEDIT_TEXT; ++ if (_use_sync_mode == 1) ++ capabilities |= IBUS_CAP_SYNC_PROCESS_KEY_V2; ++ ibus_input_context_set_capabilities (x11ic->context, capabilities); + + g_hash_table_insert (_x11_ic_table, + GINT_TO_POINTER (x11ic->icid), (gpointer)x11ic); +@@ -461,6 +461,13 @@ xim_unset_ic_focus (XIMS xims, IMChangeFocusStruct *call_data) + + } + ++typedef struct { ++ IMForwardEventStruct *pfe; ++ int count; ++ guint count_cb_id; ++ gboolean retval; ++} ProcessKeyEventReplyData; ++ + static void + _process_key_event_done (GObject *object, + GAsyncResult *res, +@@ -493,6 +500,43 @@ _process_key_event_done (GObject *object, + g_slice_free (IMForwardEventStruct, pfe); + } + ++static void ++_process_key_event_reply_done (GObject *object, ++ GAsyncResult *res, ++ gpointer user_data) ++{ ++ IBusInputContext *context = (IBusInputContext *)object; ++ ProcessKeyEventReplyData *data = (ProcessKeyEventReplyData *)user_data; ++ GError *error = NULL; ++ gboolean retval = ibus_input_context_process_key_event_async_finish ( ++ context, ++ res, ++ &error); ++ if (error != NULL) { ++ g_warning ("Process Key Event failed: %s.", error->message); ++ g_error_free (error); ++ } ++ g_return_if_fail (data); ++ data->retval = retval; ++ data->count = 0; ++ g_source_remove (data->count_cb_id); ++} ++ ++static gboolean ++_process_key_event_count_cb (gpointer user_data) ++{ ++ ProcessKeyEventReplyData *data = (ProcessKeyEventReplyData *)user_data; ++ g_return_val_if_fail (data, G_SOURCE_REMOVE); ++ if (!data->count) ++ return G_SOURCE_REMOVE; ++ /* Wait for about 10 secs. */ ++ if (data->count++ == 10000) { ++ data->count = 0; ++ return G_SOURCE_REMOVE; ++ } ++ return G_SOURCE_CONTINUE; ++} ++ + static int + xim_forward_event (XIMS xims, IMForwardEventStruct *call_data) + { +@@ -520,14 +564,15 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data) + event.state |= IBUS_RELEASE_MASK; + } + +- if (_use_sync_mode) { ++ switch (_use_sync_mode) { ++ case 1: { + retval = ibus_input_context_process_key_event ( + x11ic->context, + event.keyval, + event.hardware_keycode - 8, + event.state); + if (retval) { +- if (! x11ic->has_preedit_area) { ++ if (!x11ic->has_preedit_area) { + _xim_set_cursor_location (x11ic); + } + return 1; +@@ -546,8 +591,80 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data) + IMForwardEvent (_xims, (XPointer) &fe); + + retval = 1; ++ break; + } +- else { ++ case 2: { ++ GSource *source = g_timeout_source_new (1); ++ ProcessKeyEventReplyData *data = NULL; ++ IMForwardEventStruct fe; ++ ++ if (source) ++ data = g_slice_new0 (ProcessKeyEventReplyData); ++ if (!data) { ++ g_warning ("Cannot wait for the reply of the process key event."); ++ retval = ibus_input_context_process_key_event ( ++ x11ic->context, ++ event.keyval, ++ event.hardware_keycode - 8, ++ event.state); ++ if (source) ++ g_source_destroy (source); ++ } else { ++ CARD16 connect_id = x11ic->connect_id; ++ data->count = 1; ++ g_source_attach (source, NULL); ++ g_source_unref (source); ++ data->count_cb_id = g_source_get_id (source); ++ ibus_input_context_process_key_event_async ( ++ x11ic->context, ++ event.keyval, ++ event.hardware_keycode - 8, ++ event.state, ++ -1, ++ NULL, ++ _process_key_event_reply_done, ++ data); ++ g_source_set_callback (source, _process_key_event_count_cb, ++ data, NULL); ++ while (data->count) ++ g_main_context_iteration (NULL, TRUE); ++ if (source->ref_count > 0) { ++ /* g_source_get_id() could causes a SEGV */ ++ g_info ("Broken GSource.ref_count and maybe a timing " ++ "issue in %p.", source); ++ } ++ retval = data->retval; ++ g_slice_free (ProcessKeyEventReplyData, data); ++ ++ if (g_hash_table_lookup (_connections, ++ GINT_TO_POINTER ((gint)connect_id)) ++ == NULL) { ++ return 1; ++ } ++ } ++ ++ if (retval) { ++ if (! x11ic->has_preedit_area) { ++ _xim_set_cursor_location (x11ic); ++ } ++ return 1; ++ } ++ ++ memset (&fe, 0, sizeof (fe)); ++ ++ fe.major_code = XIM_FORWARD_EVENT; ++ fe.icid = x11ic->icid; ++ fe.connect_id = x11ic->connect_id; ++ fe.sync_bit = 0; ++ fe.serial_number = 0L; ++ fe.event = call_data->event; ++ ++ IMForwardEvent (_xims, (XPointer) &fe); ++ ++ retval = 1; ++ break; ++ } ++ default: { + IMForwardEventStruct *pfe; + + pfe = g_slice_new0 (IMForwardEventStruct); +@@ -569,6 +686,7 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data) + pfe); + retval = 1; + } ++ } + return retval; + } + +@@ -1026,23 +1144,26 @@ _context_disabled_cb (IBusInputContext *context, + _xim_preedit_end (_xims, x11ic); + } + +-static gboolean +-_get_boolean_env(const gchar *name, +- gboolean defval) ++static char ++_get_char_env (const gchar *name, ++ char defval) + { + const gchar *value = g_getenv (name); + + if (value == NULL) +- return defval; ++ return defval; + + if (g_strcmp0 (value, "") == 0 || + g_strcmp0 (value, "0") == 0 || + g_strcmp0 (value, "false") == 0 || + g_strcmp0 (value, "False") == 0 || +- g_strcmp0 (value, "FALSE") == 0) +- return FALSE; ++ g_strcmp0 (value, "FALSE") == 0) { ++ return 0; ++ } else if (!g_strcmp0 (value, "2")) { ++ return 2; ++ } + +- return TRUE; ++ return 1; + } + + static void +@@ -1059,7 +1180,7 @@ _init_ibus (void) + G_CALLBACK (_bus_disconnected_cb), NULL); + + /* https://github.com/ibus/ibus/issues/1713 */ +- _use_sync_mode = _get_boolean_env ("IBUS_ENABLE_SYNC_MODE", TRUE); ++ _use_sync_mode = _get_char_env ("IBUS_ENABLE_SYNC_MODE", 2); + } + + static void +diff --git a/src/ibustypes.h b/src/ibustypes.h +index a8eee319..ba2a0010 100644 +--- a/src/ibustypes.h ++++ b/src/ibustypes.h +@@ -124,6 +124,7 @@ typedef enum { + IBUS_CAP_SURROUNDING_TEXT = 1 << 5, + IBUS_CAP_OSK = 1 << 6, + IBUS_CAP_SYNC_PROCESS_KEY = 1 << 7, ++ IBUS_CAP_SYNC_PROCESS_KEY_V2 = IBUS_CAP_SYNC_PROCESS_KEY, + } IBusCapabilite; + + /** +-- +2.41.0 + +From 497f0c74230a65309e22ce5569060ce48310406b Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Thu, 23 Mar 2023 13:07:30 +0900 +Subject: [PATCH] client/x11: Fix Key typing order + +ibus-x11 now also uses the hybrid process key events with +IBUS_ENABLE_SYNC_MODE=2 and it waits for the async API +with GSource and g_main_context_iteration() in xim_forward_event(). + +But g_main_context_iteration() calls gdk_event_source_dispatch() +and it can call another xim_forward_event() and the callbacks +of ibus_input_context_process_key_event_async() can be nested. +So if the forwarding API is called out of the callbacks of +ibus_input_context_process_key_event_async(), the key events +order is swapped due to the delayed return of +g_main_context_iteration(). + +To resolve this issue, the forwarding API should be called in +the callbacks of ibus_input_context_process_key_event_async(). + +Fixes: https://github.com/ibus/ibus/commit/506ac99 + +BUG=https://github.com/ibus/ibus/issues/2480 +--- + client/x11/main.c | 160 ++++++++++++++++++++++++---------------------- + 1 file changed, 83 insertions(+), 77 deletions(-) + +diff --git a/client/x11/main.c b/client/x11/main.c +index 905fd251..83d95cb7 100644 +--- a/client/x11/main.c ++++ b/client/x11/main.c +@@ -2,7 +2,7 @@ + /* vim:set et sts=4: */ + /* ibus + * Copyright (C) 2007-2015 Peng Huang +- * Copyright (C) 2015-2021 Takao Fujiwara ++ * Copyright (C) 2015-2023 Takao Fujiwara + * Copyright (C) 2007-2015 Red Hat, Inc. + * + * main.c: +@@ -48,6 +48,9 @@ + + #include + ++/* Wait for about 120 secs to return a key from async process-key-event. */ ++#define MAX_WAIT_KEY_TIME 120000 ++ + #define LOG(level, fmt_args...) \ + if (g_debug_level >= (level)) { \ + g_debug (fmt_args); \ +@@ -461,11 +463,39 @@ xim_unset_ic_focus (XIMS xims, IMChangeFocusStruct *call_data) + + } + ++static void ++_xim_forward_key_event_done (X11IC *x11ic, ++ XEvent *event, ++ gboolean processed) ++{ ++ IMForwardEventStruct fe; ++ if (processed) { ++ if (!x11ic->has_preedit_area) { ++ _xim_set_cursor_location (x11ic); ++ } ++ return; ++ } ++ g_assert (x11ic); ++ g_assert (event); ++ ++ memset (&fe, 0, sizeof (fe)); ++ fe.major_code = XIM_FORWARD_EVENT; ++ fe.icid = x11ic->icid; ++ fe.connect_id = x11ic->connect_id; ++ fe.sync_bit = 0; ++ fe.serial_number = 0L; ++ fe.event = *event; ++ IMForwardEvent (_xims, (XPointer) &fe); ++} ++ ++ + typedef struct { +- IMForwardEventStruct *pfe; + int count; + guint count_cb_id; + gboolean retval; ++ X11IC *x11ic; ++ CARD16 connect_id; ++ XEvent event; + } ProcessKeyEventReplyData; + + static void +@@ -474,7 +504,7 @@ _process_key_event_done (GObject *object, + gpointer user_data) + { + IBusInputContext *context = (IBusInputContext *)object; +- IMForwardEventStruct *pfe = (IMForwardEventStruct*) user_data; ++ ProcessKeyEventReplyData *data = (ProcessKeyEventReplyData *)user_data; + + GError *error = NULL; + gboolean retval = ibus_input_context_process_key_event_async_finish ( +@@ -488,16 +518,15 @@ _process_key_event_done (GObject *object, + } + + if (g_hash_table_lookup (_connections, +- GINT_TO_POINTER ((gint) pfe->connect_id)) ++ GINT_TO_POINTER ((gint)data->connect_id)) + == NULL) { +- g_slice_free (IMForwardEventStruct, pfe); ++ g_slice_free (ProcessKeyEventReplyData, data); + return; + } + +- if (retval == FALSE) { +- IMForwardEvent (_xims, (XPointer) pfe); +- } +- g_slice_free (IMForwardEventStruct, pfe); ++ if (retval == FALSE) ++ _xim_forward_key_event_done (data->x11ic, &data->event, retval); ++ g_slice_free (ProcessKeyEventReplyData, data); + } + + static void +@@ -518,6 +547,21 @@ _process_key_event_reply_done (GObject *object, + } + g_return_if_fail (data); + data->retval = retval; ++ if (g_hash_table_lookup (_connections, ++ GINT_TO_POINTER ((gint)data->connect_id)) ++ == NULL) { ++ return; ++ } ++ /* _xim_forward_key_event_done() should be called in ++ * _process_key_event_reply_done() because g_main_context_iteration() ++ * can call another xim_forward_event() and xim_forward_event() can be ++ * nested and the first _process_key_event_reply_done() is returned ++ * at last with g_main_context_iteration() so ++ * if _xim_forward_key_event_done() is called out of ++ * _process_key_event_reply_done(), the key events order ++ * can be swapped. ++ */ ++ _xim_forward_key_event_done (data->x11ic, &data->event, retval); + data->count = 0; + g_source_remove (data->count_cb_id); + } +@@ -529,9 +573,8 @@ _process_key_event_count_cb (gpointer user_data) + g_return_val_if_fail (data, G_SOURCE_REMOVE); + if (!data->count) + return G_SOURCE_REMOVE; +- /* Wait for about 10 secs. */ +- if (data->count++ == 10000) { +- data->count = 0; ++ if (data->count++ == MAX_WAIT_KEY_TIME) { ++ g_warning ("Key event is not returned for %usecs.", MAX_WAIT_KEY_TIME); + return G_SOURCE_REMOVE; + } + return G_SOURCE_CONTINUE; +@@ -571,32 +614,13 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data) + event.keyval, + event.hardware_keycode - 8, + event.state); +- if (retval) { +- if (!x11ic->has_preedit_area) { +- _xim_set_cursor_location (x11ic); +- } +- return 1; +- } +- +- IMForwardEventStruct fe; +- memset (&fe, 0, sizeof (fe)); +- +- fe.major_code = XIM_FORWARD_EVENT; +- fe.icid = x11ic->icid; +- fe.connect_id = x11ic->connect_id; +- fe.sync_bit = 0; +- fe.serial_number = 0L; +- fe.event = call_data->event; +- +- IMForwardEvent (_xims, (XPointer) &fe); +- ++ _xim_forward_key_event_done (x11ic, &call_data->event, retval); + retval = 1; + break; + } + case 2: { + GSource *source = g_timeout_source_new (1); + ProcessKeyEventReplyData *data = NULL; +- IMForwardEventStruct fe; + + if (source) + data = g_slice_new0 (ProcessKeyEventReplyData); +@@ -610,11 +634,13 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data) + if (source) + g_source_destroy (source); + } else { +- CARD16 connect_id = x11ic->connect_id; + data->count = 1; + g_source_attach (source, NULL); + g_source_unref (source); + data->count_cb_id = g_source_get_id (source); ++ data->connect_id = call_data->connect_id; ++ data->x11ic = x11ic; ++ data->event = *((XEvent*)xevent); + ibus_input_context_process_key_event_async ( + x11ic->context, + event.keyval, +@@ -626,7 +652,7 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data) + data); + g_source_set_callback (source, _process_key_event_count_cb, + data, NULL); +- while (data->count) ++ while (data->count > 0 && data->count < MAX_WAIT_KEY_TIME) + g_main_context_iteration (NULL, TRUE); + if (source->ref_count > 0) { + /* g_source_get_id() could causes a SEGV */ +@@ -634,46 +660,33 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data) + "issue in %p.", source); + } + retval = data->retval; +- g_slice_free (ProcessKeyEventReplyData, data); +- +- if (g_hash_table_lookup (_connections, +- GINT_TO_POINTER ((gint)connect_id)) +- == NULL) { ++ if (data->count == 0) { ++ g_slice_free (ProcessKeyEventReplyData, data); + return 1; + } + } + +- if (retval) { +- if (! x11ic->has_preedit_area) { +- _xim_set_cursor_location (x11ic); +- } +- return 1; ++ g_slice_free (ProcessKeyEventReplyData, data); ++ if (g_hash_table_lookup (_connections, ++ GINT_TO_POINTER ((gint)call_data->connect_id)) ++ == NULL) { ++ return 1; + } +- +- memset (&fe, 0, sizeof (fe)); +- +- fe.major_code = XIM_FORWARD_EVENT; +- fe.icid = x11ic->icid; +- fe.connect_id = x11ic->connect_id; +- fe.sync_bit = 0; +- fe.serial_number = 0L; +- fe.event = call_data->event; +- +- IMForwardEvent (_xims, (XPointer) &fe); +- ++ _xim_forward_key_event_done (x11ic, &call_data->event, retval); + retval = 1; + break; + } + default: { +- IMForwardEventStruct *pfe; ++ ProcessKeyEventReplyData *data; + +- pfe = g_slice_new0 (IMForwardEventStruct); +- pfe->major_code = XIM_FORWARD_EVENT; +- pfe->icid = x11ic->icid; +- pfe->connect_id = x11ic->connect_id; +- pfe->sync_bit = 0; +- pfe->serial_number = 0L; +- pfe->event = call_data->event; ++ if (!(data = g_slice_new0 (ProcessKeyEventReplyData))) { ++ g_warning ("Cannot allocate async data"); ++ _xim_forward_key_event_done (x11ic, &call_data->event, 0); ++ return 1; ++ } ++ data->connect_id = call_data->connect_id; ++ data->x11ic = x11ic; ++ data->event = call_data->event; + + ibus_input_context_process_key_event_async ( + x11ic->context, +@@ -683,7 +696,7 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data) + -1, + NULL, + _process_key_event_done, +- pfe); ++ data); + retval = 1; + } + } +@@ -962,11 +975,10 @@ _xim_forward_key_event (X11IC *x11ic, + guint keycode, + guint state) + { +- g_return_if_fail (x11ic != NULL); +- +- IMForwardEventStruct fe = {0}; + XEvent xkp = {0}; + ++ g_return_if_fail (x11ic != NULL); ++ + xkp.xkey.type = (state & IBUS_RELEASE_MASK) ? KeyRelease : KeyPress; + xkp.xkey.serial = 0L; + xkp.xkey.send_event = False; +@@ -975,20 +987,14 @@ _xim_forward_key_event (X11IC *x11ic, + xkp.xkey.window = + x11ic->focus_window ? x11ic->focus_window : x11ic->client_window; + xkp.xkey.subwindow = None; +- xkp.xkey.root = DefaultRootWindow (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); ++ xkp.xkey.root = DefaultRootWindow ( ++ GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); + + xkp.xkey.time = 0; + xkp.xkey.state = state; + xkp.xkey.keycode = (keycode == 0) ? 0 : keycode + 8; + +- fe.major_code = XIM_FORWARD_EVENT; +- fe.icid = x11ic->icid; +- fe.connect_id = x11ic->connect_id; +- fe.sync_bit = 0; +- fe.serial_number = 0L; +- fe.event = xkp; +- +- IMForwardEvent (_xims, (XPointer) & fe); ++ _xim_forward_key_event_done (x11ic, &xkp, FALSE); + } + + static void +-- +2.41.0 + +From 8f706d160631f1ffdbfa16543a38b9d5f91c16ad Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Thu, 23 Mar 2023 13:07:38 +0900 +Subject: [PATCH] util/IMdkit: Disable while loop before call + ForwardEventMessageProc() + +Seems ProcessQueue() had a wrong XFree() with async process-key-event. +Fixes: https://github.com/ibus/ibus/commit/506ac99 + +BUG=https://github.com/ibus/ibus/issues/2484 +--- + util/IMdkit/i18nPtHdr.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/util/IMdkit/i18nPtHdr.c b/util/IMdkit/i18nPtHdr.c +index 8dc52714..ec20e322 100644 +--- a/util/IMdkit/i18nPtHdr.c ++++ b/util/IMdkit/i18nPtHdr.c +@@ -1747,11 +1747,13 @@ static void ProcessQueue (XIMS ims, CARD16 connect_id) + XimProtoHdr *hdr = (XimProtoHdr *) client->pending->p; + unsigned char *p1 = (unsigned char *) (hdr + 1); + IMProtocol call_data; ++ XIMPending *old = client->pending; + + call_data.major_code = hdr->major_opcode; + call_data.any.minor_code = hdr->minor_opcode; + call_data.any.connect_id = connect_id; + ++ client->pending = old->next; + switch (hdr->major_opcode) + { + case XIM_FORWARD_EVENT: +@@ -1760,12 +1762,7 @@ static void ProcessQueue (XIMS ims, CARD16 connect_id) + } + /*endswitch*/ + XFree (hdr); +- { +- XIMPending *old = client->pending; +- +- client->pending = old->next; +- XFree (old); +- } ++ XFree (old); + } + /*endwhile*/ + return; +-- +2.41.0 + +From 38f09c657fd5713e39f698aae43a09a07574f1a6 Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Wed, 12 Jul 2023 07:50:22 +0900 +Subject: [PATCH] src: Fix sync ibus_input_context_process_key_event() + +The synchronous "ProcessKeyEvent" D-Bus method cannot receive +"CommitText" and "ForwardKeyEvent" D-Bus signals during calling the method. +To resolve the issue, now +ibus_input_context_set_post_process_key_event() and +ibus_input_context_post_process_key_event() are added newly. + +ibus_input_context_post_process_key_event() retries "CommitText" and +"ForwardKeyEvent" D-Bus signals during calling the "ProcessKeyEvent" D-Bus +method and ibus-daemon does not handle those signals. + +"Since: 1.5.00" is added in header files to available APIs before 1.5.29 +is released. Will think later how to convert the version comments together +when the new version 1.5.29 is committed. + +BUG=https://github.com/ibus/ibus/issues/2486 +--- + bus/inputcontext.c | 252 ++++++++++++++++++++++++++++++++---- + client/gtk2/ibusimcontext.c | 225 ++++++++++++++++++++++---------- + src/ibusinputcontext.c | 162 +++++++++++++++++++++-- + src/ibusinputcontext.h | 36 +++++- + 4 files changed, 567 insertions(+), 108 deletions(-) + +diff --git a/bus/inputcontext.c b/bus/inputcontext.c +index 8aded5d8..4d1fb041 100644 +--- a/bus/inputcontext.c ++++ b/bus/inputcontext.c +@@ -31,6 +31,8 @@ + #include "marshalers.h" + #include "types.h" + ++#define MAX_SYNC_DATA 30 ++ + struct _SetEngineByDescData { + /* context related to the data */ + BusInputContext *context; +@@ -46,6 +48,11 @@ struct _SetEngineByDescData { + }; + typedef struct _SetEngineByDescData SetEngineByDescData; + ++typedef struct _SyncForwardingData { ++ gchar key; ++ IBusText *text; ++} SyncForwardingData; ++ + struct _BusInputContext { + IBusService parent; + +@@ -99,6 +106,9 @@ struct _BusInputContext { + + BusPanelProxy *emoji_extension; + gboolean is_extension_lookup_table; ++ GQueue *queue_during_process_key_event; ++ gboolean use_post_process_key_event; ++ gboolean processing_key_event; + }; + + struct _BusInputContextClass { +@@ -156,6 +166,15 @@ static void bus_input_context_service_method_call + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation); ++static GVariant * ++ bus_input_context_service_get_property ++ (IBusService *service, ++ GDBusConnection *connection, ++ const gchar *sender, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *property_name, ++ GError **error); + static gboolean bus_input_context_service_set_property + (IBusService *service, + GDBusConnection *connection, +@@ -214,8 +233,21 @@ static const gchar introspection_xml[] = + "" + " " + /* properties */ ++ " \n" ++ " \n" ++ " \n" ++ " \n" + " " + " \n" ++ " \n" ++ " \n" ++ " \n" ++ " \n" + /* methods */ + " " + " " +@@ -348,6 +380,8 @@ bus_input_context_class_init (BusInputContextClass *class) + /* override the parent class's implementation. */ + IBUS_SERVICE_CLASS (class)->service_method_call = + bus_input_context_service_method_call; ++ IBUS_SERVICE_CLASS (class)->service_get_property = ++ bus_input_context_service_get_property; + IBUS_SERVICE_CLASS (class)->service_set_property = + bus_input_context_service_set_property; + /* register the xml so that bus_ibus_impl_service_method_call will be called on a method call defined in the xml (e.g. 'FocusIn'.) */ +@@ -782,6 +816,11 @@ bus_input_context_property_changed (BusInputContext *context, + } + + ++typedef struct _PanelProcessKeyEventData { ++ GDBusMethodInvocation *invocation; ++ BusInputContext *context; ++} PanelProcessKeyEventData; ++ + /** + * _panel_process_key_event_cb: + * +@@ -789,14 +828,21 @@ bus_input_context_property_changed (BusInputContext *context, + * bus_panel_proxy_process_key_event() is finished. + */ + static void +-_panel_process_key_event_cb (GObject *source, +- GAsyncResult *res, +- GDBusMethodInvocation *invocation) ++_panel_process_key_event_cb (GObject *source, ++ GAsyncResult *res, ++ PanelProcessKeyEventData *data) + { + GError *error = NULL; + GVariant *value = g_dbus_proxy_call_finish ((GDBusProxy *)source, + res, + &error); ++ GDBusMethodInvocation *invocation; ++ BusInputContext *context; ++ ++ g_assert (data); ++ invocation = data->invocation; ++ context = data->context; ++ g_slice_free (PanelProcessKeyEventData, data); + if (value != NULL) { + g_dbus_method_invocation_return_value (invocation, value); + g_variant_unref (value); +@@ -805,6 +851,7 @@ _panel_process_key_event_cb (GObject *source, + g_dbus_method_invocation_return_gerror (invocation, error); + g_error_free (error); + } ++ context->processing_key_event = FALSE; + } + + typedef struct _ProcessKeyEventData ProcessKeyEventData; +@@ -841,21 +888,27 @@ _ic_process_key_event_reply_cb (GObject *source, + gboolean retval = FALSE; + g_variant_get (value, "(b)", &retval); + if (context->emoji_extension && !retval) { ++ PanelProcessKeyEventData *pdata = ++ g_slice_new (PanelProcessKeyEventData); ++ pdata->invocation = invocation; ++ pdata->context = context; + bus_panel_proxy_process_key_event (context->emoji_extension, + keyval, + keycode, + modifiers, + (GAsyncReadyCallback) + _panel_process_key_event_cb, +- invocation); ++ pdata); + } else { + g_dbus_method_invocation_return_value (invocation, value); ++ context->processing_key_event = FALSE; + } + g_variant_unref (value); + } + else { + g_dbus_method_invocation_return_gerror (invocation, error); + g_error_free (error); ++ context->processing_key_event = FALSE; + } + + g_object_unref (context); +@@ -877,6 +930,8 @@ _ic_process_key_event (BusInputContext *context, + guint keycode = 0; + guint modifiers = 0; + ++ if (context->use_post_process_key_event) ++ context->processing_key_event = TRUE; + g_variant_get (parameters, "(uuu)", &keyval, &keycode, &modifiers); + if (G_UNLIKELY (!context->has_focus)) { + /* workaround: set focus if context does not have focus */ +@@ -1372,17 +1427,109 @@ bus_input_context_service_method_call (IBusService *service, + g_return_if_reached (); + } + +-static void ++/** ++ * _ic_get_post_process_key_event: ++ * ++ * Implement the "PostProcessKeyEvent" get property of the ++ * org.freedesktop.IBus.InputContext interface because currently the Gio ++ * D-Bus method calls don't support multiple nested tuples likes ++ * G_VARIANT_TYPE ("((ba(yv)))")) in "ProcessKeyEvent" D-Bus method ++ * So these post events are separated from the return value "b" of ++ * the "ProcessKeyEvent" D-Bus method call. ++ */ ++static GVariant * ++_ic_get_post_process_key_event (BusInputContext *context, ++ GDBusConnection *connection, ++ GError **error) ++{ ++ const char *error_message = NULL; ++ GVariantBuilder array; ++ SyncForwardingData *data; ++ ++ do { ++ if (!BUS_IS_INPUT_CONTEXT (context)) { ++ error_message = "BusInputContext is freed"; ++ break; ++ } ++ if (context->processing_key_event) { ++ error_message = "Another ProcessKeyEvent is called."; ++ break; ++ } ++ g_variant_builder_init (&array, G_VARIANT_TYPE ("a(yv)")); ++ while ((data = ++ g_queue_pop_head (context->queue_during_process_key_event))) { ++ GVariant *variant = ibus_serializable_serialize_object ( ++ IBUS_SERIALIZABLE (data->text)); ++ g_variant_builder_add (&array, "(yv)", data->key, variant); ++ g_object_unref (data->text); ++ g_slice_free (SyncForwardingData, data); ++ } ++ } while (FALSE); ++ if (error_message) { ++ g_set_error (error, ++ G_DBUS_ERROR, ++ G_DBUS_ERROR_FAILED, ++ "%s", error_message); ++ return NULL; ++ } ++ return g_variant_builder_end (&array); ++} ++ ++static GVariant * ++bus_input_context_service_get_property (IBusService *service, ++ GDBusConnection *connection, ++ const gchar *sender, ++ const gchar *object_path, ++ const gchar *interface_name, ++ const gchar *property_name, ++ GError **error) ++{ ++ int i; ++ static const struct { ++ const char *property_name; ++ GVariant * (* property_callback) (BusInputContext *, ++ GDBusConnection *, ++ GError **); ++ } properties [] = { ++ { "PostProcessKeyEvent", _ic_get_post_process_key_event }, ++ }; ++ ++ if (error) ++ *error = NULL; ++ if (g_strcmp0 (interface_name, IBUS_INTERFACE_INPUT_CONTEXT) != 0) { ++ return IBUS_SERVICE_CLASS (bus_input_context_parent_class)-> ++ service_get_property ( ++ service, connection, sender, object_path, ++ interface_name, property_name, ++ error); ++ } ++ for (i = 0; i < G_N_ELEMENTS (properties); i++) { ++ if (g_strcmp0 (properties[i].property_name, property_name) == 0) { ++ return properties[i].property_callback ((BusInputContext *)service, ++ connection, ++ error); ++ } ++ } ++ ++ g_set_error (error, ++ G_DBUS_ERROR, ++ G_DBUS_ERROR_FAILED, ++ "service_get_property received an unknown property: %s", ++ property_name ? property_name : "(null)"); ++ g_return_val_if_reached (NULL); ++} ++ ++static gboolean + _ic_set_content_type (BusInputContext *context, +- GVariant *value) ++ GVariant *value, ++ GError **error) + { + guint purpose = 0; + guint hints = 0; ++ gboolean retval = TRUE; + + g_variant_get (value, "(uu)", &purpose, &hints); + if (purpose != context->purpose || hints != context->hints) { +- GError *error; +- gboolean retval; + + context->purpose = purpose; + context->hints = hints; +@@ -1400,24 +1547,30 @@ _ic_set_content_type (BusInputContext *context, + context->hints); + } + +- error = NULL; + retval = bus_input_context_property_changed (context, + "ContentType", + value, +- &error); +- if (!retval) { +- g_warning ("Failed to emit PropertiesChanged signal: %s", +- error->message); +- g_error_free (error); +- } ++ error); + } ++ return retval; + } + +-static void ++static gboolean + _ic_set_client_commit_preedit (BusInputContext *context, +- GVariant *value) ++ GVariant *value, ++ GError **error) + { + g_variant_get (value, "(b)", &context->client_commit_preedit); ++ return TRUE; ++} ++ ++static gboolean ++_ic_set_use_post_process_key_event (BusInputContext *context, ++ GVariant *value, ++ GError **error) ++{ ++ g_variant_get (value, "(b)", &context->use_post_process_key_event); ++ return TRUE; + } + + static gboolean +@@ -1384,6 +1548,18 @@ bus_input_context_service_set_property ( + GVariant *value, + GError **error) + { ++ int i; ++ static const struct { ++ const char *property_name; ++ gboolean (* property_callback) (BusInputContext *, ++ GVariant *, ++ GError **); ++ } properties [] = { ++ { "ContentType", _ic_set_content_type }, ++ { "ClientCommitPreedit", _ic_set_client_commit_preedit }, ++ { "EffectivePostProcessKeyEvent", _ic_set_use_post_process_key_event }, ++ }; ++ + if (g_strcmp0 (interface_name, IBUS_INTERFACE_INPUT_CONTEXT) != 0) { + return IBUS_SERVICE_CLASS (bus_input_context_parent_class)-> + service_set_property (service, +@@ -1401,13 +1566,12 @@ bus_input_context_service_set_property ( + + g_return_val_if_fail (BUS_IS_INPUT_CONTEXT (service), FALSE); + +- if (g_strcmp0 (property_name, "ContentType") == 0) { +- _ic_set_content_type (BUS_INPUT_CONTEXT (service), value); +- return TRUE; +- } +- if (g_strcmp0 (property_name, "ClientCommitPreedit") == 0) { +- _ic_set_client_commit_preedit (BUS_INPUT_CONTEXT (service), value); +- return TRUE; ++ for (i = 0; i < G_N_ELEMENTS (properties); i++) { ++ if (g_strcmp0 (properties[i].property_name, property_name) == 0) { ++ return properties[i].property_callback ((BusInputContext *) service, ++ value, ++ error); ++ } + } + + g_return_val_if_reached (FALSE); +@@ -2094,7 +2258,23 @@ _engine_forward_key_event_cb (BusEngineProxy *engine, + g_assert (BUS_IS_INPUT_CONTEXT (context)); + + g_assert (context->engine == engine); ++ g_assert (context->queue_during_process_key_event); + ++ if (context->processing_key_event && g_queue_get_length ( ++ context->queue_during_process_key_event) <= MAX_SYNC_DATA) { ++ SyncForwardingData *data; ++ IBusText *text = ibus_text_new_from_printf ("%u,%u,%u", ++ keyval, keycode, state); ++ if (g_queue_get_length (context->queue_during_process_key_event) ++ == MAX_SYNC_DATA) { ++ g_warning ("Exceed max number of post process_key_event data"); ++ } ++ data = g_slice_new (SyncForwardingData); ++ data->key = 'f'; ++ data->text = text; ++ g_queue_push_tail (context->queue_during_process_key_event, data); ++ return; ++ } + bus_input_context_emit_signal (context, + "ForwardKeyEvent", + g_variant_new ("(uuu)", keyval, keycode, state), +@@ -2455,6 +2634,7 @@ bus_input_context_new (BusConnection *connection, + + /* it is a fake input context, just need process hotkey */ + context->fake = (strncmp (client, "fake", 4) == 0); ++ context->queue_during_process_key_event = g_queue_new (); + + if (connection) { + g_object_ref_sink (connection); +@@ -2938,11 +3118,17 @@ bus_input_context_set_content_type (BusInputContext *context, + guint hints) + { + GVariant *value; ++ GError *error = NULL; + + g_assert (BUS_IS_INPUT_CONTEXT (context)); + + value = g_variant_ref_sink (g_variant_new ("(uu)", purpose, hints)); +- _ic_set_content_type (context, value); ++ _ic_set_content_type (context, value, &error); ++ if (error) { ++ g_warning ("Failed to emit PropertiesChanged signal: %s", ++ error->message); ++ g_error_free (error); ++ } + g_variant_unref (value); + } + +@@ -2952,12 +3138,24 @@ bus_input_context_commit_text_use_extension (BusInputContext *context, + gboolean use_extension) + { + g_assert (BUS_IS_INPUT_CONTEXT (context)); ++ g_assert (context->queue_during_process_key_event); + + if (text == text_empty || text == NULL) + return; + + if (use_extension && context->emoji_extension) { + bus_panel_proxy_commit_text_received (context->emoji_extension, text); ++ } else if (context->processing_key_event && g_queue_get_length ( ++ context->queue_during_process_key_event) <= MAX_SYNC_DATA) { ++ SyncForwardingData *data; ++ if (g_queue_get_length (context->queue_during_process_key_event) ++ == MAX_SYNC_DATA) { ++ g_warning ("Exceed max number of sync process_key_event data"); ++ } ++ data = g_slice_new (SyncForwardingData); ++ data->key = 'c'; ++ data->text = g_object_ref (text); ++ g_queue_push_tail (context->queue_during_process_key_event, data); + } else { + GVariant *variant = ibus_serializable_serialize ( + (IBusSerializable *)text); +diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c +index ea8270bb..7ccc129d 100644 +--- a/client/gtk2/ibusimcontext.c ++++ b/client/gtk2/ibusimcontext.c +@@ -111,7 +111,7 @@ static guint _signal_delete_surrounding_id = 0; + static guint _signal_retrieve_surrounding_id = 0; + + #if GTK_CHECK_VERSION (3, 98, 4) +-static char _use_sync_mode = 2; ++static char _use_sync_mode = 1; + #else + static const gchar *_no_snooper_apps = NO_SNOOPER_APPS; + static gboolean _use_key_snooper = ENABLE_SNOOPER; +@@ -386,6 +386,7 @@ typedef struct { + gboolean retval; + } ProcessKeyEventReplyData; + ++ + static void + _process_key_event_done (GObject *object, + GAsyncResult *res, +@@ -435,6 +436,7 @@ _process_key_event_done (GObject *object, + #endif + } + ++ + static void + _process_key_event_reply_done (GObject *object, + GAsyncResult *res, +@@ -457,6 +459,7 @@ _process_key_event_reply_done (GObject *object, + g_source_remove (data->count_cb_id); + } + ++ + static gboolean + _process_key_event_count_cb (gpointer user_data) + { +@@ -472,6 +475,101 @@ _process_key_event_count_cb (gpointer user_data) + return G_SOURCE_CONTINUE; + } + ++ ++static gboolean ++_process_key_event_sync (IBusInputContext *context, ++ guint keyval, ++ guint keycode, ++ guint state) ++{ ++ gboolean retval; ++ ++ g_assert (IBUS_IS_INPUT_CONTEXT (context)); ++ retval = ibus_input_context_process_key_event (context, ++ keyval, ++ keycode - 8, ++ state); ++ ibus_input_context_post_process_key_event (context); ++ return retval; ++} ++ ++ ++static gboolean ++_process_key_event_async (IBusInputContext *context, ++ guint keyval, ++ guint keycode, ++ guint state, ++ GdkEvent *event, ++ IBusIMContext *ibusimcontext) ++{ ++ ProcessKeyEventData *data = g_slice_new0 (ProcessKeyEventData); ++ ++ g_assert (event); ++ if (!data) { ++ g_warning ("Cannot allocate async data"); ++ return _process_key_event_sync (context, keyval, keycode, state); ++ } ++#if GTK_CHECK_VERSION (3, 98, 4) ++ data->event = gdk_event_ref (event); ++#else ++ data->event = gdk_event_copy (event); ++#endif ++ data->ibusimcontext = ibusimcontext; ++ ibus_input_context_process_key_event_async (context, ++ keyval, ++ keycode - 8, ++ state, ++ -1, ++ NULL, ++ _process_key_event_done, ++ data); ++ ++ return TRUE; ++} ++ ++ ++static gboolean ++_process_key_event_hybrid_async (IBusInputContext *context, ++ guint keyval, ++ guint keycode, ++ guint state) ++{ ++ GSource *source = g_timeout_source_new (1); ++ ProcessKeyEventReplyData *data = NULL; ++ gboolean retval = FALSE; ++ ++ if (source) ++ data = g_slice_new0 (ProcessKeyEventReplyData); ++ if (!data) { ++ g_warning ("Cannot wait for the reply of the process key event."); ++ retval = _process_key_event_sync (context, keyval, keycode, state); ++ if (source) ++ g_source_destroy (source); ++ return retval; ++ } ++ data->count = 1; ++ g_source_attach (source, NULL); ++ g_source_unref (source); ++ data->count_cb_id = g_source_get_id (source); ++ ibus_input_context_process_key_event_async (context, ++ keyval, ++ keycode - 8, ++ state, ++ -1, ++ NULL, ++ _process_key_event_reply_done, ++ data); ++ g_source_set_callback (source, _process_key_event_count_cb, data, NULL); ++ while (data->count) ++ g_main_context_iteration (NULL, TRUE); ++ /* #2498 Checking source->ref_count might cause Nautilus hang up ++ */ ++ retval = data->retval; ++ g_slice_free (ProcessKeyEventReplyData, data); ++ return retval; ++} ++ ++ + static gboolean + _process_key_event (IBusInputContext *context, + #if GTK_CHECK_VERSION (3, 98, 4) +@@ -505,70 +603,20 @@ _process_key_event (IBusInputContext *context, + + switch (_use_sync_mode) { + case 1: { +- retval = ibus_input_context_process_key_event (context, +- keyval, +- keycode - 8, +- state); ++ retval = _process_key_event_sync (context, keyval, keycode, state); + break; + } + case 2: { +- GSource *source = g_timeout_source_new (1); +- ProcessKeyEventReplyData *data = NULL; +- +- if (source) +- data = g_slice_new0 (ProcessKeyEventReplyData); +- if (!data) { +- g_warning ("Cannot wait for the reply of the process key event."); +- retval = ibus_input_context_process_key_event (context, +- keyval, +- keycode - 8, +- state); +- if (source) +- g_source_destroy (source); +- break; +- } +- data->count = 1; +- g_source_attach (source, NULL); +- g_source_unref (source); +- data->count_cb_id = g_source_get_id (source); +- ibus_input_context_process_key_event_async (context, +- keyval, +- keycode - 8, +- state, +- -1, +- NULL, +- _process_key_event_reply_done, +- data); +- g_source_set_callback (source, _process_key_event_count_cb, data, NULL); +- while (data->count) +- g_main_context_iteration (NULL, TRUE); +- if (source->ref_count > 0) { +- /* g_source_get_id() could causes a SEGV */ +- g_info ("Broken GSource.ref_count and maybe a timing issue in %p.", +- source); +- } +- retval = data->retval; +- g_slice_free (ProcessKeyEventReplyData, data); ++ retval = _process_key_event_hybrid_async (context, ++ keyval, keycode, state); + break; + } + default: { +- ProcessKeyEventData *data = g_slice_new0 (ProcessKeyEventData); +-#if GTK_CHECK_VERSION (3, 98, 4) +- data->event = gdk_event_ref (event); +-#else +- data->event = gdk_event_copy ((GdkEvent *)event); +-#endif +- data->ibusimcontext = ibusimcontext; +- ibus_input_context_process_key_event_async (context, +- keyval, +- keycode - 8, +- state, +- -1, +- NULL, +- _process_key_event_done, +- data); +- +- retval = TRUE; ++ retval = _process_key_event_async (context, ++ keyval, keycode, state, ++ (GdkEvent *)event, ++ ibusimcontext); ++ break; + } + } + +@@ -877,7 +925,55 @@ ibus_im_context_class_init (IBusIMContextClass *class) + g_assert (_signal_retrieve_surrounding_id != 0); + + #if GTK_CHECK_VERSION (3, 98, 4) +- _use_sync_mode = _get_char_env ("IBUS_ENABLE_SYNC_MODE", 2); ++ /* IBus GtkIMModule, QtIMModlue, ibus-x11, ibus-wayland are called as ++ * IBus clients. ++ * Each GTK application, each QT application, Xorg server, Wayland ++ * comppsitor are called as IBus event owners here. ++ * ++ * The IBus client processes the key events between the IBus event owner ++ * and the IBus daemon and the procedure step is to: ++ * ++ * receive the key event from the IBus event owner and forward the ++ * event to the IBus daemon with the "ProcessKeyEvent" D-Bus method at ++ * first, ++ * ++ * receive the return value from the IBus daemon with the "ProessKeyEvent" ++ * D-Bus method and forward the value to the IBus event owner secondly and ++ * the return value includes if the key event is processed normally or not. ++ * ++ * The procedure behavior can be changed by the "IBUS_ENABLE_SYNC_MODE" ++ * environment variable with the synchronous procedure or asynchronous ++ * one and value is: ++ * ++ * 1: Synchronous process key event: ++ * Wait for the return of the IBus "ProcessKeyEvent" D-Bus method ++ * synchronously and forward the return value to the IBus event owner ++ * synchronously. ++ * 0: Asynchronous process key event: ++ * Return to the IBus event owner as the key event is processed normally ++ * at first as soon as the IBus client receives the event from the ++ * IBus event owner and also forward the event to the IBus daemon with ++ * the "ProcessKeyEvent" D-Bus method and wait for the return value of ++ * the D-Bus method *asynchronously*. ++ * If the return value indicates the key event is disposed by IBus, ++ * the IBus client does not perform anything. Otherwise the IBus client ++ * forwards the key event with the gdk_event_put() in GTK3, ++ * gtk_im_context_filter_key() in GTK4, IMForwardEvent() in XIM API. ++ * 2: Hybrid asynchronous process key event: ++ * Wait for the return of the IBus "ProcessKeyEvent" D-Bus method ++ * *asynchronously* with a GSource loop and forward the return value ++ * to the IBus event owner synchronously. So IBus clients perform ++ * virtually synchronously to cover problems of IBus synchronous APIs. ++ * ++ * The purpose of the asynchronous process is that each IBus input ++ * method can process the key events without D-Bus timeout and also ++ * the IBus synchronous process has a problem that the IBus ++ * "ProcessKeyEvent" D-Bus method cannot send the commit-text and ++ * forwar-key-event D-Bus signals until the D-Bus method is finished. ++ * ++ * Relative issues: #1713, #2486 ++ */ ++ _use_sync_mode = _get_char_env ("IBUS_ENABLE_SYNC_MODE", 1); + #else + _use_key_snooper = !_get_boolean_env ("IBUS_DISABLE_SNOOPER", + !(ENABLE_SNOOPER)); +@@ -1004,8 +1100,6 @@ ibus_im_context_init (GObject *obj) + #else + ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS; + #endif +- if (_use_sync_mode == 1) +- ibusimcontext->caps |= IBUS_CAP_SYNC_PROCESS_KEY_V2; + + ibusimcontext->events_queue = g_queue_new (); + +@@ -2235,6 +2329,8 @@ _create_input_context_done (IBusBus *bus, + } + else { + ibus_input_context_set_client_commit_preedit (context, TRUE); ++ if (_use_sync_mode == 1) ++ ibus_input_context_set_post_process_key_event (context, TRUE); + ibusimcontext->ibuscontext = context; + + g_signal_connect (ibusimcontext->ibuscontext, +@@ -2489,9 +2585,8 @@ _create_fake_input_context_done (IBusBus *bus, + G_CALLBACK (_ibus_fake_context_destroy_cb), + NULL); + +- guint32 caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT; +- if (_use_sync_mode == 1) +- caps |= IBUS_CAP_SYNC_PROCESS_KEY_V2; ++ guint32 caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS ++ | IBUS_CAP_SURROUNDING_TEXT; + ibus_input_context_set_capabilities (_fake_context, caps); + + /* focus in/out the fake context */ +diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c +index 28ae04ad..def23b25 100644 +--- a/src/ibusinputcontext.c ++++ b/src/ibusinputcontext.c +@@ -2,7 +2,7 @@ + /* vim:set et sts=4: */ + /* ibus - The Input Bus + * Copyright (C) 2008-2013 Peng Huang +- * Copyright (C) 2018-2019 Takao Fujiwara ++ * Copyright (C) 2018-2023 Takao Fujiwara + * Copyright (C) 2008-2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or +@@ -1190,14 +1190,14 @@ ibus_input_context_set_content_type (IBusInputContext *context, + g_assert (IBUS_IS_INPUT_CONTEXT (context)); + + cached_content_type = +- g_dbus_proxy_get_cached_property ((GDBusProxy *) context, ++ g_dbus_proxy_get_cached_property ((GDBusProxy *)context, + "ContentType"); + content_type = g_variant_new ("(uu)", purpose, hints); + + g_variant_ref_sink (content_type); +- if (cached_content_type == NULL || ++ if (!cached_content_type || + !g_variant_equal (content_type, cached_content_type)) { +- g_dbus_proxy_call ((GDBusProxy *) context, ++ g_dbus_proxy_call ((GDBusProxy *)context, + "org.freedesktop.DBus.Properties.Set", + g_variant_new ("(ssv)", + IBUS_INTERFACE_INPUT_CONTEXT, +@@ -1209,9 +1209,13 @@ ibus_input_context_set_content_type (IBusInputContext *context, + NULL, /* callback */ + NULL /* user_data */ + ); ++ /* Need to update the cache by manual since there is a timing issue. */ ++ g_dbus_proxy_set_cached_property ((GDBusProxy *)context, ++ "ContentType", ++ content_type); + } + +- if (cached_content_type != NULL) ++ if (cached_content_type) + g_variant_unref (cached_content_type); + g_variant_unref (content_type); + } +@@ -1324,19 +1328,20 @@ void + ibus_input_context_set_client_commit_preedit (IBusInputContext *context, + gboolean client_commit) + { +- GVariant *cached_content_type; ++ GVariant *cached_var_client_commit; + GVariant *var_client_commit; + + g_assert (IBUS_IS_INPUT_CONTEXT (context)); + +- cached_content_type = +- g_dbus_proxy_get_cached_property ((GDBusProxy *) context, ++ cached_var_client_commit = ++ g_dbus_proxy_get_cached_property ((GDBusProxy *)context, + "ClientCommitPreedit"); + var_client_commit = g_variant_new ("(b)", client_commit); + + g_variant_ref_sink (var_client_commit); +- if (cached_content_type == NULL) { +- g_dbus_proxy_call ((GDBusProxy *) context, ++ if (!cached_var_client_commit || ++ !g_variant_equal (var_client_commit, cached_var_client_commit)) { ++ g_dbus_proxy_call ((GDBusProxy *)context, + "org.freedesktop.DBus.Properties.Set", + g_variant_new ("(ssv)", + IBUS_INTERFACE_INPUT_CONTEXT, +@@ -1348,13 +1353,146 @@ ibus_input_context_set_client_commit_preedit (IBusInputContext *context, + NULL, /* callback */ + NULL /* user_data */ + ); ++ /* Need to update the cache by manual since there is a timing issue. */ ++ g_dbus_proxy_set_cached_property ((GDBusProxy *)context, ++ "ClientCommitPreedit", ++ var_client_commit); + } + +- if (cached_content_type != NULL) +- g_variant_unref (cached_content_type); ++ if (cached_var_client_commit) ++ g_variant_unref (cached_var_client_commit); + g_variant_unref (var_client_commit); + } + ++void ++ibus_input_context_set_post_process_key_event (IBusInputContext *context, ++ gboolean enable) ++{ ++ GVariant *cached_var_post; ++ GVariant *var_post; ++ ++ g_assert (IBUS_IS_INPUT_CONTEXT (context)); ++ ++ cached_var_post = ++ g_dbus_proxy_get_cached_property ((GDBusProxy *)context, ++ "EffectivePostProcessKeyEvent"); ++ var_post = g_variant_new ("(b)", enable); ++ g_variant_ref_sink (var_post); ++ if (!cached_var_post || ++ !g_variant_equal (var_post, cached_var_post)) { ++ g_dbus_proxy_call ((GDBusProxy *)context, ++ "org.freedesktop.DBus.Properties.Set", ++ g_variant_new ("(ssv)", ++ IBUS_INTERFACE_INPUT_CONTEXT, ++ "EffectivePostProcessKeyEvent", ++ var_post), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, ++ NULL, /* cancellable */ ++ NULL, /* callback */ ++ NULL /* user_data */ ++ ); ++ /* Need to update the cache by manual since there is a timing issue. */ ++ g_dbus_proxy_set_cached_property ((GDBusProxy *)context, ++ "EffectivePostProcessKeyEvent", ++ var_post); ++ } ++ ++ if (cached_var_post) ++ g_variant_unref (cached_var_post); ++ g_variant_unref (var_post); ++} ++ ++void ++ibus_input_context_post_process_key_event (IBusInputContext *context) ++{ ++ GVariant *cached_var_post; ++ gboolean enable = FALSE; ++ GVariant *result; ++ GError *error = NULL; ++ GVariant *variant = NULL; ++ GVariantIter iter; ++ gsize size; ++ char type = 0; ++ GVariant *vtext = NULL; ++ ++ g_assert (IBUS_IS_INPUT_CONTEXT (context)); ++ ++ cached_var_post = ++ g_dbus_proxy_get_cached_property ((GDBusProxy *)context, ++ "EffectivePostProcessKeyEvent"); ++ if (cached_var_post) ++ g_variant_get (cached_var_post, "(b)", &enable); ++ if (!enable) { ++ g_warning ("%s: ibus_input_context_set_post_process_key_event() " ++ "needs to be called before.", ++ G_STRFUNC); ++ if (cached_var_post) ++ g_variant_unref (cached_var_post); ++ return; ++ } ++ g_variant_unref (cached_var_post); ++ result = g_dbus_proxy_call_sync ( ++ (GDBusProxy *)context, ++ "org.freedesktop.DBus.Properties.Get", ++ g_variant_new ("(ss)", ++ IBUS_INTERFACE_INPUT_CONTEXT, ++ "PostProcessKeyEvent"), ++ G_DBUS_CALL_FLAGS_NONE, ++ -1, ++ NULL, ++ &error); ++ if (error) { ++ g_warning ("%s: %s", G_STRFUNC, error->message); ++ g_error_free (error); ++ return; ++ } ++ ++ g_variant_get (result, "(v)", &variant); ++ g_assert (variant); ++ g_variant_iter_init (&iter, variant); ++ size = g_variant_iter_n_children (&iter); ++ while (size >0 && g_variant_iter_loop (&iter, "(yv)", &type, &vtext)) { ++ IBusText *text = ++ (IBusText *)ibus_serializable_deserialize_object (vtext); ++ if (!IBUS_IS_TEXT (text)) { ++ g_warning ("%s: %s", G_STRFUNC, "text is not IBusText"); ++ break; ++ } ++ switch (type) { ++ case 'c': ++ g_signal_emit (context, context_signals[COMMIT_TEXT], 0, text); ++ break; ++ case 'f': { ++ gchar **array = NULL; ++ guint keyval, keycode, state; ++ array = g_strsplit (text->text, ",", -1); ++ keyval = g_ascii_strtoull (array[0], NULL, 10); ++ keycode = g_ascii_strtoull (array[1], NULL, 10); ++ state = g_ascii_strtoull (array[2], NULL, 10); ++ g_strfreev (array); ++ g_signal_emit (context, ++ context_signals[FORWARD_KEY_EVENT], ++ 0, ++ keyval, ++ keycode, ++ state | IBUS_FORWARD_MASK); ++ break; ++ } ++ default: ++ g_warning ("%s: Type '%c' is not supported.", G_STRFUNC, type); ++ } ++ if (g_object_is_floating (text)) { ++ g_object_ref_sink (text); ++ g_object_unref (text); ++ } ++ g_clear_pointer (&vtext, g_variant_unref); ++ } ++ ++ g_variant_unref (variant); ++ g_variant_unref (result); ++} ++ + #define DEFINE_FUNC(name, Name) \ + void \ + ibus_input_context_##name (IBusInputContext *context) \ +diff --git a/src/ibusinputcontext.h b/src/ibusinputcontext.h +index 09992148..ca604670 100644 +--- a/src/ibusinputcontext.h ++++ b/src/ibusinputcontext.h +@@ -2,7 +2,7 @@ + /* vim:set et sts=4: */ + /* ibus - The Input Bus + * Copyright (C) 2008-2013 Peng Huang +- * Copyright (C) 2018 Takao Fujiwara ++ * Copyright (C) 2018-2023 Takao Fujiwara + * Copyright (C) 2008-2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or +@@ -298,7 +298,6 @@ gboolean ibus_input_context_process_key_event + guint32 keycode, + guint32 state); + +- + /** + * ibus_input_context_set_cursor_location: + * @context: An IBusInputContext. +@@ -519,9 +518,38 @@ void ibus_input_context_set_content_type + * + * See also ibus_engine_update_preedit_text_with_mode(). + */ +-void ibus_input_context_set_client_commit_preedit ( +- IBusInputContext *context, ++void ibus_input_context_set_client_commit_preedit ++ (IBusInputContext *context, + gboolean client_commit); + ++/** ++ * ibus_input_context_set_post_process_key_event: ++ * @context: An #IBusInputContext. ++ * @enable: Can use ibus_input_context_post_process_key_event() to retrieve ++ * commit-text and forwar-key-event signals during ++ * calling ibus_input_context_process_key_event() if it's %TRUE. ++ * ++ * Since: 1.5.00 ++ * Stability: Unstable ++ */ ++void ibus_input_context_set_post_process_key_event ++ (IBusInputContext *context, ++ gboolean enable); ++/** ++ * ibus_input_context_post_process_key_event: ++ * @context: An #IBusInputContext. ++ * ++ * Call this API after ibus_input_context_process_key_event() returns ++ * to retrieve commit-text and forwar-key-event signals during ++ * calling ibus_input_context_process_key_event(). ++ * ++ * See also ibus_input_context_set_post_process_key_event(). ++ * ++ * Since: 1.5.00 ++ * Stability: Unstable ++ */ ++void ibus_input_context_post_process_key_event ++ (IBusInputContext *context); ++ + G_END_DECLS + #endif +-- +2.41.0 + +From 86d9bb9a1cbd4ffbd6bc2a4de85cb76a43bc2ced Mon Sep 17 00:00:00 2001 +From: Peng Wu +Date: Mon, 24 Jul 2023 14:04:12 +0800 +Subject: [PATCH] client/gtk2: Update set_cursor_location function to use Gdk + functions + +For ibus-gtk4, use the Gdk functions to get the inner cursor location. +The inner cursor location is translated by XTranslateCoordinates +for X Window. +For ibus-gtk3, use gdk_window_get_root_coords function to translate the +inner cursor location for X Window. +In Wayland, the set_cursor_location_relative function is called. +In X Window, the set_cursor_location function is called. + +Fixes: https://github.com/ibus/ibus/commit/d0a47c3 +Fixes: https://github.com/ibus/ibus/commit/a823161 + +BUG=https://github.com/ibus/ibus/pull/2549 +BUG=https://gitlab.gnome.org/GNOME/gtk/-/issues/3024#note_987835 +--- + client/gtk2/ibusimcontext.c | 141 +++++++++++++++--------------------- + 1 file changed, 58 insertions(+), 83 deletions(-) + +diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c +index 7ccc129d..b5a44da0 100644 +--- a/client/gtk2/ibusimcontext.c ++++ b/client/gtk2/ibusimcontext.c +@@ -27,6 +27,7 @@ + + #include + #include ++#include + #include + #include + #include "ibusimcontext.h" +@@ -1612,8 +1613,13 @@ static gboolean + _set_cursor_location_internal (IBusIMContext *ibusimcontext) + { + GdkRectangle area; ++ GdkDisplay *display = NULL; + #if GTK_CHECK_VERSION (3, 98, 4) + GtkWidget *root; ++ GtkNative *native; ++ graphene_point_t p; ++ int tx = 0, ty = 0; ++ double nx = 0., ny = 0.; + #endif + + if(ibusimcontext->client_window == NULL || +@@ -1623,103 +1629,72 @@ _set_cursor_location_internal (IBusIMContext *ibusimcontext) + + area = ibusimcontext->cursor_area; + +-#ifdef GDK_WINDOWING_WAYLAND + #if GTK_CHECK_VERSION (3, 98, 4) + root = GTK_WIDGET (gtk_widget_get_root (ibusimcontext->client_window)); +- /* FIXME: GTK_STYLE_CLASS_TITLEBAR is available in GTK3 but not GTK4. +- * gtk_css_boxes_get_content_rect() is available in GTK4 but it's an +- * internal API and calculate the window edge 32 in GTK3. +- */ +- area.y += 32; +- area.width = 50; /* FIXME: Why 50 meets the cursor position? */ +- area.height = gtk_widget_get_height (root); +- area.height += 32; +- if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) { +- ibus_input_context_set_cursor_location_relative ( +- ibusimcontext->ibuscontext, +- area.x, +- area.y, +- area.width, +- area.height); +- return FALSE; +- } +-#else +- if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) { +- gdouble px, py; +- GdkWindow *parent; +- GdkWindow *window = ibusimcontext->client_window; +- +- while ((parent = gdk_window_get_effective_parent (window)) != NULL) { +- gdk_window_coords_to_parent (window, area.x, area.y, &px, &py); +- area.x = px; +- area.y = py; +- window = parent; +- } +- +- _set_rect_scale_factor_with_window (&area, +- ibusimcontext->client_window); +- ibus_input_context_set_cursor_location_relative ( +- ibusimcontext->ibuscontext, +- area.x, +- area.y, +- area.width, +- area.height); +- return FALSE; ++ /* Translates the given point in client_window coordinates to coordinates ++ relative to root coordinate system. */ ++ if (!gtk_widget_compute_point (ibusimcontext->client_window, ++ root, ++ &GRAPHENE_POINT_INIT (area.x, area.y), ++ &p)) { ++ graphene_point_init (&p, area.x, area.y); + } +-#endif +-#endif + +-#if GTK_CHECK_VERSION (3, 98, 4) +-#elif GTK_CHECK_VERSION (2, 91, 0) +- if (area.x == -1 && area.y == -1 && area.width == 0 && area.height == 0) { +- area.x = 0; +- area.y += gdk_window_get_height (ibusimcontext->client_window); +- } +-#else +- if (area.x == -1 && area.y == -1 && area.width == 0 && area.height == 0) { +- gint w, h; +- gdk_drawable_get_size (ibusimcontext->client_window, &w, &h); +- area.y += h; +- area.x = 0; +- } +-#endif ++ native = gtk_widget_get_native (ibusimcontext->client_window); ++ /* Translates from the surface coordinates into the widget coordinates. */ ++ gtk_native_get_surface_transform (native, &nx, &ny); + +-#if GTK_CHECK_VERSION (3, 98, 4) +-#if defined(GDK_WINDOWING_X11) +- GdkDisplay *display = gtk_widget_get_display (ibusimcontext->client_window); ++ display = gtk_widget_get_display (ibusimcontext->client_window); + if (GDK_IS_X11_DISPLAY (display)) { +- Display *xdisplay = gdk_x11_display_get_xdisplay (display); +- Window root_window = gdk_x11_display_get_xrootwindow (display); +- GtkNative *native = gtk_widget_get_native ( +- ibusimcontext->client_window); +- GdkSurface *surface = gtk_native_get_surface (native); +- /* The window is the toplevel window but not the inner text widget. +- * Unfortunatelly GTK4 cannot get the coordinate of the text widget. +- */ +- Window window = gdk_x11_surface_get_xid (surface); ++ GdkSurface *surface = gtk_native_get_surface ++ (gtk_widget_get_native (ibusimcontext->client_window)); + Window child; +- int x, y; +- XTranslateCoordinates (xdisplay, window, root_window, +- 0, 0, &x, &y, &child); +- XWindowAttributes xwa; +- XGetWindowAttributes (xdisplay, window, &xwa); +- area.x = x - xwa.x + area.x; +- area.y = y - xwa.y + area.y; +- area.width = 50; /* FIXME: Why 50 meets the cursor position? */ +- area.height = xwa.height; ++ int scale_factor = gtk_widget_get_scale_factor ++ (ibusimcontext->client_window); ++ ++ XTranslateCoordinates (GDK_DISPLAY_XDISPLAY (display), ++ GDK_SURFACE_XID (surface), ++ gdk_x11_display_get_xrootwindow (display), ++ 0, 0, &tx, &ty, ++ &child); ++ ++ tx = tx / scale_factor; ++ ty = ty / scale_factor; + } +-#endif ++ ++ area.x = p.x + nx + tx; ++ area.y = p.y + ny + ty; + #else + gdk_window_get_root_coords (ibusimcontext->client_window, + area.x, area.y, + &area.x, &area.y); + #endif ++ + _set_rect_scale_factor_with_window (&area, ibusimcontext->client_window); +- ibus_input_context_set_cursor_location (ibusimcontext->ibuscontext, +- area.x, +- area.y, +- area.width, +- area.height); ++ ++#ifdef GDK_WINDOWING_WAYLAND ++#if !GTK_CHECK_VERSION (3, 98, 4) ++ display = gdk_window_get_display (ibusimcontext->client_window); ++#endif ++ ++ if (GDK_IS_WAYLAND_DISPLAY (display)) { ++ ibus_input_context_set_cursor_location_relative (ibusimcontext->ibuscontext, ++ area.x, ++ area.y, ++ area.width, ++ area.height); ++ ++ } else { ++#endif ++ ibus_input_context_set_cursor_location (ibusimcontext->ibuscontext, ++ area.x, ++ area.y, ++ area.width, ++ area.height); ++#ifdef GDK_WINDOWING_WAYLAND ++ } ++#endif ++ + return FALSE; + } + +-- +2.41.0 + +From f176569cf774f87b23270257da68249dcda837c9 Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Wed, 18 Oct 2023 16:57:28 +0900 +Subject: [PATCH] src: Add DeleteSurroundingText to PostProcessKeyEvent + +DeleteSurroundingText also can be delayed sending to IBus clients. +Now surrounding D-Bus methods are added to PostProcessKeyEvent. + +Fixes: https://github.com/ibus/ibus/commit/38f09c6 + +BUG=https://github.com/ibus/ibus/issues/2570 +--- + bus/inputcontext.c | 33 +++++++++++++++++++++++++++++++-- + src/ibusinputcontext.c | 23 +++++++++++++++++++++++ + 2 files changed, 54 insertions(+), 2 deletions(-) + +diff --git a/bus/inputcontext.c b/bus/inputcontext.c +index aecc64f8..64430fe4 100644 +--- a/bus/inputcontext.c ++++ b/bus/inputcontext.c +@@ -2382,7 +2382,7 @@ _engine_forward_key_event_cb (BusEngineProxy *engine, + g_assert (context->queue_during_process_key_event); + + if (context->processing_key_event && g_queue_get_length ( +- context->queue_during_process_key_event) <= MAX_SYNC_DATA) { ++ context->queue_during_process_key_event) <= MAX_SYNC_DATA) { + SyncForwardingData *data; + IBusText *text = ibus_text_new_from_printf ("%u,%u,%u", + keyval, keycode, state); +@@ -2397,6 +2397,21 @@ _engine_delete_surrounding_text_cb (BusEngineProxy *engine, + + g_assert (context->engine == engine); + ++ if (context->processing_key_event && g_queue_get_length ( ++ context->queue_during_process_key_event) <= MAX_SYNC_DATA) { ++ SyncForwardingData *data; ++ IBusText *text = ibus_text_new_from_printf ("%d,%u", ++ offset_from_cursor, nchars); ++ if (g_queue_get_length (context->queue_during_process_key_event) ++ == MAX_SYNC_DATA) { ++ g_warning ("Exceed max number of sync process_key_event data"); ++ } ++ data = g_slice_new (SyncForwardingData); ++ data->key = 'd'; ++ data->text = g_object_ref (text); ++ g_queue_push_tail (context->queue_during_process_key_event, data); ++ return; ++ } + bus_input_context_emit_signal (context, + "DeleteSurroundingText", + g_variant_new ("(iu)", offset_from_cursor, nchars), +@@ -2442,6 +2457,20 @@ _engine_require_surrounding_text_cb (BusEngineProxy *engine, + + g_assert (context->engine == engine); + ++ if (context->processing_key_event && g_queue_get_length ( ++ context->queue_during_process_key_event) <= MAX_SYNC_DATA) { ++ SyncForwardingData *data; ++ IBusText *text = ibus_text_new_from_static_string (""); ++ if (g_queue_get_length (context->queue_during_process_key_event) ++ == MAX_SYNC_DATA) { ++ g_warning ("Exceed max number of post process_key_event data"); ++ } ++ data = g_slice_new (SyncForwardingData); ++ data->key = 'r'; ++ data->text = text; ++ g_queue_push_tail (context->queue_during_process_key_event, data); ++ return; ++ } + bus_input_context_emit_signal (context, + "RequireSurroundingText", + NULL, +@@ -3158,7 +3187,7 @@ bus_input_context_commit_text_use_extension (BusInputContext *context, + if (use_extension && context->emoji_extension) { + bus_panel_proxy_commit_text_received (context->emoji_extension, text); + } else if (context->processing_key_event && g_queue_get_length ( +- context->queue_during_process_key_event) <= MAX_SYNC_DATA) { ++ context->queue_during_process_key_event) <= MAX_SYNC_DATA) { + SyncForwardingData *data; + if (g_queue_get_length (context->queue_during_process_key_event) + == MAX_SYNC_DATA) { +diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c +index def23b25..c6a030fe 100644 +--- a/src/ibusinputcontext.c ++++ b/src/ibusinputcontext.c +@@ -1406,6 +1406,7 @@ ibus_input_context_set_post_process_key_event (IBusInputContext *context, + void + ibus_input_context_post_process_key_event (IBusInputContext *context) + { ++ IBusInputContextPrivate *priv; + GVariant *cached_var_post; + gboolean enable = FALSE; + GVariant *result; +@@ -1418,6 +1419,7 @@ ibus_input_context_post_process_key_event (IBusInputContext *context) + + g_assert (IBUS_IS_INPUT_CONTEXT (context)); + ++ priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context)); + cached_var_post = + g_dbus_proxy_get_cached_property ((GDBusProxy *)context, + "EffectivePostProcessKeyEvent"); +@@ -1479,6 +1481,25 @@ ibus_input_context_post_process_key_event (IBusInputContext *context) + state | IBUS_FORWARD_MASK); + break; + } ++ case 'r': { ++ priv->needs_surrounding_text = TRUE; ++ break; ++ } ++ case 'd': { ++ gchar **array = NULL; ++ gint offset_from_cursor; ++ guint nchars; ++ array = g_strsplit (text->text, ",", -1); ++ offset_from_cursor = g_ascii_strtoll (array[0], NULL, 10); ++ nchars = g_ascii_strtoull (array[1], NULL, 10); ++ g_strfreev (array); ++ g_signal_emit (context, ++ context_signals[DELETE_SURROUNDING_TEXT], ++ 0, ++ offset_from_cursor, ++ nchars); ++ break; ++ } + default: + g_warning ("%s: Type '%c' is not supported.", G_STRFUNC, type); + } +-- +2.41.0 + +From ef0d29d8bf4e533c428b2cd9d3ee9fa42e9e20e7 Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Wed, 25 Oct 2023 16:46:07 +0900 +Subject: [PATCH] src: Add preedit D-Bus signals to PostProcessKeyEvent + +ibus-hangul calls UpdatePreeditText signal during pressing Enter key +to hide the current preedit text and this also causes the reorder issue +in sync process-key-event and need to move the preedit signals +to PostProcessKeyEvent. + +Also refactor PostProcessKeyEvent codes. + +Fixes: https://github.com/ibus/ibus/commit/38f09c6 + +BUG=https://github.com/ibus/ibus/pull/2575 +--- + bus/inputcontext.c | 176 +++++++++++++++++++++++++++-------------- + src/ibusinputcontext.c | 162 +++++++++++++++++++++++++++++-------- + 2 files changed, 248 insertions(+), 90 deletions(-) + +diff --git a/bus/inputcontext.c b/bus/inputcontext.c +index 64430fe4..c914fbd2 100644 +--- a/bus/inputcontext.c ++++ b/bus/inputcontext.c +@@ -48,11 +48,25 @@ struct _SetEngineByDescData { + }; + typedef struct _SetEngineByDescData SetEngineByDescData; + ++typedef struct _DeleteSurroundingData { ++ gint offset; ++ guint nchars; ++} DeleteSurroundingData; ++ + typedef struct _SyncForwardingData { +- gchar key; +- IBusText *text; ++ char key; ++ IBusText *text; + } SyncForwardingData; + ++typedef struct _SyncForwardingPreData { ++ char key; ++ IBusText *text; ++ union { ++ guint uints[3]; ++ DeleteSurroundingData deleting; ++ } u; ++} SyncForwardingPreData; ++ + struct _BusInputContext { + IBusService parent; + +@@ -970,6 +984,7 @@ _ic_process_key_event (BusInputContext *context, + } + else { + g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", FALSE)); ++ context->processing_key_event = FALSE; + } + } + +@@ -1654,6 +1670,71 @@ bus_input_context_service_set_property (IBusService *service, + } + + ++static gboolean ++bus_input_context_make_post_process_key_event (BusInputContext *context, ++ SyncForwardingPreData *pre_data) ++{ ++ SyncForwardingData *data; ++ if (context->processing_key_event && g_queue_get_length ( ++ context->queue_during_process_key_event) <= MAX_SYNC_DATA) { ++ if (g_queue_get_length (context->queue_during_process_key_event) ++ == MAX_SYNC_DATA) { ++ g_warning ("Exceed max number of post process_key_event data"); ++ } ++ data = g_slice_new (SyncForwardingData); ++ data->key = pre_data->key; ++ switch (pre_data->key) { ++ case 'c': ++ data->text = g_object_ref (pre_data->text); ++ break; ++ case 'd': ++ data->text = ibus_text_new_from_printf ( ++ "%d,%u", ++ pre_data->u.deleting.offset, ++ pre_data->u.deleting.nchars); ++ break; ++ case 'f': ++ data->text = ibus_text_new_from_printf ("%u,%u,%u", ++ pre_data->u.uints[0], ++ pre_data->u.uints[1], ++ pre_data->u.uints[2]); ++ break; ++ case 'h': ++ case 'r': ++ case 's': ++ data->text = ibus_text_new_from_static_string (""); ++ break; ++ case 'u': ++ case 'm': ++ data->text = g_object_ref (pre_data->text); ++ g_queue_push_tail (context->queue_during_process_key_event, data); ++ data = g_slice_new (SyncForwardingData); ++ data->key = pre_data->key; ++ if (pre_data->key == 'u') { ++ data->text = ibus_text_new_from_printf ( ++ "%u,%u", ++ pre_data->u.uints[0], ++ pre_data->u.uints[1]); ++ } else { ++ data->text = ibus_text_new_from_printf ( ++ "%u,%u,%u", ++ pre_data->u.uints[0], ++ pre_data->u.uints[1], ++ pre_data->u.uints[2]); ++ } ++ break; ++ default: ++ g_warning ("Type %c of SyncForwardingData is not supported", ++ pre_data->key); ++ g_slice_free (SyncForwardingData, data); ++ return FALSE; ++ } ++ g_queue_push_tail (context->queue_during_process_key_event, data); ++ return TRUE; ++ } ++ return FALSE; ++} ++ + gboolean + bus_input_context_has_focus (BusInputContext *context) + { +@@ -1893,6 +1974,9 @@ bus_input_context_show_preedit_text (BusInputContext *context, + } + + if (PREEDIT_CONDITION) { ++ SyncForwardingPreData pre_data = { 's', }; ++ if (bus_input_context_make_post_process_key_event (context, &pre_data)) ++ return; + bus_input_context_emit_signal (context, + "ShowPreeditText", + NULL, +@@ -1933,6 +2017,9 @@ bus_input_context_hide_preedit_text (BusInputContext *context, + } + + if (PREEDIT_CONDITION) { ++ SyncForwardingPreData pre_data = { 'h', }; ++ if (bus_input_context_make_post_process_key_event (context, &pre_data)) ++ return; + bus_input_context_emit_signal (context, + "HidePreeditText", + NULL, +@@ -2254,27 +2340,18 @@ _engine_forward_key_event_cb (BusEngineProxy *engine, + guint state, + BusInputContext *context) + { ++ SyncForwardingPreData pre_data = { 'f', }; ++ + g_assert (BUS_IS_ENGINE_PROXY (engine)); + g_assert (BUS_IS_INPUT_CONTEXT (context)); +- + g_assert (context->engine == engine); + g_assert (context->queue_during_process_key_event); + +- if (context->processing_key_event && g_queue_get_length ( +- context->queue_during_process_key_event) <= MAX_SYNC_DATA) { +- SyncForwardingData *data; +- IBusText *text = ibus_text_new_from_printf ("%u,%u,%u", +- keyval, keycode, state); +- if (g_queue_get_length (context->queue_during_process_key_event) +- == MAX_SYNC_DATA) { +- g_warning ("Exceed max number of post process_key_event data"); +- } +- data = g_slice_new (SyncForwardingData); +- data->key = 'f'; +- data->text = text; +- g_queue_push_tail (context->queue_during_process_key_event, data); ++ pre_data.u.uints[0] = keyval; ++ pre_data.u.uints[1] = keycode; ++ pre_data.u.uints[2] = state; ++ if (bus_input_context_make_post_process_key_event (context, &pre_data)) + return; +- } + bus_input_context_emit_signal (context, + "ForwardKeyEvent", + g_variant_new ("(uuu)", keyval, keycode, state), +@@ -2292,26 +2369,16 @@ _engine_delete_surrounding_text_cb (BusEngineProxy *engine, + guint nchars, + BusInputContext *context) + { ++ SyncForwardingPreData pre_data = { 'd', }; ++ + g_assert (BUS_IS_ENGINE_PROXY (engine)); + g_assert (BUS_IS_INPUT_CONTEXT (context)); +- + g_assert (context->engine == engine); + +- if (context->processing_key_event && g_queue_get_length ( +- context->queue_during_process_key_event) <= MAX_SYNC_DATA) { +- SyncForwardingData *data; +- IBusText *text = ibus_text_new_from_printf ("%d,%u", +- offset_from_cursor, nchars); +- if (g_queue_get_length (context->queue_during_process_key_event) +- == MAX_SYNC_DATA) { +- g_warning ("Exceed max number of sync process_key_event data"); +- } +- data = g_slice_new (SyncForwardingData); +- data->key = 'd'; +- data->text = g_object_ref (text); +- g_queue_push_tail (context->queue_during_process_key_event, data); ++ pre_data.u.deleting.offset = offset_from_cursor; ++ pre_data.u.deleting.nchars = nchars; ++ if (bus_input_context_make_post_process_key_event (context, &pre_data)) + return; +- } + bus_input_context_emit_signal (context, + "DeleteSurroundingText", + g_variant_new ("(iu)", offset_from_cursor, nchars), +@@ -2452,25 +2520,14 @@ static void + _engine_require_surrounding_text_cb (BusEngineProxy *engine, + BusInputContext *context) + { ++ SyncForwardingPreData pre_data = { 'r', }; ++ + g_assert (BUS_IS_ENGINE_PROXY (engine)); + g_assert (BUS_IS_INPUT_CONTEXT (context)); +- + g_assert (context->engine == engine); + +- if (context->processing_key_event && g_queue_get_length ( +- context->queue_during_process_key_event) <= MAX_SYNC_DATA) { +- SyncForwardingData *data; +- IBusText *text = ibus_text_new_from_static_string (""); +- if (g_queue_get_length (context->queue_during_process_key_event) +- == MAX_SYNC_DATA) { +- g_warning ("Exceed max number of post process_key_event data"); +- } +- data = g_slice_new (SyncForwardingData); +- data->key = 'r'; +- data->text = text; +- g_queue_push_tail (context->queue_during_process_key_event, data); ++ if (bus_input_context_make_post_process_key_event (context, &pre_data)) + return; +- } + bus_input_context_emit_signal (context, + "RequireSurroundingText", + NULL, +@@ -3178,6 +3235,8 @@ bus_input_context_commit_text_use_extension (BusInputContext *context, + IBusText *text, + gboolean use_extension) + { ++ SyncForwardingPreData pre_data = { 'c', text, }; ++ + g_assert (BUS_IS_INPUT_CONTEXT (context)); + g_assert (context->queue_during_process_key_event); + +@@ -3186,17 +3245,9 @@ bus_input_context_commit_text_use_extension (BusInputContext *context, + + if (use_extension && context->emoji_extension) { + bus_panel_proxy_commit_text_received (context->emoji_extension, text); +- } else if (context->processing_key_event && g_queue_get_length ( +- context->queue_during_process_key_event) <= MAX_SYNC_DATA) { +- SyncForwardingData *data; +- if (g_queue_get_length (context->queue_during_process_key_event) +- == MAX_SYNC_DATA) { +- g_warning ("Exceed max number of sync process_key_event data"); +- } +- data = g_slice_new (SyncForwardingData); +- data->key = 'c'; +- data->text = g_object_ref (text); +- g_queue_push_tail (context->queue_during_process_key_event, data); ++ } else if (bus_input_context_make_post_process_key_event (context, ++ &pre_data)) { ++ return; + } else { + GVariant *variant = ibus_serializable_serialize ( + (IBusSerializable *)text); +@@ -3245,9 +3296,18 @@ bus_input_context_update_preedit_text (BusInputContext *context, + context->preedit_cursor_pos, + context->preedit_visible); + } else if (PREEDIT_CONDITION) { ++ SyncForwardingPreData pre_data = { 'u', context->preedit_text, }; + GVariant *variant = ibus_serializable_serialize ( + (IBusSerializable *)context->preedit_text); +- if (context->client_commit_preedit) { ++ pre_data.u.uints[0] = context->preedit_cursor_pos; ++ pre_data.u.uints[1] = extension_visible ? 1 : 0; ++ pre_data.u.uints[2] = context->preedit_mode; ++ if (context->client_commit_preedit) ++ pre_data.key = 'm'; ++ if (bus_input_context_make_post_process_key_event (context, ++ &pre_data)) { ++ return; ++ } else if (context->client_commit_preedit) { + bus_input_context_emit_signal ( + context, + "UpdatePreeditTextWithMode", +diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c +index c6a030fe..1b62f656 100644 +--- a/src/ibusinputcontext.c ++++ b/src/ibusinputcontext.c +@@ -1403,10 +1403,103 @@ ibus_input_context_set_post_process_key_event (IBusInputContext *context, + g_variant_unref (var_post); + } + ++ ++static void ++ibus_input_context_fwd_text_to_commit (IBusInputContext *context, ++ IBusText *text) ++{ ++ g_signal_emit (context, context_signals[COMMIT_TEXT], 0, text); ++} ++ ++ ++static void ++ibus_input_context_fwd_text_to_forward_key_event (IBusInputContext *context, ++ IBusText *text) ++{ ++ gchar **array = NULL; ++ guint keyval, keycode, state; ++ array = g_strsplit (text->text, ",", -1); ++ keyval = g_ascii_strtoull (array[0], NULL, 10); ++ keycode = g_ascii_strtoull (array[1], NULL, 10); ++ state = g_ascii_strtoull (array[2], NULL, 10); ++ g_strfreev (array); ++ g_signal_emit (context, ++ context_signals[FORWARD_KEY_EVENT], ++ 0, ++ keyval, ++ keycode, ++ state | IBUS_FORWARD_MASK); ++} ++ ++ ++static void ++ibus_input_context_fwd_text_to_require_surrounding (IBusInputContext *context, ++ IBusText *text) ++{ ++ IBusInputContextPrivate *priv; ++ g_assert (IBUS_IS_INPUT_CONTEXT (context)); ++ priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context)); ++ priv->needs_surrounding_text = TRUE; ++} ++ ++ ++static void ++ibus_input_context_fwd_text_to_delete_surrounding (IBusInputContext *context, ++ IBusText *text) ++{ ++ gchar **array = NULL; ++ gint offset_from_cursor; ++ guint nchars; ++ array = g_strsplit (text->text, ",", -1); ++ offset_from_cursor = g_ascii_strtoll (array[0], NULL, 10); ++ nchars = g_ascii_strtoull (array[1], NULL, 10); ++ g_strfreev (array); ++ g_signal_emit (context, ++ context_signals[DELETE_SURROUNDING_TEXT], ++ 0, ++ offset_from_cursor, ++ nchars); ++} ++ ++ ++static void ++ibus_input_context_fwd_text_to_update_preedit (IBusInputContext *context, ++ IBusText *text, ++ IBusText *position, ++ char type) ++{ ++ gchar **array = NULL; ++ guint32 cursor_pos; ++ gboolean visible; ++ guint mode = 0; ++ ++ array = g_strsplit (position->text, ",", -1); ++ cursor_pos = g_ascii_strtoull (array[0], NULL, 10); ++ visible = g_ascii_strtoull (array[1], NULL, 10) ? TRUE : FALSE; ++ if (type == 'u') { ++ g_signal_emit (context, ++ context_signals[UPDATE_PREEDIT_TEXT], ++ 0, ++ text, ++ cursor_pos, ++ visible); ++ } else { ++ mode = g_ascii_strtoull (array[2], NULL, 10); ++ g_signal_emit (context, ++ context_signals[UPDATE_PREEDIT_TEXT_WITH_MODE], ++ 0, ++ text, ++ cursor_pos, ++ visible, ++ mode); ++ } ++ g_strfreev (array); ++} ++ ++ + void + ibus_input_context_post_process_key_event (IBusInputContext *context) + { +- IBusInputContextPrivate *priv; + GVariant *cached_var_post; + gboolean enable = FALSE; + GVariant *result; +@@ -1419,7 +1513,6 @@ ibus_input_context_post_process_key_event (IBusInputContext *context) + + g_assert (IBUS_IS_INPUT_CONTEXT (context)); + +- priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context)); + cached_var_post = + g_dbus_proxy_get_cached_property ((GDBusProxy *)context, + "EffectivePostProcessKeyEvent"); +@@ -1454,7 +1547,7 @@ ibus_input_context_post_process_key_event (IBusInputContext *context) + g_assert (variant); + g_variant_iter_init (&iter, variant); + size = g_variant_iter_n_children (&iter); +- while (size >0 && g_variant_iter_loop (&iter, "(yv)", &type, &vtext)) { ++ while (size > 0 && g_variant_iter_loop (&iter, "(yv)", &type, &vtext)) { + IBusText *text = + (IBusText *)ibus_serializable_deserialize_object (vtext); + if (!IBUS_IS_TEXT (text)) { +@@ -1463,41 +1556,48 @@ ibus_input_context_post_process_key_event (IBusInputContext *context) + } + switch (type) { + case 'c': +- g_signal_emit (context, context_signals[COMMIT_TEXT], 0, text); ++ ibus_input_context_fwd_text_to_commit (context, text); + break; + case 'f': { +- gchar **array = NULL; +- guint keyval, keycode, state; +- array = g_strsplit (text->text, ",", -1); +- keyval = g_ascii_strtoull (array[0], NULL, 10); +- keycode = g_ascii_strtoull (array[1], NULL, 10); +- state = g_ascii_strtoull (array[2], NULL, 10); +- g_strfreev (array); +- g_signal_emit (context, +- context_signals[FORWARD_KEY_EVENT], +- 0, +- keyval, +- keycode, +- state | IBUS_FORWARD_MASK); ++ ibus_input_context_fwd_text_to_forward_key_event (context, text); + break; + } + case 'r': { +- priv->needs_surrounding_text = TRUE; ++ ibus_input_context_fwd_text_to_require_surrounding (context, text); + break; + } + case 'd': { +- gchar **array = NULL; +- gint offset_from_cursor; +- guint nchars; +- array = g_strsplit (text->text, ",", -1); +- offset_from_cursor = g_ascii_strtoll (array[0], NULL, 10); +- nchars = g_ascii_strtoull (array[1], NULL, 10); +- g_strfreev (array); +- g_signal_emit (context, +- context_signals[DELETE_SURROUNDING_TEXT], +- 0, +- offset_from_cursor, +- nchars); ++ ibus_input_context_fwd_text_to_delete_surrounding (context, text); ++ break; ++ } ++ case 'u': ++ case 'm': { ++ IBusText *position; ++ g_clear_pointer (&vtext, g_variant_unref); ++ if (!g_variant_iter_loop (&iter, "(yv)", &type, &vtext)) { ++ g_warning ("%s: %s", G_STRFUNC, ++ "Type 'u' requires next type 'u'"); ++ break; ++ } ++ if (type != 'u' && type != 'm') { ++ g_warning ("%s: %s", G_STRFUNC, ++ "The next of type 'u' should be type 'u'"); ++ break; ++ } ++ position = ++ (IBusText *)ibus_serializable_deserialize_object (vtext); ++ if (!IBUS_IS_TEXT (position)) { ++ g_warning ("%s: %s", G_STRFUNC, "text is not IBusText"); ++ break; ++ } ++ ibus_input_context_fwd_text_to_update_preedit (context, ++ text, ++ position, ++ type); ++ if (g_object_is_floating (position)) { ++ g_object_ref_sink (position); ++ g_object_unref (position); ++ } + break; + } + default: +-- +2.41.0 + +From 1be3e2f79b384a374b2a69a31c88a4f36e1dd868 Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Wed, 15 Nov 2023 17:19:02 +0900 +Subject: [PATCH] client/gtk2: Call strdup() after g_return_if_fail() + +--- + client/gtk2/ibusimcontext.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c +index b5a44da0..cfc08c20 100644 +--- a/client/gtk2/ibusimcontext.c ++++ b/client/gtk2/ibusimcontext.c +@@ -2417,7 +2417,7 @@ _create_input_context_done (IBusBus *bus, + static void + _create_input_context (IBusIMContext *ibusimcontext) + { +- gchar *prgname = g_strdup (g_get_prgname()); ++ gchar *prgname; + gchar *client_name; + IDEBUG ("%s", __FUNCTION__); + +@@ -2425,6 +2425,7 @@ _create_input_context (IBusIMContext *ibusimcontext) + + g_return_if_fail (ibusimcontext->cancellable == NULL); + ++ prgname = g_strdup (g_get_prgname()); + ibusimcontext->cancellable = g_cancellable_new (); + + if (!prgname) +-- +2.41.0 + diff --git a/ibus-1682157-ci.patch b/ibus-1682157-ci.patch deleted file mode 100644 index 87e72ed..0000000 --- a/ibus-1682157-ci.patch +++ /dev/null @@ -1,2639 +0,0 @@ -From c360cbd830943a4bfb0ece9cc07b99a426dc2121 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Mon, 9 Apr 2018 11:57:09 +0900 -Subject: [PATCH] src/tests: Add ibus-compose.env - ---- - src/tests/ibus-compose.env | 3 +++ - 1 file changed, 3 insertions(+) - create mode 100644 src/tests/ibus-compose.env - -diff --git a/src/tests/ibus-compose.env b/src/tests/ibus-compose.env -new file mode 100644 -index 00000000..734ab8fa ---- /dev/null -+++ b/src/tests/ibus-compose.env -@@ -0,0 +1,3 @@ -+LANG=el_GR.UTF-8 -+LANG=fi_FI.UTF-8 -+LANG=pt_BR.UTF-8 --- -2.21.0 - -From b497de5bc6525769e03b65c73fc991d4aa006223 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Wed, 20 Mar 2019 17:44:26 +0900 -Subject: [PATCH] test: Set GTK_IM_MODULE in test-console.sh - ---- - src/tests/Makefile.am | 4 ++-- - 2 files changed, 14 insertions(+), 2 deletions(-) - -diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am -index e337a59b..e2ff5ea7 100644 ---- a/src/tests/Makefile.am -+++ b/src/tests/Makefile.am -@@ -3,7 +3,7 @@ - # ibus - The Input Bus - # - # Copyright (c) 2007-2015 Peng Huang --# Copyright (c) 2015-2018 Takao Fujiwara -+# Copyright (c) 2015-2019 Takao Fujiwara - # Copyright (c) 2007-2018 Red Hat, Inc. - # - # This library is free software; you can redistribute it and/or -@@ -78,7 +78,7 @@ TESTS_ENVIRONMENT = \ - - LOG_COMPILER = $(srcdir)/runtest - --EXTRA_DIST = runtest -+EXTRA_DIST = runtest ibus-compose.env - - ibus_bus_SOURCES = ibus-bus.c - ibus_bus_LDADD = $(prog_ldadd) --- -2.21.0 - -From ac492f31b435b9464d591094d470bc94027168e8 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 28 Jun 2019 21:15:07 +0900 -Subject: [PATCH] src/tests: Fix ibus-compose for IBusComposeTableEx - -Recently IBusComposeTablEx has been integrated and the return value of -ibus_compose_table_new_with_file() is also changed and ibus-compose -needs to be updated. - -Clear IBusComposeTablePrivate in ibus_compose_table_list_add_array() -for the ibus-compose testing. - -Clear compose_buffer in IBusEngineSimple. - -Use g_get_language_names_with_category instead() of g_get_locale_variants(). - -Add ibus-compose.emoji for the tests of long compose sequences and -multiple compose output characters. - -IBUS_COMPOSE_CACHE_DIR variable is added for the temporary caches. ---- - src/ibuscomposetable.c | 15 ++-- - src/tests/Makefile.am | 2 +- - src/tests/ibus-compose.c | 10 +++ - src/tests/ibus-compose.emoji | 11 +++ - src/tests/ibus-compose.env | 1 + - src/tests/runtest | 4 +- - 9 files changed, 174 insertions(+), 47 deletions(-) - create mode 100644 src/tests/ibus-compose.emoji - -diff --git a/src/ibuscomposetable.c b/src/ibuscomposetable.c -index 4ac54e25..5fd37f10 100644 ---- a/src/ibuscomposetable.c -+++ b/src/ibuscomposetable.c -@@ -497,13 +497,18 @@ static gchar * - ibus_compose_hash_get_cache_path (guint32 hash) - { - gchar *basename = NULL; -+ const gchar *cache_dir; - gchar *dir = NULL; - gchar *path = NULL; - - basename = g_strdup_printf ("%08x.cache", hash); - -- dir = g_build_filename (g_get_user_cache_dir (), -- "ibus", "compose", NULL); -+ if ((cache_dir = g_getenv ("IBUS_COMPOSE_CACHE_DIR"))) { -+ dir = g_strdup (cache_dir); -+ } else { -+ dir = g_build_filename (g_get_user_cache_dir (), -+ "ibus", "compose", NULL); -+ } - path = g_build_filename (dir, basename, NULL); - if (g_mkdir_with_parents (dir, 0755) != 0) { - g_warning ("Failed to mkdir %s", dir); -@@ -1068,7 +1073,7 @@ ibus_compose_table_list_add_array (GSList *compose_tables, - for (i = 0; i < length; i++) - ibus_compose_seqs[i] = data[i]; - -- compose_table = g_new (IBusComposeTable, 1); -+ compose_table = g_new0 (IBusComposeTable, 1); - compose_table->data = ibus_compose_seqs; - compose_table->max_seq_len = max_seq_len; - compose_table->n_seqs = n_seqs; -diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am -index e2ff5ea7..a58504a3 100644 ---- a/src/tests/Makefile.am -+++ b/src/tests/Makefile.am -@@ -78,7 +78,7 @@ TESTS_ENVIRONMENT = \ - - LOG_COMPILER = $(srcdir)/runtest - --EXTRA_DIST = runtest ibus-compose.env -+EXTRA_DIST = runtest ibus-compose.emoji ibus-compose.env - - ibus_bus_SOURCES = ibus-bus.c - ibus_bus_LDADD = $(prog_ldadd) -diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c -index e2ff5ea7..a58504a3 100644 ---- a/src/tests/ibus-compose.c -+++ b/src/tests/ibus-compose.c -@@ -7,8 +7,10 @@ - #define NC "\033[0m" - - IBusBus *m_bus; -+gchar *m_compose_file; - IBusComposeTable *m_compose_table; - IBusEngine *m_engine; -+gchar *m_srcdir; - int m_retval; - - static gboolean window_focus_in_event_cb (GtkWidget *entry, -@@ -31,8 +33,11 @@ create_engine_cb (IBusFactory *factory, - engine_path, - ibus_bus_get_connection (m_bus)); - g_free (engine_path); -- langs = g_get_language_names (); -- for (l = langs; *l; l++) { -+ if (m_compose_file) { -+ compose_path = g_build_filename (m_srcdir, m_compose_file, NULL); -+ } else { -+ langs = g_get_language_names (); -+ for (l = langs; *l; l++) { - if (g_str_has_prefix (*l, "en_US")) - break; - if (g_strcmp0 (*l, "C") == 0) -@@ -41,10 +46,11 @@ create_engine_cb (IBusFactory *factory, - *l, - "Compose", - NULL); - if (g_file_test (compose_path, G_FILE_TEST_EXISTS)) - break; - g_free (compose_path); - compose_path = NULL; -+ } - } - if (compose_path != NULL) { - m_compose_table = ibus_compose_table_new_with_file (compose_path); -@@ -248,6 +254,9 @@ main (int argc, char *argv[]) - ibus_init (); - gtk_init (&argc, &argv); - -+ m_srcdir = argc > 1 ? g_strdup (argv[1]) : g_strdup ("."); -+ m_compose_file = g_strdup (g_getenv ("COMPOSE_FILE")); -+ - if (!register_ibus_engine ()) - return -1; - -diff --git a/src/tests/ibus-compose.emoji b/src/tests/ibus-compose.emoji -new file mode 100644 -index 00000000..7fbf82cf ---- /dev/null -+++ b/src/tests/ibus-compose.emoji -@@ -0,0 +1,2 @@ -+ : "♌" U264C # LEO -+ : "∫" -diff --git a/src/tests/ibus-compose.env b/src/tests/ibus-compose.env -index 734ab8fa..a9e289e4 100644 ---- a/src/tests/ibus-compose.env -+++ b/src/tests/ibus-compose.env -@@ -1,3 +1,4 @@ - LANG=el_GR.UTF-8 - LANG=fi_FI.UTF-8 - LANG=pt_BR.UTF-8 -+LANG=en_US.UTF-8 COMPOSE_FILE=ibus-compose.emoji -diff --git a/src/tests/runtest b/src/tests/runtest -index 4e980c71..35ccc5a0 100755 ---- a/src/tests/runtest -+++ b/src/tests/runtest -@@ -184,7 +184,9 @@ run_test_case() - export GTK_IM_MODULE=ibus - fi - -- "../$tst" ${1+"$@"} -+ export IBUS_COMPOSE_CACHE_DIR=$PWD -+ -+ "../$tst" ../$top_srcdir/src/tests ${1+"$@"} - - retval=`expr $retval \| $?` - --- -2.21.0 - -From 76dec798d5cf6cdaa96c3373f9c0e1cd13eb31f5 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 28 Jun 2019 21:28:32 +0900 -Subject: [PATCH] src/tests: Use GTest for ibus-compose - ---- - src/tests/ibus-compose.c | 45 ++++++++++++++++++++++++++++------------ - 1 file changed, 32 insertions(+), 13 deletions(-) - -diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c -index e1911b32..09c687c2 100644 ---- a/src/tests/ibus-compose.c -+++ b/src/tests/ibus-compose.c -@@ -11,7 +11,6 @@ gchar *m_compose_file; - IBusComposeTable *m_compose_table; - IBusEngine *m_engine; - gchar *m_srcdir; --int m_retval; - - static gboolean window_focus_in_event_cb (GtkWidget *entry, - GdkEventFocus *event, -@@ -111,8 +110,7 @@ register_ibus_engine () - static gboolean - finit (gpointer data) - { -- m_retval = -1; -- g_warning ("time out"); -+ g_test_incomplete ("time out"); - gtk_main_quit (); - return FALSE; - } -@@ -127,7 +125,9 @@ set_engine_cb (GObject *object, GAsyncRe - int index_stride; - - if (!ibus_bus_set_global_engine_async_finish (bus, res, &error)) { -- g_warning ("set engine failed: %s", error->message); -+ gchar *msg = g_strdup_printf ("set engine failed: %s", error->message); -+ g_test_incomplete (msg); -+ g_free (msg); - g_error_free (error); - return; - } -@@ -210,7 +210,7 @@ window_inserted_text_cb (GtkEntryBuffer - test = GREEN "PASS" NC; - } else { - test = RED "FAIL" NC; -- m_retval = -1; -+ g_test_fail (); - } - g_print ("%05d/%05d %s expected: %04X typed: %04X\n", - seq, -@@ -249,20 +249,39 @@ create_window () - gtk_widget_show_all (window); - } - -+static void -+test_compose (void) -+{ -+ if (!register_ibus_engine ()) { -+ g_test_fail (); -+ return; -+ } -+ -+ create_window (); -+ gtk_main (); -+ -+} -+ - int - main (int argc, char *argv[]) - { -+ const gchar *test_name; -+ gchar *test_path; -+ - ibus_init (); -+ g_test_init (&argc, &argv, NULL); - gtk_init (&argc, &argv); - - m_srcdir = argc > 1 ? g_strdup (argv[1]) : g_strdup ("."); - m_compose_file = g_strdup (g_getenv ("COMPOSE_FILE")); -+#if GLIB_CHECK_VERSION (2, 58, 0) -+ test_name = g_get_language_names_with_category ("LC_CTYPE")[0]; -+#else -+ test_name = g_getenv ("LANG"); -+#endif -+ test_path = g_build_filename ("/ibus-compose", test_name, NULL); -+ g_test_add_func (test_path, test_compose); -+ g_free (test_path); - -- if (!register_ibus_engine ()) -- return -1; -- -- create_window (); -- gtk_main (); -- -- return m_retval; -+ return g_test_run (); - } --- -2.21.0 - -From af00f4156b5c79c526eab18c49da80affd41ebee Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 12 Jul 2019 21:12:38 +0900 -Subject: [PATCH] src/tests: Install IBus tests into gnome-desktop-testing - ---- - configure.ac | 13 +++++++++++ - src/tests/Makefile.am | 39 ++++++++++++++++++++++++++++++- - src/tests/ibus-compose-locales.in | 23 ++++++++++++++++++ - src/tests/ibus-compose.c | 10 ++++++-- - src/tests/meta.test.in | 4 ++++ - src/tests/runtest | 4 ++-- - 6 files changed, 88 insertions(+), 5 deletions(-) - create mode 100755 src/tests/ibus-compose-locales.in - create mode 100644 src/tests/meta.test.in - -diff --git a/configure.ac b/configure.ac -index b5a87b56..f1df3ac1 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -595,6 +595,18 @@ PKG_CHECK_MODULES(XTEST, - ) - AM_CONDITIONAL([ENABLE_XTEST], [test x"$enable_xtest" = x"yes"]) - -+# --enable-install-tests -+AC_ARG_ENABLE(install-tests, -+ AS_HELP_STRING([--enable-install-tests], -+ [Enable to install tests]), -+ [enable_install_tests=$enableval], -+ [enable_install_tests=no] -+) -+AM_CONDITIONAL([ENABLE_INSTALL_TESTS], [test x"$enable_install_tests" = x"yes"]) -+if test x"$enable_install_tests" = x"no"; then -+ enable_install_tests="no (disabled, use --enable-install-tests to enable)" -+fi -+ - - # --disable-emoji-dict option. - AC_ARG_ENABLE(emoji-dict, -@@ -773,5 +785,6 @@ Build options: - Enable Unicode dict $enable_unicode_dict - UCD directory $UCD_DIR - Run test cases $enable_tests -+ Install tests $enable_install_tests - ]) - -diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am -index a58504a3..ff31111b 100644 ---- a/src/tests/Makefile.am -+++ b/src/tests/Makefile.am -@@ -78,7 +78,44 @@ TESTS_ENVIRONMENT = \ - - LOG_COMPILER = $(srcdir)/runtest - --EXTRA_DIST = runtest ibus-compose.emoji ibus-compose.env -+if ENABLE_INSTALL_TESTS -+test_metas_in = meta.test.in -+test_execs = $(TESTS:ibus-compose=ibus-compose-locales) -+test_metas = $(addsuffix .test, $(test_execs)) -+test_sources_DATA = \ -+ $(test_metas) \ -+ ibus-compose.emoji \ -+ ibus-compose.env \ -+ $(NULL) -+test_sourcesdir = $(datadir)/installed-tests/ibus -+ -+test_execs_PROGRAMS = $(TESTS) -+if ENABLE_GTK3 -+test_execs_SCRIPTS = ibus-compose-locales -+endif -+test_execsdir = $(libexecdir)/installed-tests/ibus -+endif -+ -+$(test_metas): $(test_metas_in) $(test_programs) -+ f=`echo $@ | sed -e 's/\.test//'`; \ -+ TEST_EXEC=$(test_execsdir)/$$f; \ -+ sed -e "s|@TEST_EXEC[@]|$$TEST_EXEC|g" $(test_metas_in) > $@.tmp; \ -+ mv $@.tmp $@; \ -+ $(NULL) -+ -+ibus-compose-locales: ibus-compose-locales.in -+ SRCDIR=$(test_sourcesdir); \ -+ sed -e "s|@SRCDIR[@]|$$SRCDIR|g" $< > $@.tmp; \ -+ mv $@.tmp $@; \ -+ $(NULL) -+ -+EXTRA_DIST = \ -+ $(test_metas_in) \ -+ runtest \ -+ ibus-compose.emoji \ -+ ibus-compose.env \ -+ ibus-compose-locales.in \ -+ $(NULL) - - ibus_bus_SOURCES = ibus-bus.c - ibus_bus_LDADD = $(prog_ldadd) -diff --git a/src/tests/ibus-compose-locales.in b/src/tests/ibus-compose-locales.in -new file mode 100755 -index 00000000..8d2384d1 ---- /dev/null -+++ b/src/tests/ibus-compose-locales.in -@@ -0,0 +1,23 @@ -+#!/bin/sh -+ -+SRCDIR=@SRCDIR@ -+BUILDDIR=`dirname $0` -+ -+ -+export IBUS_COMPOSE_CACHE_DIR=$PWD -+ -+for var in `cat $SRCDIR/ibus-compose.env` -+do -+ IS_COMMENT=`echo "$var" | grep "^#"` -+ if [ "x$IS_COMMENT" != x ] ; then -+ continue -+ fi -+ env $var $BUILDDIR/ibus-compose $SRCDIR $@ -+ -+ CACHE_FILES=`ls *.cache` -+ if [ x"$CACHE_FILES" != x ] ; then -+ echo "Clean $CACHE_FILES" -+ rm $CACHE_FILES -+ fi -+done -+ -diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c -index 09c687c2..c8d3c126 100644 ---- a/src/tests/ibus-compose.c -+++ b/src/tests/ibus-compose.c -@@ -351,6 +347,14 @@ main (int argc, char *argv[]) - - ibus_init (); - g_test_init (&argc, &argv, NULL); -+ /* FIXME: -+ * IBusIMContext opens GtkIMContextSimple as the slave and -+ * GtkIMContextSimple opens the compose table on el_GR.UTF-8, and the -+ * multiple outputs in el_GR's compose causes a warning in gtkcomposetable -+ * and the warning always causes a fatal in GTest: -+ " "GTK+ supports to output one char only: " -+ */ -+ g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL); - gtk_init (&argc, &argv); - - m_srcdir = argc > 1 ? g_strdup (argv[1]) : g_strdup ("."); -diff --git a/src/tests/meta.test.in b/src/tests/meta.test.in -new file mode 100644 -index 00000000..ae2b2991 ---- /dev/null -+++ b/src/tests/meta.test.in -@@ -0,0 +1,4 @@ -+[Test] -+Type=session -+Exec=@TEST_EXEC@ --tap -+Output=TAP -diff --git a/src/tests/runtest b/src/tests/runtest -index 35ccc5a0..1fcc9283 100755 ---- a/src/tests/runtest -+++ b/src/tests/runtest -@@ -200,7 +200,7 @@ if test -f $envfile ; then - ENVS="`cat $envfile`" - fi; - if test x"$ENVS" = x ; then -- run_test_case -+ run_test_case $@ - else - LANG_backup=$LANG - i=1 -@@ -212,7 +212,7 @@ else - export $e - echo "Run `func_basename $tst` on $e" - echo "=======================" -- run_test_case -+ run_test_case $@ - echo "" - i=`expr $i + 1` - done --- -2.21.0 - -From 2a4f9518d42b618d8111fa5f9f885757524758a0 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 12 Jul 2019 21:12:40 +0900 -Subject: [PATCH] src/tests: Rename test-console.sh to - ibus-desktop-testing-runner - ---- - src/tests/Makefile.am | 9 +++++++++ - .../tests/ibus-desktop-testing-runner.in | 0 - 2 files changed, 9 insertions(+) - rename test/test-console.sh => src/tests/ibus-desktop-testing-runner.in (100%) - -diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am -index ff31111b..b9aad29a 100644 ---- a/src/tests/Makefile.am -+++ b/src/tests/Makefile.am -@@ -79,6 +79,7 @@ TESTS_ENVIRONMENT = \ - LOG_COMPILER = $(srcdir)/runtest - - if ENABLE_INSTALL_TESTS -+bin_SCRIPTS = ibus-desktop-testing-runner - test_metas_in = meta.test.in - test_execs = $(TESTS:ibus-compose=ibus-compose-locales) - test_metas = $(addsuffix .test, $(test_execs)) -@@ -109,12 +110,20 @@ ibus-compose-locales: ibus-compose-locales.in - mv $@.tmp $@; \ - $(NULL) - -+ ibus-desktop-testing-runner.in \ -+ibus-desktop-testing-runner: ibus-desktop-testing-runner.in -+ SRCDIR=$(test_sourcesdir); \ -+ sed -e "s|@SRCDIR[@]|$$SRCDIR|g" $< > $@.tmp; \ -+ mv $@.tmp $@; \ -+ $(NULL) -+ - EXTRA_DIST = \ - $(test_metas_in) \ - runtest \ - ibus-compose.emoji \ - ibus-compose.env \ - ibus-compose-locales.in \ -+ ibus-desktop-testing-runner.in \ - $(NULL) - - ibus_bus_SOURCES = ibus-bus.c -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -new file mode 100755 -index 00000000..7fbf82cf ---- /dev/null -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -0,0 +1,255 @@ -+#!/bin/sh -+# -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- -+# vim:set noet ts=4: -+# -+# ibus-anthy - The Anthy engine for IBus -+# -+# Copyright (c) 2018-2019 Takao Fujiwara -+# Copyright (c) 2018 Red Hat, Inc. -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License along -+# with this program; if not, write to the Free Software Foundation, Inc., -+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ -+# This test runs /usr/bin/ibus-daemon after install ibus -+# -+# # init 3 -+# Login as root -+# # /root/ibus/tests/test-console.sh --tests ibus-compose \ -+# --builddir /root/ibus/src/tests --srcdir /root/ibus/src/tests -+ -+PROGNAME=`basename $0` -+VERSION=0.1 -+DISPLAY=:99.0 -+BUILDDIR="." -+SRCDIR="." -+TEST_LOG=test-suite.log -+HAVE_GRAPHICS=1 -+DESKTOP_COMMAND="gnome-session" -+PID_XORG=0 -+PID_GNOME_SESSION=0 -+TESTS="" -+GREEN='\033[0;32m' -+RED='\033[0;31m' -+NC='\033[0m' -+ -+usage() -+{ -+ echo -e \ -+"This test runs /usr/bin/ibus-daemon after install ibus\n" \ -+"$PROGNAME [OPTIONS…]\n" \ -+"\n" \ -+"OPTIONS:\n" \ -+"-h, --help This help\n" \ -+"-v, --version Show version\n" \ -+"-b, --builddir=BUILDDIR Set the BUILDDIR\n" \ -+"-s, --srcdir=SOURCEDIR Set the SOURCEDIR\n" \ -+"-c, --no-graphics Use Xvfb instead of Xorg\n" \ -+"-d, --desktop=DESKTOP Run DESTKTOP. The default is gnome-session\n" \ -+"-t, --tests=\"TESTS...\" Run TESTS programs which is separated by space\n" \ -+"" -+} -+ -+parse_args() -+{ -+ # This is GNU getopt. "sudo port getopt" in BSD? -+ ARGS=`getopt -o hvb:s:cd:t: --long help,version,builddir:,srcdir:,no-graphics,desktop:,tests:\ -+ -- "$@"`; -+ eval set -- "$ARGS" -+ while [ 1 ] ; do -+ case "$1" in -+ -h | --help ) usage; exit 0;; -+ -v | --version ) echo -e "$VERSION"; exit 0;; -+ -b | --builddir ) BUILDDIR="$2"; shift 2;; -+ -s | --srcdir ) SRCDIR="$2"; shift 2;; -+ -c | --no-graphics ) HAVE_GRAPHICS=0; shift;; -+ -d | --desktop ) DESKTOP_COMMAND="$2"; shift 2;; -+ -t | --tests ) TESTS="$2"; shift 2;; -+ -- ) shift; break;; -+ * ) usage; exit 1;; -+ esac -+ done -+} -+ -+init_desktop() -+{ -+ if test x$FORCE_TEST != x ; then -+ RUN_ARGS="$RUN_ARGS --force" -+ fi -+ -+ if test ! -f $HOME/.config/gnome-initial-setup-done ; then -+ if test ! -f /var/lib/AccountsService/users/$USER ; then -+ mkdir -p /var/lib/AccountsService/users -+ cat >> /var/lib/AccountsService/users/$USER << _EOF -+[User] -+Language=ja_JP.UTF-8 -+XSession=gnome -+SystemAccount=false -+_EOF -+ fi -+ mkdir -p $HOME/.config -+ touch $HOME/.config/gnome-initial-setup-done -+ fi -+ -+ # Prevent from launching a XDG dialog -+ XDG_LOCALE_FILE="$HOME/.config/user-dirs.locale" -+ if test -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 -+} -+ -+run_dbus_daemon() -+{ -+ a=`ps -ef | grep dbus-daemon | grep "\-\-system" | grep -v session | grep -v grep` -+ if test x"$a" = x ; then -+ eval `dbus-launch --sh-syntax` -+ fi -+ SUSER=`echo "$USER" | cut -c 1-7` -+ a=`ps -ef | grep dbus-daemon | grep "$SUSER" | grep -v gdm | grep session | grep -v grep` -+ if test x"$a" = x ; then -+ systemctl --user start dbus -+ export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$UID/bus -+ fi -+ systemctl --user status dbus | col -b -+ ps -ef | grep dbus-daemon | grep "$SUSER" | grep -v gdm | egrep 'session|system' | grep -v grep -+ systemctl --user show-environment | col -b -+} -+ -+run_desktop() -+{ -+ if test $HAVE_GRAPHICS -eq 1 ; then -+ /usr/libexec/Xorg.wrap -noreset +extension GLX +extension RANDR +extension RENDER -logfile ./xorg.log -config ./xorg.conf -configdir . $DISPLAY & -+ else -+ /usr/bin/Xvfb $DISPLAY -noreset +extension GLX +extension RANDR +extension RENDER -screen 0 1280x1024x24 & -+ fi -+ PID_XORG=$! -+ sleep 1 -+ export DISPLAY=$DISPLAY -+ $DESKTOP_COMMAND & -+ PID_GNOME_SESSION=$! -+ sleep 30 -+ if test "$DESKTOP_COMMAND" != "gnome-session" ; then -+ ibus-daemon --daemonize --verbose -+ sleep 1 -+ fi -+} -+ -+count_case_result() -+{ -+ retval=$1 -+ pass=$2 -+ fail=$3 -+ -+ if test $retval -eq 0 ; then -+ pass=`expr $pass + 1` -+ else -+ fail=`expr $fail + 1` -+ fi -+ echo $pass $fail -+} -+ -+echo_case_result() -+{ -+ retval=$1 -+ tst=$2 -+ log=$3 -+ subtst=${4:-''} -+ -+ if test $retval -eq 0 ; then -+ echo -e "${GREEN}PASS${NC}: $tst $subtst" -+ else -+ echo -e "${RED}FAIL${NC}: $tst $subtst" -+ echo "FAIL: $tst $subtst" >> $TEST_LOG -+ echo "======================" >> $TEST_LOG -+ echo "" >> $TEST_LOG -+ cat "$log" >> $TEST_LOG -+ echo "" >> $TEST_LOG -+ fi -+} -+ -+run_test_suite() -+{ -+ cd `dirname $0` -+ pass=0 -+ fail=0 -+ -+ export GTK_IM_MODULE=ibus -+ export IBUS_COMPOSE_CACHE_DIR=$PWD -+ if test -f $TEST_LOG ; then -+ rm $TEST_LOG -+ fi -+ for tst in $TESTS; do -+ ENVS= -+ if test -f $SRCDIR/${tst}.env ; then -+ ENVS="`cat $SRCDIR/${tst}.env`" -+ fi -+ if test x"$ENVS" = x ; then -+ $BUILDDIR/$tst $SRCDIR >&${tst}.log -+ retval=$? -+ read pass fail << EOF -+ `count_case_result $retval $pass $fail` -+EOF -+ echo_case_result $retval $tst ${tst}.log -+ else -+ LANG_backup=$LANG -+ i=1 -+ for e in $ENVS; do -+ first=`echo "$e" | cut -c1-1` -+ if test x"$first" = x"#" ; then -+ continue -+ fi -+ export $e -+ $BUILDDIR/$tst $SRCDIR >&${tst}.${i}.log -+ retval=$? -+ read pass fail << EOF -+ `count_case_result $retval $pass $fail` -+EOF -+ echo_case_result $retval $tst ${tst}.${i}.log $e -+ i=`expr $i + 1` -+ done -+ export LANG=$LANG_backup -+ fi -+ done -+ echo "" -+ echo -e "# ${GREEN}PASS${NC}: $pass" -+ echo -e "# ${RED}FAIL${NC}: $fail" -+ if test -f ${TEST_LOG} ; then -+ echo "" -+ echo -e "${RED}See ${TEST_LOG}$NC" -+ fi -+} -+ -+finit() -+{ -+ if test "$DESKTOP_COMMAND" != "gnome-session" ; then -+ ibus exit -+ fi -+ kill $PID_GNOME_SESSION $PID_XORG -+} -+ -+main() -+{ -+ parse_args $@ -+ init_desktop -+ run_dbus_daemon -+ run_desktop -+ run_test_suite -+ finit -+} -+ -+main $@ --- -2.21.0 - -From fa081ac8ea37d2feb7c7f395ad66e7381b4cb65b Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 12 Jul 2019 21:20:32 +0900 -Subject: [PATCH] src/tests: Use gnome-desktop-testing-runner - ---- - src/tests/Makefile.am | 4 +- - src/tests/ibus-desktop-testing-runner.in | 154 ++++++++++++++++++----- - 2 files changed, 123 insertions(+), 35 deletions(-) - -diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am -index b9aad29a..913e42fb 100644 ---- a/src/tests/Makefile.am -+++ b/src/tests/Makefile.am -@@ -105,8 +105,8 @@ $(test_metas): $(test_metas_in) $(test_programs) - $(NULL) - - ibus-compose-locales: ibus-compose-locales.in -- SRCDIR=$(test_sourcesdir); \ -- sed -e "s|@SRCDIR[@]|$$SRCDIR|g" $< > $@.tmp; \ -+ INSTALLEDDIR=$(datadir)/installed-tests; \ -+ sed -e "s|@INSTALLEDDIR[@]|$$INSTALLEDDIR|g" $< > $@.tmp; \ - mv $@.tmp $@; \ - $(NULL) - -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index 9e689634..a90c1378 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -2,7 +2,7 @@ - # -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- - # vim:set noet ts=4: - # --# ibus-anthy - The Anthy engine for IBus -+# ibus - The Input Bus - # - # Copyright (c) 2018-2019 Takao Fujiwara - # Copyright (c) 2018 Red Hat, Inc. -@@ -33,16 +33,32 @@ VERSION=0.1 - DISPLAY=:99.0 - BUILDDIR="." - SRCDIR="." --TEST_LOG=test-suite.log -+TEST_LOG="test-suite.log" -+RESULT_LOG="" - HAVE_GRAPHICS=1 - DESKTOP_COMMAND="gnome-session" - PID_XORG=0 - PID_GNOME_SESSION=0 -+TESTING_RUNNER="default" - TESTS="" - 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 -+} -+ - usage() - { - echo -e \ -@@ -57,13 +73,19 @@ usage() - "-c, --no-graphics Use Xvfb instead of Xorg\n" \ - "-d, --desktop=DESKTOP Run DESTKTOP. The default is gnome-session\n" \ - "-t, --tests=\"TESTS...\" Run TESTS programs which is separated by space\n" \ -+"-r, --runner=RUNNER Run TESTS programs with a test RUNNER.\n" \ -+" RUNNDER = gnome or default.\n" \ -+" default is an embedded runner.\n" \ -+"-o, --output=OUTPUT_FILE OUtput the log to OUTPUT_FILE\n" \ -+"-O, --result=RESULT_FILE OUtput the result to RESULT_FILE\n" \ - "" - } - - parse_args() - { - # This is GNU getopt. "sudo port getopt" in BSD? -- ARGS=`getopt -o hvb:s:cd:t: --long help,version,builddir:,srcdir:,no-graphics,desktop:,tests:\ -+ ARGS=`getopt -o hvb:s:cd:t:r:o:O: --long \ -+ help,version,builddir:,srcdir:,no-graphics,desktop:,tests:,runner:,output:,result:\ - -- "$@"`; - eval set -- "$ARGS" - while [ 1 ] ; do -@@ -75,6 +97,9 @@ parse_args() - -c | --no-graphics ) HAVE_GRAPHICS=0; shift;; - -d | --desktop ) DESKTOP_COMMAND="$2"; shift 2;; - -t | --tests ) TESTS="$2"; shift 2;; -+ -r | --runner ) TESTING_RUNNER="$2"; shift 2;; -+ -o | --output ) TEST_LOG="$2"; shift 2;; -+ -O | --result ) RESULT_LOG="$2"; shift 2;; - -- ) shift; break;; - * ) usage; exit 1;; - esac -@@ -83,18 +108,31 @@ parse_args() - - init_desktop() - { -+ if [ "$RESULT_LOG" != "" ] ; then -+ rm $RESULT_LOG -+ 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" -+ abrt -+ else -+ rm $TEST_LOG -+ fi - if test x$FORCE_TEST != x ; then - RUN_ARGS="$RUN_ARGS --force" - fi - - if test ! -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=false -+SystemAccount=$IS_SYSTEM_ACCOUNT - _EOF - fi - mkdir -p $HOME/.config -@@ -167,71 +205,120 @@ echo_case_result() - { - retval=$1 - tst=$2 -- log=$3 -- subtst=${4:-''} -+ subtst=${3:-''} - - if test $retval -eq 0 ; then -- echo -e "${GREEN}PASS${NC}: $tst $subtst" -+ print_log -e "${GREEN}PASS${NC}: $tst $subtst" - else -- echo -e "${RED}FAIL${NC}: $tst $subtst" -- echo "FAIL: $tst $subtst" >> $TEST_LOG -- echo "======================" >> $TEST_LOG -- echo "" >> $TEST_LOG -- cat "$log" >> $TEST_LOG -- echo "" >> $TEST_LOG -+ print_log -e "${RED}FAIL${NC}: $tst $subtst" -+ print_log "======================" -+ print_log "" - fi - } - --run_test_suite() -+run_direct_test_cases() - { -- cd `dirname $0` - pass=0 - fail=0 -- -- export GTK_IM_MODULE=ibus -- export IBUS_COMPOSE_CACHE_DIR=$PWD -- if test -f $TEST_LOG ; then -- rm $TEST_LOG -- fi - for tst in $TESTS; do - ENVS= - if test -f $SRCDIR/${tst}.env ; then - ENVS="`cat $SRCDIR/${tst}.env`" - fi - if test x"$ENVS" = x ; then -- $BUILDDIR/$tst $SRCDIR >&${tst}.log -+ $BUILDDIR/$tst $SRCDIR 2>>$TEST_LOG 1>>$TEST_LOG - retval=$? - read pass fail << EOF - `count_case_result $retval $pass $fail` - EOF -- echo_case_result $retval $tst ${tst}.log -+ echo_case_result $retval $tst -+ CACHE_FILES=`ls *.cache` -+ if [ x"$CACHE_FILES" != x ] ; then -+ print_log "Clean $CACHE_FILES" -+ rm $CACHE_FILES -+ fi - else - LANG_backup=$LANG - i=1 - for e in $ENVS; do -- first=`echo "$e" | cut -c1-1` -+ first=`echo "$e" | grep '^#'` - if test x"$first" = x"#" ; then - continue - fi - export $e -- $BUILDDIR/$tst $SRCDIR >&${tst}.${i}.log -+ $BUILDDIR/$tst $SRCDIR 2>>$TEST_LOG 1>>$TEST_LOG - retval=$? - read pass fail << EOF - `count_case_result $retval $pass $fail` - EOF -- echo_case_result $retval $tst ${tst}.${i}.log $e -+ echo_case_result $retval $tst $e -+ CACHE_FILES=`ls *.cache` -+ if [ x"$CACHE_FILES" != x ] ; then -+ print_log "Clean $CACHE_FILES" -+ rm $CACHE_FILES -+ fi - i=`expr $i + 1` - done - export LANG=$LANG_backup - 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 $tst 2>>$TEST_LOG 1>>$TEST_LOG -+ retval=$? -+ read pass fail << EOF -+ `count_case_result $retval $pass $fail` -+EOF -+ done -+ 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 "" -- echo -e "# ${GREEN}PASS${NC}: $pass" -- echo -e "# ${RED}FAIL${NC}: $fail" -- if test -f ${TEST_LOG} ; then -- echo "" -- echo -e "${RED}See ${TEST_LOG}$NC" -+ 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 "" -+ echo "See ${TEST_LOG}" - } - - finit() -@@ -240,14 +327,15 @@ finit() - ibus exit - fi - kill $PID_GNOME_SESSION $PID_XORG -+ echo "Finished $PROGNAME testing" - } - - main() - { - parse_args $@ - init_desktop -- run_dbus_daemon -- run_desktop -+ run_dbus_daemon 2>>$TEST_LOG 1>>$TEST_LOG -+ run_desktop 2>>$TEST_LOG 1>>$TEST_LOG - run_test_suite - finit - } --- -2.21.0 - -From 85b647a1c57c206779eb0b4b15a734c1b1f29c10 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Wed, 24 Jul 2019 17:27:37 +0900 -Subject: [PATCH] src/tests: Fix IBus test cases for gnome-desktop-testing - -- dconf/config.c: Replaced dconf_client_write_fast() with - dconf_client_write_sync() because - dconf_client_write_fast() does not syn the data when - ibus_config_get_values() is called immediately after - ibus_config_set_value() is called. - -- ibus-compose-locales.in returns the return value of ibus-compose - -- ibus-compose: Set $NO_AT_BRIDGE to suppress a AT_SPI warning - and call g_log_set_always_fatal() because GtkIMContextSimple - does not support multiple compose outputs yet and the API can - suppress a warning. - -- ibus-config: Delete async watch testings which causes several errors - with gnome-shell testing and the testing is now deprecated and - GSettings is recommended. - -- ibus-desktop-testing-runner.in: Support --output=log:stdout to - cat the log to stdout and Use dbus-launch --exit-with-session instead of - --sh-syntax and count PASS of test cases instead of PASS of - gnome-desktop-testing and always run ibus exit and kill - gnome-shell-calendar-server - -- ibus-engine-switch.c: Set xkb:jp::jpn if gnome-shell sets xkb:us::eng - -- ibus-inputcontext.c: Use ibus_bus_get_global_engine() instead of - ibus_bus_list_active_engines() since ibus_bus_list_active_engines() - does not work with gnome-shell and the API is now deprecated. - -- ibus-keypress.c: Set $NO_AT_BRIDGE to suppress a AT_SPI warning ---- - conf/dconf/config.c | 14 +- - src/tests/Makefile.am | 19 +- - src/tests/ibus-compose-locales.in | 4 +- - src/tests/ibus-compose.c | 10 +- - src/tests/ibus-config.c | 283 ----------------------- - src/tests/ibus-desktop-testing-runner.in | 77 +++--- - src/tests/ibus-engine-switch.c | 34 ++- - src/tests/ibus-inputcontext.c | 29 +-- - src/tests/ibus-keypress.c | 4 + - 9 files changed, 126 insertions(+), 348 deletions(-) - -diff --git a/conf/dconf/config.c b/conf/dconf/config.c -index 500ea1d8..30ac137d 100644 ---- a/conf/dconf/config.c -+++ b/conf/dconf/config.c -@@ -335,7 +335,19 @@ ibus_config_dconf_set_value (IBusConfigService *config, - } - - #ifdef DCONF_0_13_4 -- retval = dconf_client_write_fast (client, gkey, value, error); -+ /* Use dconf_client_write_sync() instead of dconf_client_write_fast() -+ * because dconf_client_write_fast() does not sync the data when -+ * ibus_config_get_values() is called immediately after -+ * ibus_config_set_value() is called. -+ * We won't add a new API for the sync only since IBusConfig is -+ * now deprecated and GSettings is recommended. -+ */ -+ retval = dconf_client_write_sync (client, -+ gkey, -+ value, -+ NULL, -+ NULL, -+ error); - #else - retval = dconf_client_write (client, - gkey, -diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am -index 913e42fb..2e75932c 100644 ---- a/src/tests/Makefile.am -+++ b/src/tests/Makefile.am -@@ -55,6 +55,8 @@ TESTS = \ - ibus-util \ - $(NULL) - -+CLEANFILES = -+ - if ENABLE_ENGINE - TESTS += ibus-engine-switch - endif -@@ -90,9 +92,17 @@ test_sources_DATA = \ - $(NULL) - test_sourcesdir = $(datadir)/installed-tests/ibus - -+CLEANFILES += \ -+ $(test_metas) \ -+ ibus-desktop-testing-runner \ -+ $(NULL) -+ - test_execs_PROGRAMS = $(TESTS) - if ENABLE_GTK3 - test_execs_SCRIPTS = ibus-compose-locales -+CLEANFILES += \ -+ ibus-compose-locales \ -+ $(NULL) - endif - test_execsdir = $(libexecdir)/installed-tests/ibus - endif -@@ -105,15 +115,14 @@ $(test_metas): $(test_metas_in) $(test_programs) - $(NULL) - - ibus-compose-locales: ibus-compose-locales.in -- INSTALLEDDIR=$(datadir)/installed-tests; \ -- sed -e "s|@INSTALLEDDIR[@]|$$INSTALLEDDIR|g" $< > $@.tmp; \ -+ SRCDIR=$(test_sourcesdir); \ -+ sed -e "s|@SRCDIR[@]|$$SRCDIR|g" $< > $@.tmp; \ - mv $@.tmp $@; \ - $(NULL) - -- ibus-desktop-testing-runner.in \ - ibus-desktop-testing-runner: ibus-desktop-testing-runner.in -- SRCDIR=$(test_sourcesdir); \ -- sed -e "s|@SRCDIR[@]|$$SRCDIR|g" $< > $@.tmp; \ -+ INSTALLEDDIR=$(datadir)/installed-tests; \ -+ sed -e "s|@INSTALLEDDIR[@]|$$INSTALLEDDIR|g" $< > $@.tmp; \ - mv $@.tmp $@; \ - $(NULL) - -diff --git a/src/tests/ibus-compose-locales.in b/src/tests/ibus-compose-locales.in -index 8d2384d1..fad02965 100755 ---- a/src/tests/ibus-compose-locales.in -+++ b/src/tests/ibus-compose-locales.in -@@ -6,6 +6,7 @@ BUILDDIR=`dirname $0` - - export IBUS_COMPOSE_CACHE_DIR=$PWD - -+retval=0 - for var in `cat $SRCDIR/ibus-compose.env` - do - IS_COMMENT=`echo "$var" | grep "^#"` -@@ -13,6 +14,7 @@ do - continue - fi - env $var $BUILDDIR/ibus-compose $SRCDIR $@ -+ retval=`expr $retval + $?` - - CACHE_FILES=`ls *.cache` - if [ x"$CACHE_FILES" != x ] ; then -@@ -20,4 +22,4 @@ do - rm $CACHE_FILES - fi - done -- -+exit $retval -diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c -index c8d3c126..db359477 100644 ---- a/src/tests/ibus-compose.c -+++ b/src/tests/ibus-compose.c -@@ -344,20 +344,26 @@ test_compose (void) - int - main (int argc, char *argv[]) - { -+ GLogLevelFlags flags; - const gchar *test_name; - gchar *test_path; - - ibus_init (); -+ /* Avoid a warning of "AT-SPI: Could not obtain desktop path or name" -+ * with gtk_main(). -+ */ -+ g_setenv ("NO_AT_BRIDGE", "1", TRUE); - g_test_init (&argc, &argv, NULL); - /* FIXME: - * IBusIMContext opens GtkIMContextSimple as the slave and - * GtkIMContextSimple opens the compose table on el_GR.UTF-8, and the -- * multiple outputs in el_GR's compose causes a warning in gtkcomposetable -+ * multiple outputs in el_GR's compose causes a warning in gtkcomposetable - * and the warning always causes a fatal in GTest: - " "GTK+ supports to output one char only: " - */ -- g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL); -+ flags = g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL); - gtk_init (&argc, &argv); -+ g_log_set_always_fatal (flags); - - m_srcdir = argc > 1 ? g_strdup (argv[1]) : g_strdup ("."); - m_compose_file = g_strdup (g_getenv ("COMPOSE_FILE")); -diff --git a/src/tests/ibus-config.c b/src/tests/ibus-config.c -index c6141ab5..9b925ad9 100644 ---- a/src/tests/ibus-config.c -+++ b/src/tests/ibus-config.c -@@ -133,254 +133,6 @@ test_config_set_get (void) - g_object_unref (config); - } - --typedef struct { -- GMainLoop *loop; -- guint timeout_id; -- gchar *section; -- gchar *name; --} WatchData; -- --typedef struct { -- gchar *section; -- gchar *name; --} WatchKey; -- --typedef struct { -- WatchKey *watched; /* watched keys (null-terminated) */ -- WatchKey *changed; /* changed keys (null-terminated) */ -- WatchKey *notified; /* notified keys (same length as -- changed, not null-terminated) */ --} WatchTestData; -- --static WatchKey default_watched[] = { -- { NULL } --}; --static WatchKey default_changed[] = { -- { "test/s1", "n1" }, -- { "test/s1", "n2" }, -- { "test/s2", "n1" }, -- { "test/s2", "n2" }, -- { NULL } --}; --static WatchKey default_notified[] = { -- { "test/s1", "n1" }, -- { "test/s1", "n2" }, -- { "test/s2", "n1" }, -- { "test/s2", "n2" } --}; --static WatchTestData default_data = { -- default_watched, -- default_changed, -- default_notified --}; -- --static WatchKey section_watched[] = { -- { "test/s1", NULL }, -- { NULL } --}; --static WatchKey section_notified[] = { -- { "test/s1", "n1" }, -- { "test/s1", "n2" }, -- { NULL, NULL }, -- { NULL, NULL }, --}; --static WatchTestData section_data = { -- section_watched, -- default_changed, -- section_notified --}; -- --static WatchKey section_multiple_watched[] = { -- { "test/s1", NULL }, -- { "test/s2", NULL }, -- { NULL } --}; --static WatchKey section_multiple_notified[] = { -- { "test/s1", "n1" }, -- { "test/s1", "n2" }, -- { "test/s2", "n1" }, -- { "test/s2", "n2" }, --}; --static WatchTestData section_multiple_data = { -- section_multiple_watched, -- default_changed, -- section_multiple_notified --}; -- --static WatchKey section_name_watched[] = { -- { "test/s1", "n1" }, -- { NULL } --}; --static WatchKey section_name_notified[] = { -- { "test/s1", "n1" }, -- { NULL, NULL }, -- { NULL, NULL }, -- { NULL, NULL }, --}; --static WatchTestData section_name_data = { -- section_name_watched, -- default_changed, -- section_name_notified --}; -- --static WatchKey section_name_multiple_watched[] = { -- { "test/s1", "n1" }, -- { "test/s2", "n2" }, -- { NULL } --}; --static WatchKey section_name_multiple_notified[] = { -- { "test/s1", "n1" }, -- { NULL, NULL }, -- { NULL, NULL }, -- { "test/s2", "n2" }, --}; --static WatchTestData section_name_multiple_data = { -- section_name_multiple_watched, -- default_changed, -- section_name_multiple_notified --}; -- --typedef struct { -- IBusConfig *config; -- WatchData data; --} WatchFixture; -- --static void --value_changed_cb (IBusConfig *config, -- const gchar *section, -- const gchar *name, -- GVariant *value, -- gpointer user_data) --{ -- WatchData *data = (WatchData *) user_data; -- -- data->section = g_strdup (section); -- data->name = g_strdup (name); -- -- g_main_loop_quit (data->loop); --} -- --static gboolean --timeout_cb (gpointer user_data) --{ -- WatchData *data = (WatchData *) user_data; -- g_main_loop_quit (data->loop); -- data->timeout_id = 0; -- return FALSE; --} -- --static void --change_and_test (IBusConfig *config, -- const gchar *section, -- const gchar *name, -- const gchar *expected_section, -- const gchar *expected_name, -- WatchData *data) --{ -- gboolean retval; -- GVariant *var; -- -- data->section = NULL; -- data->name = NULL; -- -- /* Unset won't notify value-changed signal. */ -- var = ibus_config_get_values (config, section); -- if (var != NULL) { -- GVariant *value = g_variant_lookup_value (var, name, -- G_VARIANT_TYPE_VARIANT); -- if (value != NULL) { -- ibus_config_unset (config, section, name); -- g_variant_unref (value); -- } -- g_variant_unref (var); -- } -- -- data->timeout_id = g_timeout_add (1, timeout_cb, data); -- g_main_loop_run (data->loop); -- if (data->timeout_id != 0) { -- g_source_remove (data->timeout_id); -- } -- -- retval = ibus_config_set_value (config, section, name, -- g_variant_new_int32 (1)); -- g_assert (retval); -- -- data->timeout_id = g_timeout_add (1, timeout_cb, data); -- g_main_loop_run (data->loop); -- if (data->timeout_id != 0) { -- g_source_remove (data->timeout_id); -- } -- -- g_assert_cmpstr (data->section, ==, expected_section); -- g_assert_cmpstr (data->name, ==, expected_name); -- -- g_free (data->section); -- g_free (data->name); --} -- --static void --watch_fixture_setup (WatchFixture *fixture, gconstpointer user_data) --{ -- fixture->config = ibus_config_new (ibus_bus_get_connection (bus), -- NULL, -- NULL); -- g_assert (fixture->config); -- -- fixture->data.loop = g_main_loop_new (NULL, FALSE); -- g_signal_connect (fixture->config, "value-changed", -- G_CALLBACK (value_changed_cb), &fixture->data); --} -- --static void --watch_fixture_teardown (WatchFixture *fixture, gconstpointer user_data) --{ -- g_main_loop_unref (fixture->data.loop); -- -- ibus_proxy_destroy (IBUS_PROXY (fixture->config)); -- g_object_unref (fixture->config); --} -- --static void --test_config_watch (WatchFixture *fixture, gconstpointer user_data) --{ -- const WatchTestData *data = user_data; -- gint i; -- -- for (i = 0; data->watched[i].section != NULL; i++) { -- ibus_config_watch (fixture->config, -- data->watched[i].section, -- data->watched[i].name); -- } -- for (i = 0; data->changed[i].section != NULL; i++) { -- change_and_test (fixture->config, -- data->changed[i].section, -- data->changed[i].name, -- data->notified[i].section, -- data->notified[i].name, -- &fixture->data); -- } -- for (i = 0; data->watched[i].section != NULL; i++) { -- ibus_config_unwatch (fixture->config, -- data->watched[i].section, -- data->watched[i].name); -- } -- if (i > 0) { -- /* Check if the above unwatch takes effect. */ -- for (i = 0; data->changed[i].section != NULL; i++) { -- change_and_test (fixture->config, -- data->changed[i].section, -- data->changed[i].name, -- NULL, -- NULL, -- &fixture->data); -- } -- } else { -- /* Since we reuse single D-Bus connection, we need to remove the -- default match rule for the next ibus_config_new() call. */ -- ibus_config_unwatch (fixture->config, NULL, NULL); -- } --} -- - gint - main (gint argc, - gchar **argv) -@@ -390,41 +142,6 @@ main (gint argc, - g_test_init (&argc, &argv, NULL); - bus = ibus_bus_new (); - -- g_test_add ("/ibus/config-watch/default", -- WatchFixture, -- &default_data, -- watch_fixture_setup, -- test_config_watch, -- watch_fixture_teardown); -- -- g_test_add ("/ibus/config-watch/section", -- WatchFixture, -- §ion_data, -- watch_fixture_setup, -- test_config_watch, -- watch_fixture_teardown); -- -- g_test_add ("/ibus/config-watch/section-multiple", -- WatchFixture, -- §ion_multiple_data, -- watch_fixture_setup, -- test_config_watch, -- watch_fixture_teardown); -- -- g_test_add ("/ibus/config-watch/section-name", -- WatchFixture, -- §ion_name_data, -- watch_fixture_setup, -- test_config_watch, -- watch_fixture_teardown); -- -- g_test_add ("/ibus/config-watch/section-name-multiple", -- WatchFixture, -- §ion_name_multiple_data, -- watch_fixture_setup, -- test_config_watch, -- watch_fixture_teardown); -- - g_test_add_func ("/ibus/create-config-async", test_create_config_async); - g_test_add_func ("/ibus/config-set-get", test_config_set_get); - -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index a90c1378..b7a72285 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -34,9 +34,10 @@ DISPLAY=:99.0 - BUILDDIR="." - SRCDIR="." - TEST_LOG="test-suite.log" -+TEST_LOG_STDOUT=0 - RESULT_LOG="" - HAVE_GRAPHICS=1 --DESKTOP_COMMAND="gnome-session" -+DESKTOP_COMMAND="dbus-launch --exit-with-session gnome-session" - PID_XORG=0 - PID_GNOME_SESSION=0 - TESTING_RUNNER="default" -@@ -109,19 +110,26 @@ parse_args() - init_desktop() - { - if [ "$RESULT_LOG" != "" ] ; then -- rm $RESULT_LOG -+ if [ -f $RESULT_LOG ] ; then -+ rm $RESULT_LOG -+ fi -+ fi -+ HAS_STDOUT=`echo "$TEST_LOG" | grep ':stdout'` -+ if [ x"$HAS_STDOUT" != x ] ; 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" -- abrt -- else -+ exit -1 -+ elif [ -f $TEST_LOG ] ; then - rm $TEST_LOG - fi -- if test x$FORCE_TEST != x ; then -+ if [ x$FORCE_TEST != x ] ; then - RUN_ARGS="$RUN_ARGS --force" - fi - -- if test ! -f $HOME/.config/gnome-initial-setup-done ; then -+ if [ ! -f $HOME/.config/gnome-initial-setup-done ] ; then - IS_SYSTEM_ACCOUNT=false - if [ "$USER" = "root" ] ; then - IS_SYSTEM_ACCOUNT=true -@@ -141,7 +149,7 @@ _EOF - - # Prevent from launching a XDG dialog - XDG_LOCALE_FILE="$HOME/.config/user-dirs.locale" -- if test -f $XDG_LOCALE_FILE ; then -+ 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 -@@ -153,19 +161,8 @@ _EOF - - run_dbus_daemon() - { -- a=`ps -ef | grep dbus-daemon | grep "\-\-system" | grep -v session | grep -v grep` -- if test x"$a" = x ; then -- eval `dbus-launch --sh-syntax` -- fi -- SUSER=`echo "$USER" | cut -c 1-7` -- a=`ps -ef | grep dbus-daemon | grep "$SUSER" | grep -v gdm | grep session | grep -v grep` -- if test x"$a" = x ; then -- systemctl --user start dbus -- export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$UID/bus -- fi -- systemctl --user status dbus | col -b -- ps -ef | grep dbus-daemon | grep "$SUSER" | grep -v gdm | egrep 'session|system' | grep -v grep -- systemctl --user show-environment | col -b -+ # Use dbus-launch --exit-with-session later instead of --sh-syntax -+ export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$UID/bus - } - - run_desktop() -@@ -181,7 +178,8 @@ run_desktop() - $DESKTOP_COMMAND & - PID_GNOME_SESSION=$! - sleep 30 -- if test "$DESKTOP_COMMAND" != "gnome-session" ; then -+ HAS_GNOME=`echo $DESKTOP_COMMAND | grep gnome-session` -+ if [ x"$HAS_GNOME" = x ] ; then - ibus-daemon --daemonize --verbose - sleep 1 - fi -@@ -285,6 +283,16 @@ run_gnome_desktop_testing_runner() - `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 -o $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 - } - -@@ -311,22 +319,29 @@ EOF_RUNNER - ;; - esac - echo "" -- 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 -+ print_log -e "${GREEN}PASS${NC}: $pass" -+ print_log -e "${RED}FAIL${NC}: $fail" - echo "" -- echo "See ${TEST_LOG}" -+ if [ $TEST_LOG_STDOUT -eq 1 ] ; then -+ cat $TEST_LOG -+ else -+ echo "See $TEST_LOG" -+ fi - } - - finit() - { -- if test "$DESKTOP_COMMAND" != "gnome-session" ; then -- ibus exit -- fi -+ 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" - } - -diff --git a/src/tests/ibus-engine-switch.c b/src/tests/ibus-engine-switch.c -index 5c2bd516..a1eeba2a 100644 ---- a/src/tests/ibus-engine-switch.c -+++ b/src/tests/ibus-engine-switch.c -@@ -13,17 +13,25 @@ static const gchar *engine_names[] = { - AFTER_ENGINE - }; - -+static const gchar *engine_names2[] = { -+ AFTER_ENGINE, -+ BEFORE_ENGINE -+}; -+ - static void --change_global_engine (void) -+change_global_engine (gboolean reverse) - { - gint i; - - for (i = 0; i < G_N_ELEMENTS (engine_names); i++) { -- ibus_bus_set_global_engine (bus, engine_names[i]); -+ const gchar *engine_name = engine_names[i]; -+ if (reverse) -+ engine_name = engine_names2[i]; -+ ibus_bus_set_global_engine (bus, engine_name); - IBusEngineDesc *engine_desc = ibus_bus_get_global_engine (bus); - g_assert_cmpstr (ibus_engine_desc_get_name (engine_desc), - ==, -- engine_names[i]); -+ engine_name); - g_object_unref (G_OBJECT (engine_desc)); - } - } -@@ -46,6 +54,7 @@ typedef struct { - gint count; - guint timeout_id; - guint idle_id; -+ gboolean reverse; - } GlobalEngineChangedData; - - static void -@@ -70,7 +79,7 @@ static gboolean - change_global_engine_cb (gpointer user_data) - { - GlobalEngineChangedData *data = (GlobalEngineChangedData *) user_data; -- change_global_engine (); -+ change_global_engine (data->reverse); - data->idle_id = 0; - return FALSE; - } -@@ -78,12 +87,25 @@ change_global_engine_cb (gpointer user_data) - static void - test_global_engine (void) - { -+ GLogLevelFlags flags; -+ IBusEngineDesc *desc; - GlobalEngineChangedData data; - guint handler_id; - - if (!ibus_bus_get_use_global_engine (bus)) - return; - -+ /* "No global engine." warning is not critical message. */ -+ flags = g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL); -+ desc = ibus_bus_get_global_engine (bus); -+ g_log_set_always_fatal (flags); -+ if (desc && -+ !g_strcmp0 (BEFORE_ENGINE, ibus_engine_desc_get_name (desc))) { -+ data.reverse = TRUE; -+ } else { -+ data.reverse = FALSE; -+ } -+ - data.count = 0; - - handler_id = g_signal_connect (bus, -@@ -141,7 +163,7 @@ test_context_engine_set_by_global (void) - /* ibus_bus_set_global_engine() changes focused context engine. */ - ibus_input_context_focus_in (context); - -- change_global_engine (); -+ change_global_engine (FALSE); - - /* ibus_input_context_set_engine() does not take effect when - global engine is used. */ -@@ -170,7 +192,7 @@ test_context_engine_set_by_focus (void) - - ibus_input_context_focus_in (context); - -- change_global_engine (); -+ change_global_engine (FALSE); - - /* When focus is lost, context engine is set to "dummy". */ - ibus_input_context_focus_in (another_context); -diff --git a/src/tests/ibus-inputcontext.c b/src/tests/ibus-inputcontext.c -index fab183aa..ed04bd64 100644 ---- a/src/tests/ibus-inputcontext.c -+++ b/src/tests/ibus-inputcontext.c -@@ -37,18 +37,6 @@ fatal_handler(const gchar *log_domain, - return TRUE; - } - --static gchar * --get_last_engine_id (const GList *engines) --{ -- const char *result = NULL; -- for (; engines; engines = g_list_next (engines)) { -- IBusEngineDesc *engine_desc = IBUS_ENGINE_DESC (engines->data); -- g_assert (engine_desc); -- result = ibus_engine_desc_get_name (engine_desc); -- } -- return g_strdup (result); --} -- - static void - call_basic_ipcs (IBusInputContext *context) - { -@@ -68,18 +56,23 @@ call_basic_ipcs (IBusInputContext *context) - static void - test_input_context (void) - { -- GList *engines; -- gchar *active_engine_name = NULL; - IBusInputContext *context; -+ GLogLevelFlags flags; - IBusEngineDesc *engine_desc; -+ gchar *active_engine_name = NULL; - gchar *current_ic; - - context = ibus_bus_create_input_context (bus, "test"); - call_basic_ipcs (context); - -- engines = ibus_bus_list_active_engines (bus); -- if (engines != NULL) { -- active_engine_name = get_last_engine_id (engines); -+ /* "No global engine." warning is not critical message. */ -+ flags = g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL); -+ engine_desc = ibus_bus_get_global_engine (bus); -+ g_log_set_always_fatal (flags); -+ if (engine_desc != NULL) { -+ active_engine_name = g_strdup (ibus_engine_desc_get_name(engine_desc)); -+ g_object_unref (engine_desc); -+ engine_desc = NULL; - } else { - active_engine_name = g_strdup ("dummy"); - } -@@ -111,8 +104,6 @@ test_input_context (void) - g_object_unref (context); - - g_free (active_engine_name); -- g_list_foreach (engines, (GFunc) g_object_unref, NULL); -- g_list_free (engines); - } - - static void -diff --git a/src/tests/ibus-keypress.c b/src/tests/ibus-keypress.c -index 17920226..dd1b0042 100644 ---- a/src/tests/ibus-keypress.c -+++ b/src/tests/ibus-keypress.c -@@ -288,6 +288,10 @@ int - main (int argc, char *argv[]) - { - ibus_init (); -+ /* Avoid a warning of "AT-SPI: Could not obtain desktop path or name" -+ * with gtk_main(). -+ */ -+ g_setenv ("NO_AT_BRIDGE", "1", TRUE); - g_test_init (&argc, &argv, NULL); - gtk_init (&argc, &argv); - --- -2.21.0 - -From f4463c0433c5f48a4fb2830e8c2ae9619fbb18d1 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Mon, 29 Jul 2019 19:05:43 +0900 -Subject: [PATCH] src/tests: Fix a fatal error with g_warning - -I set g_log_set_always_fatal() before gtk_init() in ibus-compose for -a compose warning of GtkIMContextSimple but actually the warning is -output during gtk_main() due to GtkIMContextSimple.set_client_window() -so I moved g_log_set_always_fatal() before gtk_main() in ibus-compose.c. - -Also set IFS in ibus-compose-locales to set the delimiter to '\n' for -for-loop arguments. ---- - src/tests/ibus-compose-locales.in | 8 ++++++++ - src/tests/ibus-compose.c | 21 ++++++++++----------- - 2 files changed, 18 insertions(+), 11 deletions(-) - -diff --git a/src/tests/ibus-compose-locales.in b/src/tests/ibus-compose-locales.in -index fad02965..f650b584 100755 ---- a/src/tests/ibus-compose-locales.in -+++ b/src/tests/ibus-compose-locales.in -@@ -7,19 +7,27 @@ BUILDDIR=`dirname $0` - export IBUS_COMPOSE_CACHE_DIR=$PWD - - retval=0 -+# Let for-loop notice '\n' as a delimiter -+IFS=$'\n' - for var in `cat $SRCDIR/ibus-compose.env` - do -+ # Revert IFS to recognize env a=foo b=foo -+ IFS=' ' - IS_COMMENT=`echo "$var" | grep "^#"` - if [ "x$IS_COMMENT" != x ] ; then - continue - fi -+ echo "# Starting $var $BUILDDIR/ibus-compose $SRCDIR $@" - env $var $BUILDDIR/ibus-compose $SRCDIR $@ - 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 -+ IFS=$'\n' - done -+IFS=' ' - exit $retval -diff --git a/src/tests/ibus-compose.c b/src/tests/ibus-compose.c -index db359477..4b4c56e7 100644 ---- a/src/tests/ibus-compose.c -+++ b/src/tests/ibus-compose.c -@@ -331,20 +331,28 @@ create_window () - static void - test_compose (void) - { -+ GLogLevelFlags flags; - if (!register_ibus_engine ()) { - g_test_fail (); - return; - } - - create_window (); -+ /* FIXME: -+ * IBusIMContext opens GtkIMContextSimple as the slave and -+ * GtkIMContextSimple opens the compose table on el_GR.UTF-8, and the -+ * multiple outputs in el_GR's compose causes a warning in gtkcomposetable -+ * and the warning always causes a fatal in GTest: -+ " "GTK+ supports to output one char only: " -+ */ -+ flags = g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL); - gtk_main (); -- -+ g_log_set_always_fatal (flags); - } - - int - main (int argc, char *argv[]) - { -- GLogLevelFlags flags; - const gchar *test_name; - gchar *test_path; - -@@ -354,16 +362,7 @@ main (int argc, char *argv[]) - */ - g_setenv ("NO_AT_BRIDGE", "1", TRUE); - g_test_init (&argc, &argv, NULL); -- /* FIXME: -- * IBusIMContext opens GtkIMContextSimple as the slave and -- * GtkIMContextSimple opens the compose table on el_GR.UTF-8, and the -- * multiple outputs in el_GR's compose causes a warning in gtkcomposetable -- * and the warning always causes a fatal in GTest: -- " "GTK+ supports to output one char only: " -- */ -- flags = g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL); - gtk_init (&argc, &argv); -- g_log_set_always_fatal (flags); - - m_srcdir = argc > 1 ? g_strdup (argv[1]) : g_strdup ("."); - m_compose_file = g_strdup (g_getenv ("COMPOSE_FILE")); --- -2.21.0 - -From 7dde99600777f195da614130950ecbd339439d35 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Wed, 31 Jul 2019 16:27:49 +0900 -Subject: [PATCH] src/tests: Fix wrong echo with direct runner in - ibus-desktop-testing-runner - -The wrong echo prevent from counting the test results in the direct -testing runner. ---- - src/tests/ibus-desktop-testing-runner.in | 33 +++++++++++++----------- - 1 file changed, 18 insertions(+), 15 deletions(-) - -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index b7a72285..3045d601 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -153,7 +153,7 @@ _EOF - 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 "# Overriding XDG locale $XDG_LANG_ORIG with $XDG_LANG_NEW" - echo "$XDG_LANG_NEW" > $XDG_LOCALE_FILE - fi - fi -@@ -206,11 +206,9 @@ echo_case_result() - subtst=${3:-''} - - if test $retval -eq 0 ; then -- print_log -e "${GREEN}PASS${NC}: $tst $subtst" -+ echo "PASS: $tst $subtst" >>$TEST_LOG - else -- print_log -e "${RED}FAIL${NC}: $tst $subtst" -- print_log "======================" -- print_log "" -+ echo "FAIL: $tst $subtst" >>$TEST_LOG - fi - } - -@@ -232,32 +230,37 @@ EOF - echo_case_result $retval $tst - CACHE_FILES=`ls *.cache` - if [ x"$CACHE_FILES" != x ] ; then -- print_log "Clean $CACHE_FILES" -+ echo "# Clean $CACHE_FILES" >>$TEST_LOG - rm $CACHE_FILES - fi - else -- LANG_backup=$LANG - i=1 -+ # Let for-loop notice '\n' as a delimiter -+ IFS=$'\n' - for e in $ENVS; do -+ # Revert IFS to recognize env a=foo b=foo -+ IFS=' ' - first=`echo "$e" | grep '^#'` - if test x"$first" = x"#" ; then - continue - fi -- export $e -- $BUILDDIR/$tst $SRCDIR 2>>$TEST_LOG 1>>$TEST_LOG -+ 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_case_result $retval $pass $fail` - EOF - echo_case_result $retval $tst $e - CACHE_FILES=`ls *.cache` - if [ x"$CACHE_FILES" != x ] ; then -- print_log "Clean $CACHE_FILES" -+ echo "# Clean $CACHE_FILES" >>$TEST_LOG - rm $CACHE_FILES - fi - i=`expr $i + 1` -+ IFS=$'\n' - done -- export LANG=$LANG_backup -+ IFS=' ' - fi - done - echo $pass $fail -@@ -325,24 +328,24 @@ EOF_RUNNER - if [ $TEST_LOG_STDOUT -eq 1 ] ; then - cat $TEST_LOG - else -- echo "See $TEST_LOG" -+ echo "# See $TEST_LOG" - fi - } - - finit() - { -- echo "Killing left gnome-session and Xorg" -+ 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 "# Killing left gnome-shell-calendar-server" - echo "$LEFT_CALENDAR" - echo "$LEFT_CALENDAR" | awk '{print $2}' | xargs kill - fi - -- echo "Finished $PROGNAME testing" -+ echo "# Finished $PROGNAME testing" - } - - main() --- -2.21.0 - -From 28c10d64d282fa9fbc35a7bc44a096f6137d5e46 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 13 Aug 2019 20:06:51 +0900 -Subject: [PATCH] src/tests: Set XDG_SESSION_TYPE in - ibus-desktop-testing-runner - -mutter 3.33.90 or later exits the session without loginctl. -Now ibus-desktop-testing-runner has XDG_SESSION_TYPE forcibly -not to exit gnome-shell. ---- - src/tests/ibus-desktop-testing-runner.in | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index 3045d601..141e9b5b 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -157,6 +157,8 @@ _EOF - echo "$XDG_LANG_NEW" > $XDG_LOCALE_FILE - fi - fi -+ # `su` command does not run loginctl -+ export XDG_SESSION_TYPE='x11' - } - - run_dbus_daemon() -@@ -175,6 +177,7 @@ run_desktop() - PID_XORG=$! - sleep 1 - export DISPLAY=$DISPLAY -+ echo "Running $DESKTOP_COMMAND with $USER in `tty`" - $DESKTOP_COMMAND & - PID_GNOME_SESSION=$! - sleep 30 --- -2.21.0 - -From bccf94d5ec1c5fc80d5aeac622f2ab8007d5a28a Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 29 Nov 2019 20:28:49 +0900 -Subject: [PATCH] src/tests: RHEL codereview for ibus-desktop-testing-runner - ---- - src/tests/ibus-desktop-testing-runner.in | 16 ++++++++++------ - 1 file changed, 10 insertions(+), 6 deletions(-) - -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index 141e9b5b..72537cd4 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -28,6 +28,10 @@ - # # /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'} -+ -+ - PROGNAME=`basename $0` - VERSION=0.1 - DISPLAY=:99.0 -@@ -54,15 +58,15 @@ print_log() - shift - fi - NO_ESCAPE=`echo $@ | sed -e 's/\\\033\\[0;3.m//g' -e 's/\\\033\\[0m//g'` -- echo $NO_ESCAPE >> $RESULT_LOG -+ $ECHO $NO_ESCAPE >> $RESULT_LOG - else -- echo $@ -+ $ECHO $@ - fi - } - - usage() - { -- echo -e \ -+ $ECHO -e \ - "This test runs /usr/bin/ibus-daemon after install ibus\n" \ - "$PROGNAME [OPTIONS…]\n" \ - "\n" \ -@@ -92,7 +96,7 @@ parse_args() - while [ 1 ] ; do - case "$1" in - -h | --help ) usage; exit 0;; -- -v | --version ) echo -e "$VERSION"; 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;; -@@ -121,7 +125,7 @@ init_desktop() - 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 -+ exit 255 - elif [ -f $TEST_LOG ] ; then - rm $TEST_LOG - fi -@@ -291,7 +295,7 @@ EOF - done - child_pass=`grep '^PASS:' $TEST_LOG | wc -l` - child_fail=`grep '^FAIL:' $TEST_LOG | wc -l` -- if [ $child_pass -ne 0 -o $child_fail -ne 0 ] ; then -+ if [ $child_pass -ne 0 ] || [ $child_fail -ne 0 ] ; then - pass=$child_pass - if [ $child_fail -ne 0 ] ; then - fail=`expr $child_fail / 2` --- -2.21.0 - -From d50627f0b7a000ee13ea6dcc02a4162be1fa853d Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 3 Dec 2019 21:42:49 +0900 -Subject: [PATCH] src/tests: RHEL codereview #2 for ibus-desktop-testing-runner - ---- - src/tests/ibus-compose-locales.in | 21 +++++++-------- - src/tests/ibus-desktop-testing-runner.in | 33 ++++++++++++------------ - 2 files changed, 27 insertions(+), 27 deletions(-) - -diff --git a/src/tests/ibus-compose-locales.in b/src/tests/ibus-compose-locales.in -index f650b584..b36165fe 100755 ---- a/src/tests/ibus-compose-locales.in -+++ b/src/tests/ibus-compose-locales.in -@@ -7,27 +7,26 @@ BUILDDIR=`dirname $0` - export IBUS_COMPOSE_CACHE_DIR=$PWD - - retval=0 --# Let for-loop notice '\n' as a delimiter --IFS=$'\n' --for var in `cat $SRCDIR/ibus-compose.env` -+# Deleted for var in `cat *.env` because IFS=$'\n' is not supported in POSIX sh -+while read var - do -- # Revert IFS to recognize env a=foo b=foo -- IFS=' ' - IS_COMMENT=`echo "$var" | grep "^#"` - if [ "x$IS_COMMENT" != x ] ; then - continue - fi -- echo "# Starting $var $BUILDDIR/ibus-compose $SRCDIR $@" -- env $var $BUILDDIR/ibus-compose $SRCDIR $@ -+ # 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" -+ 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 -- IFS=$'\n' --done --IFS=' ' -+done << EOF_ENVS -+`cat $SRCDIR/ibus-compose.env` -+EOF_ENVS - exit $retval -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index 72537cd4..981941d5 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -30,6 +30,8 @@ - - # POSIX sh has no 'echo -e' - : ${ECHO:='/usr/bin/echo'} -+# POSIX sh has $UID -+: ${UID:='`id -u`'} - - - PROGNAME=`basename $0` -@@ -57,10 +59,10 @@ print_log() - if [ x"$1" = x'-e' ] ; then - shift - fi -- NO_ESCAPE=`echo $@ | sed -e 's/\\\033\\[0;3.m//g' -e 's/\\\033\\[0m//g'` -+ NO_ESCAPE=`echo "$@" | sed -e 's/\\\033\\[0;3.m//g' -e 's/\\\033\\[0m//g'` - $ECHO $NO_ESCAPE >> $RESULT_LOG - else -- $ECHO $@ -+ $ECHO "$@" - fi - } - -@@ -231,9 +233,9 @@ run_direct_test_cases() - if test x"$ENVS" = x ; then - $BUILDDIR/$tst $SRCDIR 2>>$TEST_LOG 1>>$TEST_LOG - retval=$? -- read pass fail << EOF -+ read pass fail << EOF_COUNT - `count_case_result $retval $pass $fail` --EOF -+EOF_COUNT - echo_case_result $retval $tst - CACHE_FILES=`ls *.cache` - if [ x"$CACHE_FILES" != x ] ; then -@@ -242,11 +244,9 @@ EOF - fi - else - i=1 -- # Let for-loop notice '\n' as a delimiter -- IFS=$'\n' -- for e in $ENVS; do -- # Revert IFS to recognize env a=foo b=foo -- IFS=' ' -+ # 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 -@@ -255,9 +255,9 @@ EOF - 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 -+ read pass fail << EOF_COUNT - `count_case_result $retval $pass $fail` --EOF -+EOF_COUNT - echo_case_result $retval $tst $e - CACHE_FILES=`ls *.cache` - if [ x"$CACHE_FILES" != x ] ; then -@@ -265,9 +265,9 @@ EOF - rm $CACHE_FILES - fi - i=`expr $i + 1` -- IFS=$'\n' -- done -- IFS=' ' -+ done << EOF_ENVS -+ `echo "$ENVS"` -+EOF_ENVS - fi - done - echo $pass $fail -@@ -357,7 +357,7 @@ finit() - - main() - { -- parse_args $@ -+ parse_args "$@" - init_desktop - run_dbus_daemon 2>>$TEST_LOG 1>>$TEST_LOG - run_desktop 2>>$TEST_LOG 1>>$TEST_LOG -@@ -365,4 +365,5 @@ main() - finit - } - --main $@ -+# Need to enclose $@ with double quotes not to split the array. -+main "$@" --- -2.21.0 - -From 74863851e83972e86a5bdb3da3d99784fc8d4955 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 28 Jan 2020 18:46:13 +0900 -Subject: [PATCH] src/tests: Increase sleep to 3 waiting for IBusConfig - -Sleep 1 would be too short for ibus-daemon which could run all components. -ibus-config test requires the running IBusConfig and the test could fail -in some slow systems. -Sleep time will be increased to 3 to run all components. - -BUG=https://github.com/ibus/ibus/issues/2170 ---- - src/tests/ibus-config.c | 4 ++++ - src/tests/ibus-desktop-testing-runner.in | 2 +- - src/tests/runtest | 2 +- - 3 files changed, 6 insertions(+), 2 deletions(-) - -diff --git a/src/tests/ibus-config.c b/src/tests/ibus-config.c -index 5e845f10..0d9812a3 100644 ---- a/src/tests/ibus-config.c -+++ b/src/tests/ibus-config.c -@@ -16,6 +16,10 @@ finish_create_config_async_success (GObject *source_object, - IBusConfig *config = - ibus_config_new_async_finish (res, &error); - -+ if (error) { -+ g_message ("Failed to generate IBusConfig: %s", error->message); -+ g_error_free (error); -+ } - g_assert (IBUS_IS_CONFIG (config)); - - /* Since we reuse single D-Bus connection, we need to remove the -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index 981941d5..0d9a847c 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -190,7 +190,7 @@ run_desktop() - HAS_GNOME=`echo $DESKTOP_COMMAND | grep gnome-session` - if [ x"$HAS_GNOME" = x ] ; then - ibus-daemon --daemonize --verbose -- sleep 1 -+ sleep 3 - fi - } - -diff --git a/src/tests/runtest b/src/tests/runtest -index ed38992f..a6e4194b 100755 ---- a/src/tests/runtest -+++ b/src/tests/runtest -@@ -180,7 +180,7 @@ run_test_case() - fi - - # Wait until all necessary components are up. -- sleep 1 -+ sleep 3 - - export GTK_IM_MODULE=ibus - fi --- -2.24.1 - -From 7b0d091839a4f1315ba216175fb2787e86f7fa31 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 3 Mar 2020 17:08:30 +0900 -Subject: [PATCH] src/tests: Delete graves in substitution in - ibus-desktop-testing-runner - -Delete the single quotations to enclose grave chracters because -DASH saves the single quoted '`id -u`' as the raw string in the command -substitution not to be extracted. - -BUG=https://github.com/ibus/ibus/issues/2189 ---- - src/tests/ibus-desktop-testing-runner.in | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index 0d9a847c..f9238e69 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-2019 Takao Fujiwara -+# Copyright (c) 2018-2020 Takao Fujiwara - # Copyright (c) 2018 Red Hat, Inc. - # - # This program is free software; you can redistribute it and/or modify -@@ -31,7 +31,8 @@ - # POSIX sh has no 'echo -e' - : ${ECHO:='/usr/bin/echo'} - # POSIX sh has $UID --: ${UID:='`id -u`'} -+# DASH saves the graves in '``' as characters not to be extracted -+: ${UID:=`id -u`} - - - PROGNAME=`basename $0` -@@ -170,7 +171,7 @@ _EOF - run_dbus_daemon() - { - # Use dbus-launch --exit-with-session later instead of --sh-syntax -- export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$UID/bus -+ export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$UID/bus" - } - - run_desktop() --- -2.24.1 - -From 8da016764cee9616cca4658d1fb311d6b3bfc0df Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Wed, 15 Apr 2020 17:55:03 +0900 -Subject: [PATCH] src/tests: Fix to get focus events with su in - ibus-desktop-testing-runner - -GtkWindow haven't received focus events in any test cases since Fedora 31 -whenever Ansible runs ibus-desktop-testing-runner after `su root`. -Seems su command does not run systemd automatically and now systemd -requires XDG_RUNTIME_DIR and Ansible requires root access with ssh. -This fix requires to restart sshd with modified /etc/ssh/sshd_config -with "PermitRootLogin yes" in order to run with su command. - -Ansible with ibus-desktop-testin-runner has worked fine if root console -login is used without this patch because PAM runs systemd by login. ---- - src/tests/ibus-desktop-testing-runner.in | 36 ++++++++++++++++++++++-- - 1 file changed, 33 insertions(+), 3 deletions(-) - -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index f9238e69..f760fd5b 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -49,6 +49,7 @@ PID_XORG=0 - PID_GNOME_SESSION=0 - TESTING_RUNNER="default" - TESTS="" -+TIMEOUT=300 - GREEN='\033[0;32m' - RED='\033[0;31m' - NC='\033[0m' -@@ -84,6 +85,7 @@ usage() - "-r, --runner=RUNNER Run TESTS programs with a test RUNNER.\n" \ - " RUNNDER = gnome or default.\n" \ - " default is an embedded runner.\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" \ - "" -@@ -92,8 +94,8 @@ usage() - parse_args() - { - # This is GNU getopt. "sudo port getopt" in BSD? -- ARGS=`getopt -o hvb:s:cd:t:r:o:O: --long \ -- help,version,builddir:,srcdir:,no-graphics,desktop:,tests:,runner:,output:,result:\ -+ ARGS=`getopt -o hvb:s:cd:t:r:T:o:O: --long \ -+ help,version,builddir:,srcdir:,no-graphics,desktop:,tests:,runner:,timeout:,output:,result:\ - -- "$@"`; - eval set -- "$ARGS" - while [ 1 ] ; do -@@ -106,6 +108,7 @@ parse_args() - -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;; - -- ) shift; break;; -@@ -166,11 +169,37 @@ _EOF - 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" - } - -@@ -288,7 +317,8 @@ run_gnome_desktop_testing_runner() - fail=1 - continue - fi -- gnome-desktop-testing-runner $tst 2>>$TEST_LOG 1>>$TEST_LOG -+ gnome-desktop-testing-runner --timeout=$TIMEOUT $tst \ -+ 2>>$TEST_LOG 1>>$TEST_LOG - retval=$? - read pass fail << EOF - `count_case_result $retval $pass $fail` --- -2.24.1 - -From 0b9d9365988a96a2bc31c48624f9c2b8081601b6 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Wed, 22 Apr 2020 20:17:12 +0900 -Subject: [PATCH] client/gtk2: Fix typo - ---- - client/gtk2/ibusim.c | 4 ++-- - src/tests/ibus-desktop-testing-runner.in | 2 +- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/tests/ibus-desktop-testing-runner.in b/src/tests/ibus-desktop-testing-runner.in -index f760fd5b..4232c549 100755 ---- a/src/tests/ibus-desktop-testing-runner.in -+++ b/src/tests/ibus-desktop-testing-runner.in -@@ -173,7 +173,7 @@ _EOF - # `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 -+ 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" --- -2.24.1 - diff --git a/ibus-1713606-hangul-with-mouse.patch b/ibus-1713606-hangul-with-mouse.patch deleted file mode 100644 index 0fabe65..0000000 --- a/ibus-1713606-hangul-with-mouse.patch +++ /dev/null @@ -1,1424 +0,0 @@ -From a40631e166137c9042a68c2d76844e7afc53d388 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Fri, 9 Nov 2018 14:49:44 +0900 -Subject: [PATCH] Detect mouse click to commit Hangul preedit - -If preedit text is not committed with the mouse click, preedit text -is moved to the new cursor position in Hangul typing. -Since set_cursor_location() is received before the reset() signal is -sent to ibus-daemon and commit_text() signal is received from -ibus-daemon, UpdatePreeditTextWithMode D-Bus method is newly added -and now ibus clients commit the preedit. - -BUG=https://github.com/ibus/ibus/issues/1980 ---- - bus/ibusimpl.c | 11 ++++ - bus/inputcontext.c | 108 ++++++++++++++++++++++++------- - bus/inputcontext.h | 19 +++++- - client/gtk2/ibusimcontext.c | 95 +++++++++++++++++++++++++--- - src/ibusinputcontext.c | 122 ++++++++++++++++++++++++++++++++---- - src/ibusinputcontext.h | 27 +++++++- - 6 files changed, 338 insertions(+), 44 deletions(-) - -diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c -index 80f3acfb..bbbb5770 100644 ---- a/bus/ibusimpl.c -+++ b/bus/ibusimpl.c -@@ -815,6 +815,17 @@ bus_ibus_impl_set_focused_context (BusIBusImpl *ibus, - engine = bus_input_context_get_engine (ibus->focused_context); - if (engine) { - g_object_ref (engine); -+ /* _ic_focus_in() can be called before _ic_focus_out() is -+ * called under the async processes of two ibus clients. -+ * E.g. gedit is a little slower v.s. a simple GtkTextView -+ * application is the fastest when you click a Hangul -+ * preedit text between the applications. -+ * preedit will be committed with focus-out in the ibus client -+ * likes ibus-im.so -+ * so do not commit preedit here in focus-in event. -+ */ -+ bus_input_context_clear_preedit_text (ibus->focused_context, -+ FALSE); - bus_input_context_set_engine (ibus->focused_context, NULL); - bus_input_context_set_emoji_extension (ibus->focused_context, - NULL); -diff --git a/bus/inputcontext.c b/bus/inputcontext.c -index 4f98b849..1b8e7adb 100644 ---- a/bus/inputcontext.c -+++ b/bus/inputcontext.c -@@ -73,6 +73,7 @@ struct _BusInputContext { - guint preedit_cursor_pos; - gboolean preedit_visible; - guint preedit_mode; -+ gboolean client_commit_preedit; - - /* auxiliary text */ - IBusText *auxiliary_text; -@@ -212,6 +213,9 @@ static IBusPropList *props_empty = NULL; - static const gchar introspection_xml[] = - "" - " " -+ /* properties */ -+ " " -+ " \n" - /* methods */ - " " - " " -@@ -273,6 +277,12 @@ static const gchar introspection_xml[] = - " " - " " - " " -+ " " -+ " " -+ " " -+ " " -+ " " -+ " " - " " - " " - " " -@@ -297,9 +307,6 @@ static const gchar introspection_xml[] = - " " - " " - " " -- -- /* properties */ -- " " - " " - ""; - -@@ -1069,6 +1076,12 @@ _ic_reset (BusInputContext *context, - GDBusMethodInvocation *invocation) - { - if (context->engine) { -+ if (context->preedit_mode == IBUS_ENGINE_PREEDIT_COMMIT) { -+ if (context->client_commit_preedit) -+ bus_input_context_clear_preedit_text (context, FALSE); -+ else -+ bus_input_context_clear_preedit_text (context, TRUE); -+ } - bus_engine_proxy_reset (context->engine); - } - g_dbus_method_invocation_return_value (invocation, NULL); -@@ -1354,6 +1367,13 @@ _ic_set_content_type (BusInputContext *context, - } - } - -+static void -+_ic_set_client_commit_preedit (BusInputContext *context, -+ GVariant *value) -+{ -+ g_variant_get (value, "(b)", &context->client_commit_preedit); -+} -+ - static gboolean - bus_input_context_service_set_property (IBusService *service, - GDBusConnection *connection, -@@ -1379,9 +1399,14 @@ bus_input_context_service_set_property (IBusService *service, - if (!bus_input_context_service_authorized_method (service, connection)) - return FALSE; - -+ g_return_val_if_fail (BUS_IS_INPUT_CONTEXT (service), FALSE); -+ - if (g_strcmp0 (property_name, "ContentType") == 0) { -- BusInputContext *context = (BusInputContext *) service; -- _ic_set_content_type (context, value); -+ _ic_set_content_type (BUS_INPUT_CONTEXT (service), value); -+ return TRUE; -+ } -+ if (g_strcmp0 (property_name, "ClientCommitPreedit") == 0) { -+ _ic_set_client_commit_preedit (BUS_INPUT_CONTEXT (service), value); - return TRUE; - } - -@@ -1453,22 +1478,44 @@ bus_input_context_focus_in (BusInputContext *context) - - /** - * bus_input_context_clear_preedit_text: -+ * @context: A #BusInputContext -+ * @with_signal: %FALSE if the preedit is already updated in ibus clients -+ * likes ibus-im.so. Otherwise %TRUE. - * -- * Clear context->preedit_text. If the preedit mode is IBUS_ENGINE_PREEDIT_COMMIT, commit it before clearing. -+ * Clear context->preedit_text. If the preedit mode is -+ * IBUS_ENGINE_PREEDIT_COMMIT, commit it before clearing. - */ --static void --bus_input_context_clear_preedit_text (BusInputContext *context) -+void -+bus_input_context_clear_preedit_text (BusInputContext *context, -+ gboolean with_signal) - { -+ IBusText *preedit_text; -+ guint preedit_mode; -+ gboolean preedit_visible; -+ - g_assert (BUS_IS_INPUT_CONTEXT (context)); - -- if (context->preedit_visible && -- context->preedit_mode == IBUS_ENGINE_PREEDIT_COMMIT) { -- bus_input_context_commit_text (context, context->preedit_text); -+ if (!with_signal) { -+ g_object_unref (context->preedit_text); -+ context->preedit_mode = IBUS_ENGINE_PREEDIT_CLEAR; -+ context->preedit_text = (IBusText *) g_object_ref_sink (text_empty); -+ context->preedit_cursor_pos = 0; -+ context->preedit_visible = FALSE; -+ return; - } - -- /* always clear preedit text */ -+ /* always clear preedit text to reset the cursor position in the -+ * client application before commit the preeit text. */ -+ preedit_text = g_object_ref (context->preedit_text); -+ preedit_mode = context->preedit_mode; -+ preedit_visible = context->preedit_visible; - bus_input_context_update_preedit_text (context, - text_empty, 0, FALSE, IBUS_ENGINE_PREEDIT_CLEAR, TRUE); -+ -+ if (preedit_visible && preedit_mode == IBUS_ENGINE_PREEDIT_COMMIT) { -+ bus_input_context_commit_text (context, preedit_text); -+ } -+ g_object_unref (preedit_text); - } - - void -@@ -1479,7 +1526,10 @@ bus_input_context_focus_out (BusInputContext *context) - if (!context->has_focus) - return; - -- bus_input_context_clear_preedit_text (context); -+ if (context->client_commit_preedit) -+ bus_input_context_clear_preedit_text (context, FALSE); -+ else -+ bus_input_context_clear_preedit_text (context, TRUE); - bus_input_context_update_auxiliary_text (context, text_empty, FALSE); - bus_input_context_update_lookup_table (context, - lookup_table_empty, -@@ -2338,7 +2388,7 @@ bus_input_context_disable (BusInputContext *context) - { - g_assert (BUS_IS_INPUT_CONTEXT (context)); - -- bus_input_context_clear_preedit_text (context); -+ bus_input_context_clear_preedit_text (context, TRUE); - bus_input_context_update_auxiliary_text (context, text_empty, FALSE); - bus_input_context_update_lookup_table (context, - lookup_table_empty, -@@ -2385,7 +2435,7 @@ bus_input_context_unset_engine (BusInputContext *context) - { - g_assert (BUS_IS_INPUT_CONTEXT (context)); - -- bus_input_context_clear_preedit_text (context); -+ bus_input_context_clear_preedit_text (context, TRUE); - bus_input_context_update_auxiliary_text (context, text_empty, FALSE); - bus_input_context_update_lookup_table (context, - lookup_table_empty, -@@ -2807,14 +2857,26 @@ bus_input_context_update_preedit_text (BusInputContext *context, - } else if (PREEDIT_CONDITION) { - GVariant *variant = ibus_serializable_serialize ( - (IBusSerializable *)context->preedit_text); -- bus_input_context_emit_signal (context, -- "UpdatePreeditText", -- g_variant_new ( -- "(vub)", -- variant, -- context->preedit_cursor_pos, -- extension_visible), -- NULL); -+ if (context->client_commit_preedit) { -+ bus_input_context_emit_signal ( -+ context, -+ "UpdatePreeditTextWithMode", -+ g_variant_new ("(vubu)", -+ variant, -+ context->preedit_cursor_pos, -+ extension_visible, -+ context->preedit_mode), -+ NULL); -+ } else { -+ bus_input_context_emit_signal ( -+ context, -+ "UpdatePreeditText", -+ g_variant_new ("(vub)", -+ variant, -+ context->preedit_cursor_pos, -+ extension_visible), -+ NULL); -+ } - } else { - g_signal_emit (context, - context_signals[UPDATE_PREEDIT_TEXT], -diff --git a/bus/inputcontext.h b/bus/inputcontext.h -index a46d5c06..7105fff8 100644 ---- a/bus/inputcontext.h -+++ b/bus/inputcontext.h -@@ -2,8 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2014 Peng Huang -- * Copyright (C) 2017 Takao Fujiwara -- * Copyright (C) 2008-2014 Red Hat, Inc. -+ * Copyright (C) 2017-2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -377,5 +377,20 @@ void bus_input_context_update_lookup_table - void bus_input_context_panel_extension_received - (BusInputContext *context, - IBusExtensionEvent *event); -+ -+/** -+ * bus_input_context_clear_preedit_text: -+ * -+ * Clear context->preedit_text. If the preedit mode is -+ * IBUS_ENGINE_PREEDIT_COMMIT and with_signal is %TRUE, commit it before -+ * clearing. -+ * If with_signal is %FALSE, this just clears the preedit coditions -+ * and the actual preedit is handled in ibus clients. -+ */ -+void bus_input_context_clear_preedit_text -+ (BusInputContext *context, -+ gboolean -+ with_signal); -+ - G_END_DECLS - #endif -diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c -index e4de52d9..73a0eaec 100644 ---- a/client/gtk2/ibusimcontext.c -+++ b/client/gtk2/ibusimcontext.c -@@ -2,8 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2015-2017 Takao Fujiwara -- * Copyright (C) 2008-2017 Red Hat, Inc. -+ * Copyright (C) 2015-2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -61,6 +61,7 @@ struct _IBusIMContext { - PangoAttrList *preedit_attrs; - gint preedit_cursor_pos; - gboolean preedit_visible; -+ guint preedit_mode; - - GdkRectangle cursor_area; - gboolean has_focus; -@@ -132,8 +133,14 @@ static void ibus_im_context_set_surrounding - gint len, - gint cursor_index); - -- - /* static methods*/ -+static void _ibus_context_update_preedit_text_cb -+ (IBusInputContext *ibuscontext, -+ IBusText *text, -+ gint cursor_pos, -+ gboolean visible, -+ guint mode, -+ IBusIMContext *ibusimcontext); - static void _create_input_context (IBusIMContext *context); - static gboolean _set_cursor_location_internal - (IBusIMContext *context); -@@ -744,6 +751,7 @@ ibus_im_context_init (GObject *obj) - ibusimcontext->preedit_attrs = NULL; - ibusimcontext->preedit_cursor_pos = 0; - ibusimcontext->preedit_visible = FALSE; -+ ibusimcontext->preedit_mode = IBUS_ENGINE_PREEDIT_CLEAR; - - // Init cursor area - ibusimcontext->cursor_area.x = -1; -@@ -854,6 +862,24 @@ ibus_im_context_finalize (GObject *obj) - G_OBJECT_CLASS(parent_class)->finalize (obj); - } - -+static void -+ibus_im_context_clear_preedit_text (IBusIMContext *ibusimcontext) -+{ -+ g_assert (ibusimcontext->ibuscontext); -+ if (ibusimcontext->preedit_visible && -+ ibusimcontext->preedit_mode == IBUS_ENGINE_PREEDIT_COMMIT) { -+ gchar *preedit_string = g_strdup (ibusimcontext->preedit_string); -+ _ibus_context_update_preedit_text_cb (ibusimcontext->ibuscontext, -+ ibus_text_new_from_string (""), -+ 0, -+ FALSE, -+ IBUS_ENGINE_PREEDIT_CLEAR, -+ ibusimcontext); -+ g_signal_emit (ibusimcontext, _signal_commit_id, 0, preedit_string); -+ g_free (preedit_string); -+ } -+} -+ - static gboolean - ibus_im_context_filter_keypress (GtkIMContext *context, - GdkEventKey *event) -@@ -1003,6 +1029,7 @@ ibus_im_context_focus_out (GtkIMContext *context) - - ibusimcontext->has_focus = FALSE; - if (ibusimcontext->ibuscontext) { -+ ibus_im_context_clear_preedit_text (ibusimcontext); - ibus_input_context_focus_out (ibusimcontext->ibuscontext); - } - -@@ -1022,6 +1049,12 @@ ibus_im_context_reset (GtkIMContext *context) - IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context); - - if (ibusimcontext->ibuscontext) { -+ /* Commented out ibus_im_context_clear_preedit_text(). -+ * Hangul needs to receive the reset callback with button press -+ * but other IMEs should avoid to receive the reset callback -+ * so the signal would need to be customized with GtkSetting. -+ * IBus uses button-press-event instead. -+ */ - ibus_input_context_reset (ibusimcontext->ibuscontext); - } - gtk_im_context_reset (ibusimcontext->slave); -@@ -1068,21 +1101,67 @@ ibus_im_context_get_preedit_string (GtkIMContext *context, - } - - -+static gboolean -+ibus_im_context_button_press_event_cb (GtkWidget *widget, -+ GdkEventButton *event, -+ IBusIMContext *ibusimcontext) -+{ -+ if (event->button != 1) -+ return FALSE; -+ -+ if (ibusimcontext->preedit_visible && -+ ibusimcontext->preedit_mode == IBUS_ENGINE_PREEDIT_COMMIT) { -+ ibus_im_context_clear_preedit_text (ibusimcontext); -+ if (ibusimcontext->ibuscontext) -+ ibus_input_context_reset (ibusimcontext->ibuscontext); -+ } -+ return FALSE; -+} -+ - static void - ibus_im_context_set_client_window (GtkIMContext *context, GdkWindow *client) - { -+ IBusIMContext *ibusimcontext; -+#if !GTK_CHECK_VERSION (3, 93, 0) -+ GtkWidget *widget; -+#endif -+ - IDEBUG ("%s", __FUNCTION__); - -- IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context); -+ ibusimcontext = IBUS_IM_CONTEXT (context); - - if (ibusimcontext->client_window) { -+#if !GTK_CHECK_VERSION (3, 93, 0) -+ gdk_window_get_user_data (ibusimcontext->client_window, -+ (gpointer *)&widget); -+ /* firefox needs GtkWidget instead of GtkWindow */ -+ if (GTK_IS_WIDGET (widget)) { -+ g_signal_handlers_disconnect_by_func ( -+ widget, -+ (GCallback)ibus_im_context_button_press_event_cb, -+ ibusimcontext); -+ } -+#endif - g_object_unref (ibusimcontext->client_window); - ibusimcontext->client_window = NULL; - } - -- if (client != NULL) -+ if (client != NULL) { - ibusimcontext->client_window = g_object_ref (client); -+#if !GTK_CHECK_VERSION (3, 93, 0) -+ gdk_window_get_user_data (ibusimcontext->client_window, -+ (gpointer *)&widget); - -+ /* firefox needs GtkWidget instead of GtkWindow */ -+ if (GTK_IS_WIDGET (widget)) { -+ g_signal_connect ( -+ widget, -+ "button-press-event", -+ G_CALLBACK (ibus_im_context_button_press_event_cb), -+ ibusimcontext); -+ } -+#endif -+ } - if (ibusimcontext->slave) - gtk_im_context_set_client_window (ibusimcontext->slave, client); - } -@@ -1530,6 +1609,7 @@ _ibus_context_update_preedit_text_cb (IBusInputContext *ibuscontext, - IBusText *text, - gint cursor_pos, - gboolean visible, -+ guint mode, - IBusIMContext *ibusimcontext) - { - IDEBUG ("%s", __FUNCTION__); -@@ -1586,6 +1666,7 @@ _ibus_context_update_preedit_text_cb (IBusInputContext *ibuscontext, - - flag = ibusimcontext->preedit_visible != visible; - ibusimcontext->preedit_visible = visible; -+ ibusimcontext->preedit_mode = mode; - - if (ibusimcontext->preedit_visible) { - if (flag) { -@@ -1676,7 +1757,7 @@ _create_input_context_done (IBusBus *bus, - g_error_free (error); - } - else { -- -+ ibus_input_context_set_client_commit_preedit (context, TRUE); - ibusimcontext->ibuscontext = context; - - g_signal_connect (ibusimcontext->ibuscontext, -@@ -1692,7 +1773,7 @@ _create_input_context_done (IBusBus *bus, - G_CALLBACK (_ibus_context_delete_surrounding_text_cb), - ibusimcontext); - g_signal_connect (ibusimcontext->ibuscontext, -- "update-preedit-text", -+ "update-preedit-text-with-mode", - G_CALLBACK (_ibus_context_update_preedit_text_cb), - ibusimcontext); - g_signal_connect (ibusimcontext->ibuscontext, -diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c -index ae7048ad..a809ef08 100644 ---- a/src/ibusinputcontext.c -+++ b/src/ibusinputcontext.c -@@ -2,7 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2008-2013 Red Hat, Inc. -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -39,6 +40,7 @@ enum { - FORWARD_KEY_EVENT, - DELETE_SURROUNDING_TEXT, - UPDATE_PREEDIT_TEXT, -+ UPDATE_PREEDIT_TEXT_WITH_MODE, - SHOW_PREEDIT_TEXT, - HIDE_PREEDIT_TEXT, - UPDATE_AUXILIARY_TEXT, -@@ -217,6 +219,34 @@ ibus_input_context_class_init (IBusInputContextClass *class) - G_TYPE_UINT, - G_TYPE_BOOLEAN); - -+ /** -+ * IBusInputContext::update-preedit-text-with-mode: -+ * @context: An IBusInputContext. -+ * @text: Text to be updated. -+ * @cursor_pos: Cursor position. -+ * @visible: Whether the update is visible. -+ * @mode: Preedit mode. -+ * -+ * Emitted to update preedit text with the mode. -+ * -+ * (Note: The text object is floating, and it will be released after the -+ * signal. If signal handler wants to keep the object, the handler should -+ * use g_object_ref_sink() to get the ownership of the object.) -+ */ -+ context_signals[UPDATE_PREEDIT_TEXT_WITH_MODE] = -+ g_signal_new (I_("update-preedit-text-with-mode"), -+ G_TYPE_FROM_CLASS (class), -+ G_SIGNAL_RUN_LAST, -+ 0, -+ NULL, NULL, -+ _ibus_marshal_VOID__OBJECT_UINT_BOOLEAN_UINT, -+ G_TYPE_NONE, -+ 4, -+ IBUS_TYPE_TEXT, -+ G_TYPE_UINT, -+ G_TYPE_BOOLEAN, -+ G_TYPE_UINT); -+ - /** - * IBusInputContext::show-preedit-text: - * @context: An IBusInputContext. -@@ -542,6 +572,28 @@ ibus_input_context_g_signal (GDBusProxy *proxy, - g_object_unref (text); - return; - } -+ if (g_strcmp0 (signal_name, "UpdatePreeditTextWithMode") == 0) { -+ GVariant *variant = NULL; -+ gint32 cursor_pos; -+ gboolean visible; -+ guint mode = 0; -+ g_variant_get (parameters, -+ "(vubu)", &variant, &cursor_pos, &visible, &mode); -+ IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (variant)); -+ g_variant_unref (variant); -+ -+ g_signal_emit (context, -+ context_signals[UPDATE_PREEDIT_TEXT_WITH_MODE], -+ 0, -+ text, -+ cursor_pos, -+ visible, -+ mode); -+ -+ if (g_object_is_floating (text)) -+ g_object_unref (text); -+ return; -+ } - - /* lookup signal in table */ - gint i; -@@ -1043,10 +1095,11 @@ ibus_input_context_set_surrounding_text (IBusInputContext *context, - guint32 cursor_pos, - guint32 anchor_pos) - { -+ IBusInputContextPrivate *priv; -+ - g_assert (IBUS_IS_INPUT_CONTEXT (context)); - g_assert (IBUS_IS_TEXT (text)); - -- IBusInputContextPrivate *priv; - priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (context); - - if (cursor_pos != priv->surrounding_cursor_pos || -@@ -1090,12 +1143,15 @@ ibus_input_context_set_content_type (IBusInputContext *context, - guint purpose, - guint hints) - { -+ GVariant *cached_content_type; -+ GVariant *content_type; -+ - g_assert (IBUS_IS_INPUT_CONTEXT (context)); - -- GVariant *cached_content_type = -+ cached_content_type = - g_dbus_proxy_get_cached_property ((GDBusProxy *) context, - "ContentType"); -- GVariant *content_type = g_variant_new ("(uu)", purpose, hints); -+ content_type = g_variant_new ("(uu)", purpose, hints); - - g_variant_ref_sink (content_type); - if (cached_content_type == NULL || -@@ -1142,18 +1198,22 @@ ibus_input_context_get_engine_async_finish (IBusInputContext *context, - GAsyncResult *res, - GError **error) - { -+ GVariant *variant; -+ GVariant *engine_desc_variant; -+ IBusEngineDesc *desc; -+ - g_assert (IBUS_IS_INPUT_CONTEXT (context)); - g_assert (G_IS_ASYNC_RESULT (res)); - g_assert (error == NULL || *error == NULL); - -- GVariant *variant = g_dbus_proxy_call_finish ((GDBusProxy *) context, -- res, error); -+ variant = g_dbus_proxy_call_finish ((GDBusProxy *) context, res, error); - if (variant == NULL) { - return NULL; - } - -- GVariant *engine_desc_variant = g_variant_get_child_value (variant, 0); -- IBusEngineDesc *desc = IBUS_ENGINE_DESC (ibus_serializable_deserialize (engine_desc_variant)); -+ engine_desc_variant = g_variant_get_child_value (variant, 0); -+ desc = IBUS_ENGINE_DESC ( -+ ibus_serializable_deserialize (engine_desc_variant)); - g_variant_unref (engine_desc_variant); - g_variant_unref (variant); - -@@ -1163,9 +1223,13 @@ ibus_input_context_get_engine_async_finish (IBusInputContext *context, - IBusEngineDesc * - ibus_input_context_get_engine (IBusInputContext *context) - { -- g_assert (IBUS_IS_INPUT_CONTEXT (context)); - GVariant *result = NULL; - GError *error = NULL; -+ GVariant *engine_desc_variant; -+ IBusEngineDesc *desc; -+ -+ g_assert (IBUS_IS_INPUT_CONTEXT (context)); -+ - result = g_dbus_proxy_call_sync ((GDBusProxy *) context, - "GetEngine", /* method_name */ - NULL, /* parameters */ -@@ -1189,8 +1253,9 @@ ibus_input_context_get_engine (IBusInputContext *context) - return NULL; - } - -- GVariant *engine_desc_variant = g_variant_get_child_value (result, 0); -- IBusEngineDesc *desc = IBUS_ENGINE_DESC (ibus_serializable_deserialize (engine_desc_variant)); -+ engine_desc_variant = g_variant_get_child_value (result, 0); -+ desc = IBUS_ENGINE_DESC ( -+ ibus_serializable_deserialize (engine_desc_variant)); - g_variant_unref (engine_desc_variant); - g_variant_unref (result); - -@@ -1214,6 +1279,41 @@ ibus_input_context_set_engine (IBusInputContext *context, - ); - } - -+void -+ibus_input_context_set_client_commit_preedit (IBusInputContext *context, -+ gboolean client_commit) -+{ -+ GVariant *cached_content_type; -+ GVariant *var_client_commit; -+ -+ g_assert (IBUS_IS_INPUT_CONTEXT (context)); -+ -+ cached_content_type = -+ g_dbus_proxy_get_cached_property ((GDBusProxy *) context, -+ "ClientCommitPreedit"); -+ var_client_commit = g_variant_new ("(b)", client_commit); -+ -+ g_variant_ref_sink (var_client_commit); -+ if (cached_content_type == NULL) { -+ g_dbus_proxy_call ((GDBusProxy *) context, -+ "org.freedesktop.DBus.Properties.Set", -+ g_variant_new ("(ssv)", -+ IBUS_INTERFACE_INPUT_CONTEXT, -+ "ClientCommitPreedit", -+ var_client_commit), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ NULL, /* cancellable */ -+ NULL, /* callback */ -+ NULL /* user_data */ -+ ); -+ } -+ -+ if (cached_content_type != NULL) -+ g_variant_unref (cached_content_type); -+ g_variant_unref (var_client_commit); -+} -+ - #define DEFINE_FUNC(name, Name) \ - void \ - ibus_input_context_##name (IBusInputContext *context) \ -diff --git a/src/ibusinputcontext.h b/src/ibusinputcontext.h -index a77cf92f..09992148 100644 ---- a/src/ibusinputcontext.h -+++ b/src/ibusinputcontext.h -@@ -2,7 +2,8 @@ - /* vim:set et sts=4: */ - /* ibus - The Input Bus - * Copyright (C) 2008-2013 Peng Huang -- * Copyright (C) 2008-2013 Red Hat, Inc. -+ * Copyright (C) 2018 Takao Fujiwara -+ * Copyright (C) 2008-2018 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -498,5 +499,29 @@ void ibus_input_context_set_content_type - guint purpose, - guint hints); - -+/** -+ * ibus_input_context_set_client_commit_preedit: -+ * @context: An #IBusInputContext. -+ * @client_commit: %TRUE if your input context commits pre-edit texts -+ * with Space or Enter key events or mouse click events. %FALSE if -+ * ibus-daemon commits pre-edit texts with those events. -+ * The default is %FALSE. The behavior is decided with -+ * ibus_engine_update_preedit_text_with_mode() to commit, clear or -+ * keep the pre-edit text and this API is important in ibus-hangul. -+ * -+ * Set whether #IBusInputContext commits pre-edit texts or not. -+ * If %TRUE, 'update-preedit-text-with-mode' signal is emitted -+ * instead of 'update-preedit-text' signal. -+ * If your client receives the 'update-preedit-text-with-mode' signal, -+ * the client needs to implement commit_text() of pre-edit text when -+ * GtkIMContextClass.focus_out() is called in case an IME desires that -+ * behavior but it depends on each IME. -+ * -+ * See also ibus_engine_update_preedit_text_with_mode(). -+ */ -+void ibus_input_context_set_client_commit_preedit ( -+ IBusInputContext *context, -+ gboolean client_commit); -+ - G_END_DECLS - #endif --- -2.24.1 - -From 7b3b8c8b0c6a41ab524e0be9474825da9cba96ac Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 13 Nov 2018 14:27:52 +0900 -Subject: [PATCH] client/gtk2: Do not delete IBUS_CAP_SURROUNDING_TEXT - -retrieve-surrounding signal could be failed with the first typing -on firefox. It could be a bug in firefox but now IBusIMContext does not -delete IBUS_CAP_SURROUNDING_TEXT in the capabilities as a workaround -when retrieve-surrounding signal is failed. -Also added retrieve-surrounding signal after some committing text. - -BUG=https://github.com/ibus/ibus/issues/2054 ---- - client/gtk2/ibusimcontext.c | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - -diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c -index 73a0eaec..82af51a1 100644 ---- a/client/gtk2/ibusimcontext.c -+++ b/client/gtk2/ibusimcontext.c -@@ -298,6 +298,7 @@ ibus_im_context_commit_event (IBusIMContext *ibusimcontext, - IBusText *text = ibus_text_new_from_unichar (ch); - g_signal_emit (ibusimcontext, _signal_commit_id, 0, text->text); - g_object_unref (text); -+ _request_surrounding_text (ibusimcontext); - return TRUE; - } - return FALSE; -@@ -386,9 +387,12 @@ _request_surrounding_text (IBusIMContext *context) - g_signal_emit (context, _signal_retrieve_surrounding_id, 0, - &return_value); - if (!return_value) { -- context->caps &= ~IBUS_CAP_SURROUNDING_TEXT; -- ibus_input_context_set_capabilities (context->ibuscontext, -- context->caps); -+ /* #2054 firefox::IMContextWrapper::GetCurrentParagraph() could -+ * fail with the first typing on firefox but it succeeds with -+ * the second typing. -+ */ -+ g_warning ("%s has no capability of surrounding-text feature", -+ g_get_prgname ()); - } - } - } -@@ -877,6 +881,7 @@ ibus_im_context_clear_preedit_text (IBusIMContext *ibusimcontext) - ibusimcontext); - g_signal_emit (ibusimcontext, _signal_commit_id, 0, preedit_string); - g_free (preedit_string); -+ _request_surrounding_text (ibusimcontext); - } - } - --- -2.24.1 - -From 4c40afba9c862b4f6651b1b971553e5e89e83343 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Thu, 6 Dec 2018 16:53:57 +0900 -Subject: [PATCH] client/gtk2: Always reset and clear preedit on mouse click - -Thinking about the reset signal again, now I think it's good to emit -the reset signal and clear the preedit on mouse click for any engines -besides Hangul because the behavior could be handled by each engine -with the reset signal. - -BUG=https://github.com/ibus/ibus/issues/1980 ---- - client/gtk2/ibusimcontext.c | 26 +++++++++++++------------- - 1 file changed, 13 insertions(+), 13 deletions(-) - -diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c -index 82af51a1..ed7fea6e 100644 ---- a/client/gtk2/ibusimcontext.c -+++ b/client/gtk2/ibusimcontext.c -@@ -869,16 +869,19 @@ ibus_im_context_finalize (GObject *obj) - static void - ibus_im_context_clear_preedit_text (IBusIMContext *ibusimcontext) - { -+ gchar *preedit_string = NULL; - g_assert (ibusimcontext->ibuscontext); - if (ibusimcontext->preedit_visible && - ibusimcontext->preedit_mode == IBUS_ENGINE_PREEDIT_COMMIT) { -- gchar *preedit_string = g_strdup (ibusimcontext->preedit_string); -- _ibus_context_update_preedit_text_cb (ibusimcontext->ibuscontext, -- ibus_text_new_from_string (""), -- 0, -- FALSE, -- IBUS_ENGINE_PREEDIT_CLEAR, -- ibusimcontext); -+ preedit_string = g_strdup (ibusimcontext->preedit_string); -+ } -+ _ibus_context_update_preedit_text_cb (ibusimcontext->ibuscontext, -+ ibus_text_new_from_string (""), -+ 0, -+ FALSE, -+ IBUS_ENGINE_PREEDIT_CLEAR, -+ ibusimcontext); -+ if (preedit_string) { - g_signal_emit (ibusimcontext, _signal_commit_id, 0, preedit_string); - g_free (preedit_string); - _request_surrounding_text (ibusimcontext); -@@ -1114,12 +1117,9 @@ ibus_im_context_button_press_event_cb (GtkWidget *widget, - if (event->button != 1) - return FALSE; - -- if (ibusimcontext->preedit_visible && -- ibusimcontext->preedit_mode == IBUS_ENGINE_PREEDIT_COMMIT) { -- ibus_im_context_clear_preedit_text (ibusimcontext); -- if (ibusimcontext->ibuscontext) -- ibus_input_context_reset (ibusimcontext->ibuscontext); -- } -+ ibus_im_context_clear_preedit_text (ibusimcontext); -+ if (ibusimcontext->ibuscontext) -+ ibus_input_context_reset (ibusimcontext->ibuscontext); - return FALSE; - } - --- -2.24.1 - -From c7d8771cb9fc652cb638aa7cb8e10ea6b889509e Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 11 Dec 2018 19:16:10 +0900 -Subject: [PATCH] client/gtk2: Fix SEGV on mouse clicks when ibus-daemon not - running - ---- - client/gtk2/ibusimcontext.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c -index ed7fea6e..ab7ff88a 100644 ---- a/client/gtk2/ibusimcontext.c -+++ b/client/gtk2/ibusimcontext.c -@@ -1117,9 +1117,10 @@ ibus_im_context_button_press_event_cb (GtkWidget *widget, - if (event->button != 1) - return FALSE; - -- ibus_im_context_clear_preedit_text (ibusimcontext); -- if (ibusimcontext->ibuscontext) -+ if (ibusimcontext->ibuscontext) { -+ ibus_im_context_clear_preedit_text (ibusimcontext); - ibus_input_context_reset (ibusimcontext->ibuscontext); -+ } - return FALSE; - } - --- -2.24.1 - -From 9ae2d4658fff3d1e7262fb4fb7ca9ce1af0a27ec Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Thu, 20 Dec 2018 16:40:31 +0900 -Subject: [PATCH] client/gtk2: Use button-press-event only with - IBUS_ENGINE_PREEDIT_COMMIT - -BUG=https://github.com/ibus/ibus/issues/1980 ---- - client/gtk2/ibusimcontext.c | 66 ++++++++++++++++++++++++------------- - 1 file changed, 43 insertions(+), 23 deletions(-) - -diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c -index ab7ff88a..f9310867 100644 ---- a/client/gtk2/ibusimcontext.c -+++ b/client/gtk2/ibusimcontext.c -@@ -72,6 +72,8 @@ struct _IBusIMContext { - /* cancellable */ - GCancellable *cancellable; - GQueue *events_queue; -+ -+ gboolean use_button_press_event; - }; - - struct _IBusIMContextClass { -@@ -1109,6 +1111,7 @@ ibus_im_context_get_preedit_string (GtkIMContext *context, - } - - -+#if !GTK_CHECK_VERSION (3, 93, 0) - static gboolean - ibus_im_context_button_press_event_cb (GtkWidget *widget, - GdkEventButton *event, -@@ -1124,13 +1127,37 @@ ibus_im_context_button_press_event_cb (GtkWidget *widget, - return FALSE; - } - -+static void -+_connect_button_press_event (IBusIMContext *ibusimcontext, -+ gboolean do_connect) -+{ -+ GtkWidget *widget = NULL; -+ -+ g_assert (ibusimcontext->client_window); -+ gdk_window_get_user_data (ibusimcontext->client_window, -+ (gpointer *)&widget); -+ /* firefox needs GtkWidget instead of GtkWindow */ -+ if (GTK_IS_WIDGET (widget)) { -+ if (do_connect) { -+ g_signal_connect ( -+ widget, -+ "button-press-event", -+ G_CALLBACK (ibus_im_context_button_press_event_cb), -+ ibusimcontext); -+ } else { -+ g_signal_handlers_disconnect_by_func ( -+ widget, -+ G_CALLBACK (ibus_im_context_button_press_event_cb), -+ ibusimcontext); -+ } -+ } -+} -+#endif -+ - static void - ibus_im_context_set_client_window (GtkIMContext *context, GdkWindow *client) - { - IBusIMContext *ibusimcontext; --#if !GTK_CHECK_VERSION (3, 93, 0) -- GtkWidget *widget; --#endif - - IDEBUG ("%s", __FUNCTION__); - -@@ -1138,15 +1165,8 @@ ibus_im_context_set_client_window (GtkIMContext *context, GdkWindow *client) - - if (ibusimcontext->client_window) { - #if !GTK_CHECK_VERSION (3, 93, 0) -- gdk_window_get_user_data (ibusimcontext->client_window, -- (gpointer *)&widget); -- /* firefox needs GtkWidget instead of GtkWindow */ -- if (GTK_IS_WIDGET (widget)) { -- g_signal_handlers_disconnect_by_func ( -- widget, -- (GCallback)ibus_im_context_button_press_event_cb, -- ibusimcontext); -- } -+ if (ibusimcontext->use_button_press_event) -+ _connect_button_press_event (ibusimcontext, FALSE); - #endif - g_object_unref (ibusimcontext->client_window); - ibusimcontext->client_window = NULL; -@@ -1155,17 +1175,8 @@ ibus_im_context_set_client_window (GtkIMContext *context, GdkWindow *client) - if (client != NULL) { - ibusimcontext->client_window = g_object_ref (client); - #if !GTK_CHECK_VERSION (3, 93, 0) -- gdk_window_get_user_data (ibusimcontext->client_window, -- (gpointer *)&widget); -- -- /* firefox needs GtkWidget instead of GtkWindow */ -- if (GTK_IS_WIDGET (widget)) { -- g_signal_connect ( -- widget, -- "button-press-event", -- G_CALLBACK (ibus_im_context_button_press_event_cb), -- ibusimcontext); -- } -+ if (ibusimcontext->use_button_press_event) -+ _connect_button_press_event (ibusimcontext, TRUE); - #endif - } - if (ibusimcontext->slave) -@@ -1631,6 +1642,15 @@ _ibus_context_update_preedit_text_cb (IBusInputContext *ibuscontext, - ibusimcontext->preedit_attrs = NULL; - } - -+ if (!ibusimcontext->use_button_press_event && -+ mode == IBUS_ENGINE_PREEDIT_COMMIT) { -+#if !GTK_CHECK_VERSION (3, 93, 0) -+ if (ibusimcontext->client_window) -+ _connect_button_press_event (ibusimcontext, TRUE); -+#endif -+ ibusimcontext->use_button_press_event = TRUE; -+ } -+ - str = text->text; - ibusimcontext->preedit_string = g_strdup (str); - if (text->attrs) { --- -2.24.1 - -From 0fd043c3b4c90855bfb4fceed4bf2f3c3635a041 Mon Sep 17 00:00:00 2001 -From: fujiwarat -Date: Tue, 8 Jan 2019 12:02:32 +0900 -Subject: [PATCH] portal: Update APIs for Hangul preedit in Flatpak - -BUG=https://github.com/ibus/ibus/issues/1980 ---- - portal/org.freedesktop.IBus.Portal.xml | 9 ++++++++- - portal/portal.c | 18 +++++++++++++++++- - 2 files changed, 25 insertions(+), 2 deletions(-) - -diff --git a/portal/org.freedesktop.IBus.Portal.xml b/portal/org.freedesktop.IBus.Portal.xml -index afce4daa..376ad424 100644 ---- a/portal/org.freedesktop.IBus.Portal.xml -+++ b/portal/org.freedesktop.IBus.Portal.xml -@@ -1,6 +1,6 @@ - -