public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/ibus] autotool: Add some new features
@ 2026-05-31 2:07 Takao Fujiwara
0 siblings, 0 replies; only message in thread
From: Takao Fujiwara @ 2026-05-31 2:07 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/ibus
Branch : autotool
Commit : ebbfbeae2909e68c3b6f8165302a2620fb55e45f
Author : Takao Fujiwara <tfujiwar@redhat.com>
Date : 2022-07-07T08:47:31+09:00
Stats : +1942/-213 in 3 file(s)
URL : https://src.fedoraproject.org/rpms/ibus/c/ebbfbeae2909e68c3b6f8165302a2620fb55e45f?branch=autotool
Log:
Add some new features
- Add IBUS_CAP_OSK to IBusCapabilite
- Update ibus restart for --service-file option
- Update manpage for ibus im-module command
- Implement new process_key_event for GTK4
- Add focus_in_id()/focus_out_id() class methods in IBusEngine
---
diff --git a/ibus-1385349-segv-bus-proxy.patch b/ibus-1385349-segv-bus-proxy.patch
index 7a2b140..1f16094 100644
--- a/ibus-1385349-segv-bus-proxy.patch
+++ b/ibus-1385349-segv-bus-proxy.patch
@@ -1,6 +1,6 @@
-From fd69784c0ed45fe11b801f3a563231735920896a Mon Sep 17 00:00:00 2001
+From c093fec83da277c79f31e09b1b910d35bd4135c8 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Mon, 23 May 2022 21:50:16 +0900
+Date: Sat, 25 Jun 2022 19:46:01 +0900
Subject: [PATCH] Fix SEGV in bus_panel_proxy_focus_in()
rhbz#1350291 SEGV in BUS_IS_CONNECTION(skip_connection) in
@@ -42,12 +42,12 @@ BUG=rhbz#1767976
BUG=rhbz#1797120
---
bus/dbusimpl.c | 47 ++++++++++++++++++++++++---
- bus/engineproxy.c | 51 ++++++++++++++++++++++-------
+ bus/engineproxy.c | 44 +++++++++++++++++++------
client/x11/main.c | 8 ++++-
src/ibusbus.c | 6 ++++
ui/gtk3/extension.vala | 4 +++
ui/gtk3/switcher.vala | 73 +++++++++++++++++++++++++-----------------
- 6 files changed, 142 insertions(+), 47 deletions(-)
+ 6 files changed, 137 insertions(+), 45 deletions(-)
diff --git a/bus/dbusimpl.c b/bus/dbusimpl.c
index 59787a80..af2fbde2 100644
@@ -138,10 +138,10 @@ index 59787a80..af2fbde2 100644
if (incoming) {
/* is incoming message */
diff --git a/bus/engineproxy.c b/bus/engineproxy.c
-index 2d98995c..bbbe5532 100644
+index fd1f34fb..57c061ba 100644
--- a/bus/engineproxy.c
+++ b/bus/engineproxy.c
-@@ -660,20 +660,33 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy,
+@@ -690,10 +690,12 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy,
g_return_if_reached ();
}
@@ -153,16 +153,14 @@ index 2d98995c..bbbe5532 100644
+ GDBusConnection *connection,
+ GError **error)
{
-+ GDBusProxyFlags flags;
-+ BusEngineProxy *engine;
-+
+ GDBusProxyFlags flags;
+ BusEngineProxy *engine;
+@@ -704,12 +706,20 @@ bus_engine_proxy_new_internal (const gchar *path,
g_assert (path);
g_assert (IBUS_IS_ENGINE_DESC (desc));
g_assert (G_IS_DBUS_CONNECTION (connection));
+ 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,
@@ -170,19 +168,19 @@ index 2d98995c..bbbe5532 100644
+ "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,
- "desc", desc,
- "g-connection", connection,
- "g-interface-name", IBUS_INTERFACE_ENGINE,
-@@ -681,12 +694,19 @@ bus_engine_proxy_new_internal (const gchar *path,
- "g-default-timeout", g_gdbus_timeout,
- "g-flags", flags,
- NULL);
+ flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
+ engine = (BusEngineProxy *) g_initable_new (
+ BUS_TYPE_ENGINE_PROXY,
+ NULL,
+- NULL,
++ error,
+ "desc", desc,
+ "g-connection", connection,
+ "g-interface-name", IBUS_INTERFACE_ENGINE,
+@@ -717,6 +727,12 @@ bus_engine_proxy_new_internal (const gchar *path,
+ "g-default-timeout", g_gdbus_timeout,
+ "g-flags", flags,
+ NULL);
+ /* FIXME: rhbz#1601577 */
+ if (!engine) {
+ /* show abrt local variable */
@@ -192,6 +190,7 @@ index 2d98995c..bbbe5532 100644
const gchar *layout = ibus_engine_desc_get_layout (desc);
if (layout != NULL && layout[0] != '\0') {
engine->keymap = ibus_keymap_get (layout);
+@@ -736,6 +752,7 @@ bus_engine_proxy_new_internal (const gchar *path,
}
return engine;
}
@@ -199,7 +198,7 @@ index 2d98995c..bbbe5532 100644
typedef struct {
GTask *task;
-@@ -748,23 +768,30 @@ create_engine_ready_cb (BusFactoryProxy *factory,
+@@ -798,23 +815,30 @@ create_engine_ready_cb (BusFactoryProxy *factory,
GAsyncResult *res,
EngineProxyNewData *data)
{
@@ -401,5 +400,5 @@ index a4529c88..29a70dd5 100644
#if VALA_0_34
seat.ungrab();
--
-2.35.1
+2.35.3
diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch
index 2e08e8c..dc9f150 100644
--- a/ibus-HEAD.patch
+++ b/ibus-HEAD.patch
@@ -1782,9 +1782,83 @@ index 101c2b3d..452b14c8 100644
--
2.35.3
-From 78ce092914e00d6af3b2b90263dd6f41de75741e Mon Sep 17 00:00:00 2001
+From b94f0c1cea5d0e423fef3bcc13b23f212f04c930 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Sat, 25 Jun 2022 20:48:50 +0900
+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.
+---
+ src/ibusaccelgroup.c | 14 +++++++-------
+ src/ibustypes.h | 2 ++
+ 2 files changed, 9 insertions(+), 7 deletions(-)
+
+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
+- * “<Control>a” or “<Shift><Alt>F1” or “<Release>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 “<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>-”.
++ * 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 “<Control>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.35.3
+
+From 4e48e7237d73d20f0426265dbb6b692b14891932 Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Thu, 7 Jul 2022 08:21:24 +0900
Subject: [PATCH] tools: Enable ibus restart in GNOME desktop
If ibus-daemon is called via systemd, IBus restart API cannot restart
@@ -1792,11 +1866,13 @@ ibus-daemon but just terminates it.
Now ibus restart command checks the systemd avaiability and restart
ibus-daemon via systemd.
ibus start command is also added to launch ibus-daemon with systemd.
+
+BUG=https://github.com/ibus/ibus/issues/2407
---
tools/Makefile.am | 3 +-
tools/ibus.1.in | 30 +++++-
- tools/main.vala | 231 ++++++++++++++++++++++++++++++++++++++++++++--
- 3 files changed, 252 insertions(+), 12 deletions(-)
+ tools/main.vala | 261 ++++++++++++++++++++++++++++++++++++++++++++--
+ 3 files changed, 330 insertions(+), 44 deletions(-)
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 5c18d3d6..e380a9aa 100644
@@ -1820,7 +1896,7 @@ index 5c18d3d6..e380a9aa 100644
--pkg=posix \
--pkg=config \
diff --git a/tools/ibus.1.in b/tools/ibus.1.in
-index 525d972e..0c16a0d2 100644
+index 525d972e..fe1b7157 100644
--- a/tools/ibus.1.in
+++ b/tools/ibus.1.in
@@ -3,7 +3,7 @@
@@ -1828,7 +1904,7 @@ index 525d972e..0c16a0d2 100644
.\" Copyright (c) Peng Huang <shawn.p.huang@gmail.com>, 2013.
.\"
-.TH "IBUS" 1 "May 2017" "@VERSION@" "User Commands"
-+.TH "IBUS" 1 "Jun 2022" "@VERSION@" "User Commands"
++.TH "IBUS" 1 "Jul 2022" "@VERSION@" "User Commands"
.SH NAME
.B ibus
\- command line utility for ibus
@@ -1879,7 +1955,7 @@ index 525d972e..0c16a0d2 100644
.B \-\-system
is not given.
diff --git a/tools/main.vala b/tools/main.vala
-index 26e7fd88..71134334 100644
+index 26e7fd88..407eaf74 100644
--- a/tools/main.vala
+++ b/tools/main.vala
@@ -3,7 +3,7 @@
@@ -1891,7 +1967,7 @@ index 26e7fd88..71134334 100644
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
-@@ -27,17 +27,22 @@ private const string IBUS_SCHEMAS_GENERAL_HOTKEY =
+@@ -27,17 +27,23 @@ private const string IBUS_SCHEMAS_GENERAL_HOTKEY =
private const string IBUS_SCHEMAS_PANEL = "org.freedesktop.ibus.panel";
private const string IBUS_SCHEMAS_PANEL_EMOJI =
"org.freedesktop.ibus.panel.emoji";
@@ -1905,6 +1981,7 @@ index 26e7fd88..71134334 100644
string engine_id = null;
+bool verbose = false;
+string daemon_type = null;
++string systemd_service_file = null;
class EngineList {
public IBus.EngineDesc[] data = {};
@@ -1914,7 +1991,7 @@ index 26e7fd88..71134334 100644
IBus.Bus? get_bus() {
var bus = new IBus.Bus();
if (!bus.is_connected ())
-@@ -45,6 +50,123 @@ IBus.Bus? get_bus() {
+@@ -45,6 +51,131 @@ IBus.Bus? get_bus() {
return bus;
}
@@ -1933,14 +2010,14 @@ index 26e7fd88..71134334 100644
+get_ibus_systemd_object_path(GLib.DBusConnection connection,
+ bool verbose) {
+ string object_path = null;
-+ const string service_file = SYSTEMD_SESSION_GNOME_FILE;
++ assert(systemd_service_file != null);
+ try {
+ var variant = connection.call_sync (
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetUnit",
-+ new GLib.Variant("(s)", service_file),
++ new GLib.Variant("(s)", systemd_service_file),
+ new GLib.VariantType("(o)"),
+ GLib.DBusCallFlags.NONE,
+ -1,
@@ -1949,13 +2026,14 @@ index 26e7fd88..71134334 100644
+ if (verbose) {
+ stderr.printf("Succeed to get an object path \"%s\" for IBus " +
+ "systemd service file \"%s\".\n",
-+ object_path, service_file);
++ object_path, systemd_service_file);
+ }
+ return object_path;
+ } catch (GLib.Error e) {
+ if (verbose) {
+ stderr.printf("IBus systemd service file \"%s\" is not installed " +
-+ "in your system: %s\n", service_file, e.message);
++ "in your system: %s\n",
++ systemd_service_file, e.message);
+ }
+ }
+ return null;
@@ -1968,24 +2046,29 @@ index 26e7fd88..71134334 100644
+ bool verbose) {
+ string? state = null;
+ try {
-+ var variant = connection.call_sync (
-+ "org.freedesktop.systemd1",
-+ object_path,
-+ "org.freedesktop.DBus.Properties",
-+ "Get",
-+ new GLib.Variant("(ss)",
-+ "org.freedesktop.systemd1.Unit",
-+ "ActiveState"),
-+ new GLib.VariantType("(v)"),
-+ GLib.DBusCallFlags.NONE,
-+ -1,
-+ null);
-+ GLib.Variant child = null;
-+ variant.get("(v)", ref child);
-+ state = child.dup_string();
-+ if (verbose) {
-+ stderr.printf("Succeed to get the state \"%s\" for an object " +
-+ "path \"%s\".\n", state, object_path);
++ while (true) {
++ var variant = connection.call_sync (
++ "org.freedesktop.systemd1",
++ object_path,
++ "org.freedesktop.DBus.Properties",
++ "Get",
++ new GLib.Variant("(ss)",
++ "org.freedesktop.systemd1.Unit",
++ "ActiveState"),
++ new GLib.VariantType("(v)"),
++ GLib.DBusCallFlags.NONE,
++ -1,
++ null);
++ GLib.Variant child = null;
++ variant.get("(v)", ref child);
++ state = child.dup_string();
++ if (verbose) {
++ stderr.printf("systemd state is \"%s\" for an object " +
++ "path \"%s\".\n", state, object_path);
++ }
++ if (state != "activating")
++ break;
++ Posix.sleep(1);
+ }
+ } catch (GLib.Error e) {
+ if (verbose)
@@ -2003,8 +2086,8 @@ index 26e7fd88..71134334 100644
+ bool restart,
+ bool verbose) {
+ string object_path = null;
-+ const string service_file = SYSTEMD_SESSION_GNOME_FILE;
+ string method = "StartUnit";
++ assert(systemd_service_file != null);
+ if (restart)
+ method = "RestartUnit";
+ try {
@@ -2013,7 +2096,7 @@ index 26e7fd88..71134334 100644
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ method,
-+ new GLib.Variant("(ss)", service_file, "fail"),
++ new GLib.Variant("(ss)", systemd_service_file, "fail"),
+ new GLib.VariantType("(o)"),
+ GLib.DBusCallFlags.NONE,
+ -1,
@@ -2022,13 +2105,15 @@ index 26e7fd88..71134334 100644
+ if (verbose) {
+ stderr.printf("Succeed to restart IBus daemon via IBus systemd " +
+ "service file \"%s\": \"%s\"\n",
-+ service_file, object_path);
++ systemd_service_file, object_path);
+ }
+ return true;
+ } catch (GLib.Error e) {
+ if (verbose) {
-+ stderr.printf("Failed to restart IBus daemon via IBus systemd " +
-+ "service file \"%s\": %s\n", service_file, e.message);
++ stderr.printf("Failed to %s IBus daemon via IBus systemd " +
++ "service file \"%s\": %s\n",
++ restart ? "restart" : "start",
++ systemd_service_file, e.message);
+ }
+ }
+ return false;
@@ -2038,7 +2123,7 @@ index 26e7fd88..71134334 100644
int list_engine(string[] argv) {
const OptionEntry[] options = {
{ "name-only", 0, 0, OptionArg.NONE, out name_only,
-@@ -99,6 +221,7 @@ int list_engine(string[] argv) {
+@@ -99,6 +230,7 @@ int list_engine(string[] argv) {
return Posix.EXIT_SUCCESS;
}
@@ -2046,7 +2131,7 @@ index 26e7fd88..71134334 100644
private int exec_setxkbmap(IBus.EngineDesc engine) {
string layout = engine.get_layout();
string variant = engine.get_layout_variant();
-@@ -149,6 +272,7 @@ private int exec_setxkbmap(IBus.EngineDesc engine) {
+@@ -149,6 +281,7 @@ private int exec_setxkbmap(IBus.EngineDesc engine) {
return Posix.EXIT_SUCCESS;
}
@@ -2054,7 +2139,7 @@ index 26e7fd88..71134334 100644
int get_set_engine(string[] argv) {
var bus = get_bus();
string engine = null;
-@@ -182,20 +306,100 @@ int get_set_engine(string[] argv) {
+@@ -182,20 +315,121 @@ int get_set_engine(string[] argv) {
return Posix.EXIT_SUCCESS;
}
@@ -2074,6 +2159,9 @@ index 26e7fd88..71134334 100644
+ { "type", 0, 0, OptionArg.STRING, out daemon_type,
+ N_("Start or restart daemon with \"direct\" or \"systemd\" TYPE."),
+ "TYPE" },
++ { "service-file", 0, 0, OptionArg.STRING, out systemd_service_file,
++ N_("Start or restart daemon with SYSTEMD_SERVICE file."),
++ "SYSTEMD_SERVICE" },
+ { "verbose", 0, 0, OptionArg.NONE, out verbose,
+ N_("Show debug messages."), null },
+ { null }
@@ -2094,6 +2182,8 @@ index 26e7fd88..71134334 100644
+ stderr.printf("type argument must be \"direct\" or \"systemd\"\n");
+ return Posix.EXIT_FAILURE;
+ }
++ if (systemd_service_file == null)
++ systemd_service_file = SYSTEMD_SESSION_GNOME_FILE;
+
+ do {
+ if (daemon_type == "direct")
@@ -2101,19 +2191,35 @@ index 26e7fd88..71134334 100644
+ GLib.DBusConnection? connection = get_session_bus(verbose);
+ if (connection == null)
+ break;
-+ string? object_path = get_ibus_systemd_object_path(connection, verbose);
++ string? object_path = null;
++ if (restart) {
++ object_path = get_ibus_systemd_object_path(connection, verbose);
++ if (object_path == null)
++ break;
++ if (!is_running_daemon_via_systemd(connection,
++ object_path,
++ verbose)) {
++ break;
++ }
++ }
++ if (!start_daemon_via_systemd(connection, restart, verbose))
++ break;
++ // Do not check the systemd state in case of restart because
++ // the systemd file validation is already done and also stopping
++ // daemon and starting daemon take time and the state could be
++ // "inactive" with the time lag.
++ if (restart)
++ return Posix.EXIT_SUCCESS;
++ object_path = get_ibus_systemd_object_path(connection, verbose);
+ if (object_path == null)
+ break;
-+ if (restart &&
-+ !is_running_daemon_via_systemd(connection, object_path, verbose))
++ if (!is_running_daemon_via_systemd(connection, object_path, verbose))
+ break;
-+ if (start_daemon_via_systemd(connection, restart, verbose))
-+ return Posix.EXIT_SUCCESS;
- return Posix.EXIT_FAILURE;
++ return Posix.EXIT_SUCCESS;
+ } while (false);
+
+ if (daemon_type == "systemd")
-+ return Posix.EXIT_FAILURE;
+ return Posix.EXIT_FAILURE;
+ if (restart) {
+ var bus = get_bus();
+ if (bus == null) {
@@ -2160,7 +2266,7 @@ index 26e7fd88..71134334 100644
int exit_daemon(string[] argv) {
var bus = get_bus();
if (bus == null) {
-@@ -206,11 +410,13 @@ int exit_daemon(string[] argv) {
+@@ -206,11 +440,13 @@ int exit_daemon(string[] argv) {
return Posix.EXIT_SUCCESS;
}
@@ -2174,7 +2280,7 @@ index 26e7fd88..71134334 100644
int read_cache (string[] argv) {
const OptionEntry[] options = {
{ "system", 0, 0, OptionArg.NONE, out is_system,
-@@ -251,6 +457,7 @@ int read_cache (string[] argv) {
+@@ -251,6 +487,7 @@ int read_cache (string[] argv) {
return Posix.EXIT_SUCCESS;
}
@@ -2182,7 +2288,7 @@ index 26e7fd88..71134334 100644
int write_cache (string[] argv) {
const OptionEntry[] options = {
{ "system", 0, 0, OptionArg.NONE, out is_system,
-@@ -283,12 +490,14 @@ int write_cache (string[] argv) {
+@@ -283,12 +520,14 @@ int write_cache (string[] argv) {
Posix.EXIT_SUCCESS : Posix.EXIT_FAILURE;
}
@@ -2197,7 +2303,7 @@ index 26e7fd88..71134334 100644
private int read_config_options(string[] argv) {
const OptionEntry[] options = {
{ "engine-id", 0, 0, OptionArg.STRING, out engine_id,
-@@ -309,6 +518,7 @@ private int read_config_options(string[] argv) {
+@@ -309,6 +548,7 @@ private int read_config_options(string[] argv) {
return Posix.EXIT_SUCCESS;
}
@@ -2205,7 +2311,7 @@ index 26e7fd88..71134334 100644
private GLib.SList<string> get_ibus_schemas() {
string[] ids = {};
if (engine_id != null) {
-@@ -342,6 +552,7 @@ private GLib.SList<string> get_ibus_schemas() {
+@@ -342,6 +582,7 @@ private GLib.SList<string> get_ibus_schemas() {
return ibus_schemas;
}
@@ -2213,7 +2319,7 @@ index 26e7fd88..71134334 100644
int read_config(string[] argv) {
if (read_config_options(argv) == Posix.EXIT_FAILURE)
return Posix.EXIT_FAILURE;
-@@ -370,6 +581,7 @@ int read_config(string[] argv) {
+@@ -370,6 +611,7 @@ int read_config(string[] argv) {
return Posix.EXIT_SUCCESS;
}
@@ -2221,7 +2327,7 @@ index 26e7fd88..71134334 100644
int reset_config(string[] argv) {
if (read_config_options(argv) == Posix.EXIT_FAILURE)
return Posix.EXIT_FAILURE;
-@@ -401,6 +613,7 @@ int reset_config(string[] argv) {
+@@ -401,6 +643,7 @@ int reset_config(string[] argv) {
return Posix.EXIT_SUCCESS;
}
@@ -2229,7 +2335,7 @@ index 26e7fd88..71134334 100644
#if EMOJI_DICT
int emoji_dialog(string[] argv) {
string cmd = Config.LIBEXECDIR + "/ibus-ui-emojier";
-@@ -427,11 +640,13 @@ int emoji_dialog(string[] argv) {
+@@ -427,11 +670,13 @@ int emoji_dialog(string[] argv) {
}
#endif
@@ -2243,7 +2349,7 @@ index 26e7fd88..71134334 100644
delegate int EntryFunc(string[] argv);
struct CommandEntry {
-@@ -440,12 +655,14 @@ struct CommandEntry {
+@@ -440,12 +685,14 @@ struct CommandEntry {
unowned EntryFunc entry;
}
@@ -2258,7 +2364,7 @@ index 26e7fd88..71134334 100644
{ "version", N_("Show version"), print_version },
{ "read-cache", N_("Show the content of registry cache"), read_cache },
{ "write-cache", N_("Create registry cache"), write_cache },
-@@ -460,6 +677,7 @@ const CommandEntry commands[] = {
+@@ -460,6 +707,7 @@ const CommandEntry commands[] = {
static string program_name;
@@ -2266,7 +2372,7 @@ index 26e7fd88..71134334 100644
void print_usage(FileStream stream) {
stream.printf(_("Usage: %s COMMAND [OPTION...]\n\n"), program_name);
stream.printf(_("Commands:\n"));
-@@ -470,6 +688,7 @@ void print_usage(FileStream stream) {
+@@ -470,6 +718,7 @@ void print_usage(FileStream stream) {
}
}
@@ -2277,67 +2383,9 @@ index 26e7fd88..71134334 100644
--
2.35.3
-From 6203b6c4e1d41e731bdccb1338ed45c93bc56903 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Tue, 21 Jun 2022 00:49:46 +0900
-Subject: [PATCH] src/tests: Unset G_MESSAGES_DEBUG for gsettings in
- xkb-latin-layouts
-
-gsettings cannot get the key value when G_MESSAGES_DEBUG is enabled.
-Add denylist.txt to engine/Makefile.am
----
- engine/Makefile.am | 3 ++-
- src/tests/xkb-latin-layouts | 7 +++++++
- 2 files changed, 9 insertions(+), 1 deletion(-)
-
-diff --git a/engine/Makefile.am b/engine/Makefile.am
-index 03867f52..7256fbc8 100644
---- a/engine/Makefile.am
-+++ b/engine/Makefile.am
-@@ -4,7 +4,7 @@
- #
- # Copyright (c) 2010-2016, Google Inc. All rights reserved.
- # Copyright (c) 2007-2016 Peng Huang <shawn.p.huang@gmail.com>
--# Copyright (c) 2013-2020 Takao Fujiwara <takao.fujiwara1@gmail.com>
-+# Copyright (c) 2013-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
- #
- # This library is free software; you can redistribute it and/or
- # modify it under the terms of the GNU Lesser General Public
-@@ -88,6 +88,7 @@ CLEANFILES = \
- $(NULL)
-
- EXTRA_DIST = \
-+ denylist.txt \
- gensimple.py \
- iso639converter.py \
- simple.xml.in \
-diff --git a/src/tests/xkb-latin-layouts b/src/tests/xkb-latin-layouts
-index f8dced6b..92464234 100755
---- a/src/tests/xkb-latin-layouts
-+++ b/src/tests/xkb-latin-layouts
-@@ -82,9 +82,16 @@ finit()
-
- test_xkb_keymaps()
- {
-+ # G_MESSAGES_DEBUG=all or G_MESSAGES_DEBUG=GLib-GIO-DEBUG would append
-+ # debug messages to gsettings output and could not get the result correctly.
-+ backup_G_MESSAGES_DEBUG="$G_MESSAGES_DEBUG"
-+ unset G_MESSAGES_DEBUG
- # Loop over top level schemas since "gsettings list-recursively" only
- # looks for direct children.
- xkb_latin_layouts=`gsettings get org.freedesktop.ibus.general xkb-latin-layouts`
-+ if [ x"$backup_G_MESSAGES_DEBUG" != x ] ; then
-+ export G_MESSAGES_DEBUG=$backup_G_MESSAGES_DEBUG
-+ fi
- while read keymap ; do
- eval keymap="$keymap"
- HAS_VARIANT=$($ECHO "$keymap" | grep '(' 2> /dev/null) ||:
---
-2.35.3
-
-From 65a70a49416a5a2f0fe75815cafce68ca39ee1f1 Mon Sep 17 00:00:00 2001
+From 5b441fabc9d766e694b992e0e2f28924d00a7402 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
-Date: Wed, 29 Jun 2022 15:36:12 +0900
+Date: Thu, 7 Jul 2022 08:22:26 +0900
Subject: [PATCH] tools: Add ibus im-module command
ibus im-module command can retrive gtk-im-module value from an
@@ -2345,14 +2393,15 @@ instance of GtkIMMultiContext.
The GTK version can be specified by --type option and the default
is --type=gtk3 and GTK3 im-ibus.so is dlopened.
---
- client/gtk2/ibusim.c | 20 +++++++
- client/gtk4/ibusim.c | 20 +++++++
- tools/IBusIMModule-1.0.metadata | 1 +
- tools/Makefile.am | 92 ++++++++++++++++++++++++++++++---
- tools/ibusimmodule.c | 84 ++++++++++++++++++++++++++++++
- tools/ibusimmodule.h | 36 +++++++++++++
- tools/main.vala | 15 ++++++
- 7 files changed, 262 insertions(+), 6 deletions(-)
+ client/gtk2/ibusim.c | 20 ++++++
+ client/gtk4/ibusim.c | 20 ++++++
+ tools/IBusIMModule-1.0.metadata | 1 +
+ tools/Makefile.am | 116 ++++++++++++++++++++++++++------
+ tools/ibus.1.in | 10 +++
+ tools/ibusimmodule.c | 87 ++++++++++++++++++++++++
+ tools/ibusimmodule.h | 36 ++++++++++
+ tools/main.vala | 11 +++
+ 8 files changed, 308 insertions(+), 40 deletions(-)
create mode 100644 tools/IBusIMModule-1.0.metadata
create mode 100644 tools/ibusimmodule.c
create mode 100644 tools/ibusimmodule.h
@@ -2421,42 +2470,110 @@ index 00000000..14adc9ee
@@ -0,0 +1 @@
+IBusIMModule cheader_filename="ibusimmodule.h" name="IBusIMModule"
diff --git a/tools/Makefile.am b/tools/Makefile.am
-index e380a9aa..f96f2ba2 100644
+index e380a9aa..a9262ee0 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
-@@ -22,6 +22,12 @@
- # USA
-
+@@ -24,9 +24,19 @@
NULL =
-+noinst_LTLIBRARIES =
+
+ libibus = $(top_builddir)/src/libibus-@IBUS_API_VERSION@.la
++libibusimmodule = libibusimmodule.la
++ibusimmodule_gir = IBusIMModule-1.0.gir
++ibus_immodule_vapi = ibus-immodule-1.0.vapi
+ libibus_emoji_dialog = \
+ $(top_builddir)/ui/gtk3/libibus-emoji-dialog-@IBUS_API_VERSION@.la
+
++noinst_LTLIBRARIES = $(libibusimmodule)
+noinst_DATA =
+INTROSPECTION_GIRS =
+MAINTAINERCLEANFILES =
+DISTCLEANFILES =
+VAPIGEN_VAPIS =
++
+ # force include config.h before gi18n.h.
+ AM_CPPFLAGS = \
+ -I$(top_srcdir)/src \
+@@ -47,22 +57,26 @@ AM_CFLAGS = \
+ $(NULL)
+
+ AM_LDADD = \
+- @GOBJECT2_LIBS@ \
+- @GLIB2_LIBS@ \
+- @GIO2_LIBS@ \
+- @GTHREAD2_LIBS@ \
+- $(libibus) \
+- $(NULL)
++ @GOBJECT2_LIBS@ \
++ @GLIB2_LIBS@ \
++ @GIO2_LIBS@ \
++ @GTHREAD2_LIBS@ \
++ $(libibus) \
++ $(libibusimmodule) \
++ $(NULL)
- libibus = $(top_builddir)/src/libibus-@IBUS_API_VERSION@.la
- libibus_emoji_dialog = \
-@@ -57,6 +63,8 @@ AM_LDADD = \
AM_VALAFLAGS = \
- --vapidir=$(top_builddir)/bindings/vala \
- --vapidir=$(top_srcdir)/bindings/vala \
-+ --vapidir=$(builddir) \
-+ --vapidir=$(srcdir) \
- --pkg=gio-2.0 \
- --pkg=ibus-1.0 \
- --pkg=posix \
-@@ -91,14 +99,17 @@ man_onedir = $(mandir)/man1
+- --vapidir=$(top_builddir)/bindings/vala \
+- --vapidir=$(top_srcdir)/bindings/vala \
+- --pkg=gio-2.0 \
+- --pkg=ibus-1.0 \
+- --pkg=posix \
+- --pkg=config \
+- --target-glib="$(VALA_TARGET_GLIB_VERSION)" \
+- $(NULL)
++ --vapidir=$(top_builddir)/bindings/vala \
++ --vapidir=$(top_srcdir)/bindings/vala \
++ --vapidir=$(builddir) \
++ --vapidir=$(srcdir) \
++ --pkg=gio-2.0 \
++ --pkg=ibus-1.0 \
++ --pkg=ibus-immodule-1.0 \
++ --pkg=posix \
++ --pkg=config \
++ --target-glib="$(VALA_TARGET_GLIB_VERSION)" \
++ $(NULL)
+
+ bin_PROGRAMS = ibus
+
+@@ -79,9 +93,27 @@ bash_completion_DATA= \
+ $(NULL)
+ bash_completiondir=@datadir@/bash-completion/completions
+
++libibusimmodule_la_SOURCES = \
++ ibusimmodule.c \
++ ibusimmodule.h \
++ $(NULL)
++libibusimmodule_la_CFLAGS = \
++ @GLIB2_CFLAGS@ \
++ -DGTK2_IM_MODULEDIR=\"$(GTK2_IM_MODULEDIR)\" \
++ -DGTK3_IM_MODULEDIR=\"$(GTK3_IM_MODULEDIR)\" \
++ -DGTK4_IM_MODULEDIR=\"$(GTK4_IM_MODULEDIR)\" \
++ $(NULL)
++libibusimmodule_la_LIBADD = \
++ @GLIB2_LIBS@ \
++ $(NULL)
++libibusimmodule_la_LDFLAGS = \
++ -no-undefined \
++ -export-symbols-regex "ibus_.*" \
++ $(NULL)
++
+ man_one_in_files = ibus.1.in
+ man_one_files = $(man_one_in_files:.1.in=.1)
+-man_one_DATA =$(man_one_files:.1=.1.gz)
++man_one_DATA =$(man_one_files:.1=.1.gz)
+ man_onedir = $(mandir)/man1
+ %.1: %.1.in
+ $(AM_V_GEN) sed \
+@@ -91,14 +123,17 @@ man_onedir = $(mandir)/man1
$(AM_V_GEN) gzip -c $< > $@.tmp && mv $@.tmp $@
EXTRA_DIST = \
- $(man_one_in_files) \
- ibus.bash \
- $(NULL)
++ $(ibus_immodule_vapi) \
++ $(ibusimmodule_gir) \
+ $(man_one_in_files) \
+ ibus.bash \
-+ ibusimmodule.c \
-+ ibusimmodule.h \
+ IBusIMModule-1.0.metadata \
+ $(NULL)
@@ -2470,38 +2587,12 @@ index e380a9aa..f96f2ba2 100644
if ENABLE_EMOJI_DICT
if ENABLE_UI
-@@ -108,4 +119,73 @@ AM_VALAFLAGS += \
+@@ -108,4 +143,43 @@ AM_VALAFLAGS += \
endif
endif
+if HAVE_INTROSPECTION
+BUILT_SOURCES = $(INTROSPECTION_GIRS) $(VAPIGEN_VAPIS)
-+libibusimmodule = libibusimmodule.la
-+noinst_LTLIBRARIES += $(libibusimmodule)
-+
-+AM_LDADD += $(libibusimmodule)
-+AM_VALAFLAGS += \
-+ --define=LIB_IBUS_MODULE \
-+ --pkg=ibus-immodule-1.0 \
-+ $(NULL)
-+
-+libibusimmodule_la_SOURCES = \
-+ ibusimmodule.c \
-+ ibusimmodule.h \
-+ $(NULL)
-+libibusimmodule_la_CFLAGS = \
-+ @GLIB2_CFLAGS@ \
-+ -DGTK2_IM_MODULEDIR=\"$(GTK2_IM_MODULEDIR)\" \
-+ -DGTK3_IM_MODULEDIR=\"$(GTK3_IM_MODULEDIR)\" \
-+ -DGTK4_IM_MODULEDIR=\"$(GTK4_IM_MODULEDIR)\" \
-+ $(NULL)
-+libibusimmodule_la_LIBADD = \
-+ @GLIB2_LIBS@ \
-+ $(NULL)
-+libibusimmodule_la_LDFLAGS = \
-+ -no-undefined \
-+ -export-symbols-regex "ibus_.*" \
-+ $(NULL)
+
+-include $(INTROSPECTION_MAKEFILE)
+INTROSPECTION_SCANNER_ARGS =
@@ -2523,33 +2614,50 @@ index e380a9aa..f96f2ba2 100644
+ -I$(builddir) \
+ $(NULL)
+
-+ibusimmodule_gir = IBusIMModule-1.0.gir
+INTROSPECTION_GIRS += $(ibusimmodule_gir)
+noinst_DATA += $(ibusimmodule_gir)
-+EXTRA_DIST += $(ibusimmodule_gir)
+MAINTAINERCLEANFILES += $(ibusimmodule_gir)
+DISTCLEANFILES += $(ibusimmodule_gir)
+
+-include $(VAPIGEN_MAKEFILE)
+ibus-immodule-1.0.vapi: $(ibusimmodule_gir) IBusIMModule-1.0.metadata
-+ibus_immodule_vapi = ibus-immodule-1.0.vapi
+ibus_immodule_1_0_vapi_DEPS = glib-2.0
+ibus_immodule_1_0_vapi_METADATADIRS = $(srcdir)
+ibus_immodule_1_0_vapi_FILES = IBusIMModule-1.0.gir
+VAPIGEN_VAPIS += $(ibus_immodule_vapi)
+noinst_DATA += $(ibus_immodule_vapi)
-+EXTRA_DIST += $(ibus_immodule_vapi)
+MAINTAINERCLEANFILES += $(ibus_immodule_vapi)
+DISTCLEANFILES += $(ibus_immodule_vapi)
-+
+endif
++
-include $(top_srcdir)/git.mk
+diff --git a/tools/ibus.1.in b/tools/ibus.1.in
+index fe1b7157..84ef5fff 100644
+--- a/tools/ibus.1.in
++++ b/tools/ibus.1.in
+@@ -128,6 +128,16 @@ option enables to match annotations with a partial string. These settings
+ are available with
+ .B ibus\-setup (1)
+ utility.
++.TP
++\fBim-module\fR [\fB\-\-type=TYPE|\-\-help\fR]
++Show an internal im-module value in a virtual GTK application. If IBus is
++installed and configured properly, the output is "ibus". This sub-command
++is useful for some users who build IBus from the source codes and check
++the configurations. Currently the sub-command supports GTK applications only
++and the default is GTK3. If you wish to check a GTK4 application, you can
++specify
++.B \-\-type=gtk4
++option and you can choose one of "gtk2", "gtk3" and "gtk4".
+
+ .SH BUGS
+ If you find a bug, please report it at https://github.com/ibus/ibus/issues
diff --git a/tools/ibusimmodule.c b/tools/ibusimmodule.c
new file mode 100644
-index 00000000..1587af3d
+index 00000000..20ccc748
--- /dev/null
+++ b/tools/ibusimmodule.c
-@@ -0,0 +1,84 @@
+@@ -0,0 +1,87 @@
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <dlfcn.h>
@@ -2558,6 +2666,10 @@ index 00000000..1587af3d
+#define DEFAULT_IM_MODULE_TYPE "gtk3"
+#endif
+
++#define OPTION_TYPE_MESSAGE \
++ N_("Type im-module TYPE = \"gtk2\", \"gtk3\", \"gtk4\". Default is " \
++ "\"gtk3\".")
++
+typedef const char * (* IBusIMGetContextIdFunc) (int *argc, char ***argv);
+
+static char *im_module_type;
@@ -2568,8 +2680,7 @@ index 00000000..1587af3d
+{
+ static const GOptionEntry options[3] = {
+ { "type", (char)0, (int)0, G_OPTION_ARG_STRING, &im_module_type,
-+ N_ ("Type im-module TYPE = \"gtk2\", \"gtk3\", \"gtk4\". " \
-+ "Default is \"" DEFAULT_IM_MODULE_TYPE "\"."),
++ OPTION_TYPE_MESSAGE,
+ "TYPE"},
+ { NULL }
+ };
@@ -2677,22 +2788,18 @@ index 00000000..e762a747
+
+#endif
diff --git a/tools/main.vala b/tools/main.vala
-index 71134334..587f3a09 100644
+index 407eaf74..1fed2440 100644
--- a/tools/main.vala
+++ b/tools/main.vala
-@@ -641,6 +641,19 @@ int emoji_dialog(string[] argv) {
+@@ -671,6 +671,15 @@ int emoji_dialog(string[] argv) {
#endif
+int read_im_module(string[] argv) {
-+#if LIB_IBUS_MODULE
+ string? im_module = IBusIMModule.im_module_get_id(argv);
+ if (im_module == null)
+ return Posix.EXIT_FAILURE;
+ print("%s\n".printf(im_module));
-+#else
-+ print("%s\n".printf(_("Not supported in your system.")));
-+#endif
+ return Posix.EXIT_SUCCESS;
+}
+
@@ -2700,7 +2807,7 @@ index 71134334..587f3a09 100644
int print_help(string[] argv) {
print_usage(stdout);
return Posix.EXIT_SUCCESS;
-@@ -672,6 +685,8 @@ const CommandEntry commands[] = {
+@@ -702,6 +711,8 @@ const CommandEntry commands[] = {
#if EMOJI_DICT
{ "emoji", N_("Save emoji on dialog to clipboard"), emoji_dialog },
#endif
@@ -2712,3 +2819,1619 @@ index 71134334..587f3a09 100644
--
2.35.3
+From 7e42b437c901bb56ca2f776aad5fe65d0d8c246a Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Thu, 7 Jul 2022 08:22:42 +0900
+Subject: [PATCH] client/gtk2: Implement new process_key_event for GTK4
+
+---
+ client/gtk2/ibusimcontext.c | 147 ++++++++++++++++++++++++++++++------
+ src/ibustypes.h | 4 +
+ 2 files changed, 127 insertions(+), 24 deletions(-)
+
+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.35.3
+
+From b14cab3753c6510a0a48eec673aa6eac89c793a1 Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Thu, 7 Jul 2022 08:22:45 +0900
+Subject: [PATCH] src/ibusengine: Add focus_in_id()/focus_out_id() class
+ methods
+
+IBusEngine constructor now has a 'has-focus-id' property and if it's %TRUE,
+IBusEngine::focus_in_id()/focus_out_id() are called instaed of
+IBusEngine::focus_in()/focus_out() and the class method has an object_path
+argument for the unique input context ID and a client argument for
+the client application type likes ibus-gtk, ibus-gtk4, xim.
+---
+ bus/engineproxy.c | 304 +++++++++++++++++++++++++++++-----------
+ bus/engineproxy.h | 12 +-
+ bus/ibusimpl.c | 13 ++
+ bus/ibusimpl.h | 13 +-
+ bus/inputcontext.c | 50 +++++--
+ src/ibusengine.c | 217 ++++++++++++++++++++++++++--
+ src/ibusengine.h | 10 +-
+ src/ibusmarshalers.list | 1 +
+ 8 files changed, 505 insertions(+), 115 deletions(-)
+
+diff --git a/bus/engineproxy.c b/bus/engineproxy.c
+index 2d98995c..fd1f34fb 100644
+--- a/bus/engineproxy.c
++++ b/bus/engineproxy.c
+@@ -2,7 +2,7 @@
+ /* vim:set et sts=4: */
+ /* ibus - The Input Bus
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+- * Copyright (C) 2015-2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
++ * Copyright (C) 2015-2022 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2016 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+@@ -59,6 +59,7 @@ struct _BusEngineProxy {
+
+ /* cached properties */
+ IBusPropList *prop_list;
++ gboolean has_focus_id;
+ };
+
+ struct _BusEngineProxyClass {
+@@ -105,30 +106,35 @@ static IBusText *text_empty = NULL;
+ static IBusPropList *prop_list_empty = NULL;
+
+ /* functions prototype */
+-static void bus_engine_proxy_set_property (BusEngineProxy *engine,
+- guint prop_id,
+- const GValue *value,
+- GParamSpec *pspec);
+-static void bus_engine_proxy_get_property (BusEngineProxy *engine,
+- guint prop_id,
+- GValue *value,
+- GParamSpec *pspec);
++static void bus_engine_proxy_set_property (BusEngineProxy *engine,
++ guint prop_id,
++ const GValue *value,
++ GParamSpec *pspec);
++static void bus_engine_proxy_get_property (BusEngineProxy *engine,
++ guint prop_id,
++ GValue *value,
++ GParamSpec *pspec);
+ static void bus_engine_proxy_real_register_properties
+- (BusEngineProxy *engine,
+- IBusPropList *prop_list);
++ (BusEngineProxy *engine,
++ IBusPropList *prop_list);
+ static void bus_engine_proxy_real_update_property
+- (BusEngineProxy *engine,
+- IBusProperty *prop);
+-static void bus_engine_proxy_real_destroy (IBusProxy *proxy);
+-static void bus_engine_proxy_g_signal (GDBusProxy *proxy,
+- const gchar *sender_name,
+- const gchar *signal_name,
+- GVariant *parameters);
++ (BusEngineProxy *engine,
++ IBusProperty *prop);
++static void bus_engine_proxy_real_destroy (IBusProxy *proxy);
++static void bus_engine_proxy_g_signal (GDBusProxy *proxy,
++ const gchar *sender_name,
++ const gchar *signal_name,
++ GVariant *parameters);
+ static void bus_engine_proxy_initable_iface_init
+- (GInitableIface *initable_iface);
++ (GInitableIface
++ *initable_iface);
++static void bus_engine_proxy_get_has_focus_id
++ (BusEngineProxy *engine);
+
+ G_DEFINE_TYPE_WITH_CODE (BusEngineProxy, bus_engine_proxy, IBUS_TYPE_PROXY,
+- G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, bus_engine_proxy_initable_iface_init)
++ G_IMPLEMENT_INTERFACE (
++ G_TYPE_INITABLE,
++ bus_engine_proxy_initable_iface_init)
+ );
+
+ static GInitableIface *parent_initable_iface = NULL;
+@@ -138,8 +144,10 @@ bus_engine_proxy_class_init (BusEngineProxyClass *class)
+ {
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+- gobject_class->set_property = (GObjectSetPropertyFunc)bus_engine_proxy_set_property;
+- gobject_class->get_property = (GObjectGetPropertyFunc)bus_engine_proxy_get_property;
++ gobject_class->set_property =
++ (GObjectSetPropertyFunc)bus_engine_proxy_set_property;
++ gobject_class->get_property =
++ (GObjectGetPropertyFunc)bus_engine_proxy_get_property;
+
+ class->register_properties = bus_engine_proxy_real_register_properties;
+ class->update_property = bus_engine_proxy_real_update_property;
+@@ -147,8 +155,9 @@ bus_engine_proxy_class_init (BusEngineProxyClass *class)
+ IBUS_PROXY_CLASS (class)->destroy = bus_engine_proxy_real_destroy;
+ G_DBUS_PROXY_CLASS (class)->g_signal = bus_engine_proxy_g_signal;
+
+- parent_initable_iface =
+- (GInitableIface *)g_type_interface_peek (bus_engine_proxy_parent_class, G_TYPE_INITABLE);
++ parent_initable_iface = (GInitableIface *)g_type_interface_peek (
++ bus_engine_proxy_parent_class,
++ G_TYPE_INITABLE);
+
+ /* install properties */
+ g_object_class_install_property (gobject_class,
+@@ -164,7 +173,9 @@ bus_engine_proxy_class_init (BusEngineProxyClass *class)
+ G_PARAM_STATIC_NICK
+ ));
+
+- /* install glib signals that will be sent when corresponding D-Bus signals are sent from an engine process. */
++ /* install glib signals that will be sent when corresponding D-Bus signals
++ * are sent from an engine process.
++ */
+ engine_signals[COMMIT_TEXT] =
+ g_signal_new (I_("commit-text"),
+ G_TYPE_FROM_CLASS (class),
+@@ -473,7 +484,8 @@ bus_engine_proxy_real_destroy (IBusProxy *proxy)
+ engine->prop_list = NULL;
+ }
+
+- IBUS_PROXY_CLASS (bus_engine_proxy_parent_class)->destroy ((IBusProxy *)engine);
++ IBUS_PROXY_CLASS (bus_engine_proxy_parent_class)->destroy (
++ (IBusProxy *)engine);
+ }
+
+ static void
+@@ -486,7 +498,8 @@ _g_object_unref_if_floating (gpointer instance)
+ /**
+ * bus_engine_proxy_g_signal:
+ *
+- * Handle all D-Bus signals from the engine process. This function emits corresponding glib signal for the D-Bus signal.
++ * Handle all D-Bus signals from the engine process. This function emits
++ * corresponding glib signal for the D-Bus signal.
+ */
+ static void
+ bus_engine_proxy_g_signal (GDBusProxy *proxy,
+@@ -522,7 +535,9 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy,
+ }
+ }
+
+- /* Handle D-Bus signals with parameters. Deserialize them and emit a glib signal. */
++ /* Handle D-Bus signals with parameters. Deserialize them and emit a glib
++ * signal.
++ */
+ if (g_strcmp0 (signal_name, "CommitText") == 0) {
+ GVariant *arg0 = NULL;
+ g_variant_get (parameters, "(v)", &arg0);
+@@ -568,7 +583,8 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy,
+ gboolean visible = FALSE;
+ guint mode = 0;
+
+- g_variant_get (parameters, "(vubu)", &arg0, &cursor_pos, &visible, &mode);
++ g_variant_get (parameters, "(vubu)",
++ &arg0, &cursor_pos, &visible, &mode);
+ g_return_if_fail (arg0 != NULL);
+
+ IBusText *text = IBUS_TEXT (ibus_serializable_deserialize (arg0));
+@@ -594,7 +610,11 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy,
+ g_variant_unref (arg0);
+ g_return_if_fail (text != NULL);
+
+- g_signal_emit (engine, engine_signals[UPDATE_AUXILIARY_TEXT], 0, text, visible);
++ g_signal_emit (engine,
++ engine_signals[UPDATE_AUXILIARY_TEXT],
++ 0,
++ text,
++ visible);
+ _g_object_unref_if_floating (text);
+ return;
+ }
+@@ -606,11 +626,16 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy,
+ g_variant_get (parameters, "(vb)", &arg0, &visible);
+ g_return_if_fail (arg0 != NULL);
+
+- IBusLookupTable *table = IBUS_LOOKUP_TABLE (ibus_serializable_deserialize (arg0));
++ IBusLookupTable *table =
++ IBUS_LOOKUP_TABLE (ibus_serializable_deserialize (arg0));
+ g_variant_unref (arg0);
+ g_return_if_fail (table != NULL);
+
+- g_signal_emit (engine, engine_signals[UPDATE_LOOKUP_TABLE], 0, table, visible);
++ g_signal_emit (engine,
++ engine_signals[UPDATE_LOOKUP_TABLE],
++ 0,
++ table,
++ visible);
+ _g_object_unref_if_floating (table);
+ return;
+ }
+@@ -620,11 +645,15 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy,
+ g_variant_get (parameters, "(v)", &arg0);
+ g_return_if_fail (arg0 != NULL);
+
+- IBusPropList *prop_list = IBUS_PROP_LIST (ibus_serializable_deserialize (arg0));
++ IBusPropList *prop_list =
++ IBUS_PROP_LIST (ibus_serializable_deserialize (arg0));
+ g_variant_unref (arg0);
+ g_return_if_fail (prop_list != NULL);
+
+- g_signal_emit (engine, engine_signals[REGISTER_PROPERTIES], 0, prop_list);
++ g_signal_emit (engine,
++ engine_signals[REGISTER_PROPERTIES],
++ 0,
++ prop_list);
+ _g_object_unref_if_floating (prop_list);
+ return;
+ }
+@@ -634,7 +663,8 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy,
+ g_variant_get (parameters, "(v)", &arg0);
+ g_return_if_fail (arg0 != NULL);
+
+- IBusProperty *prop = IBUS_PROPERTY (ibus_serializable_deserialize (arg0));
++ IBusProperty *prop =
++ IBUS_PROPERTY (ibus_serializable_deserialize (arg0));
+ g_variant_unref (arg0);
+ g_return_if_fail (prop != NULL);
+
+@@ -665,26 +695,45 @@ bus_engine_proxy_new_internal (const gchar *path,
+ IBusEngineDesc *desc,
+ GDBusConnection *connection)
+ {
++ GDBusProxyFlags flags;
++ BusEngineProxy *engine;
++ BusIBusImpl *ibus = BUS_DEFAULT_IBUS;
++ GHashTable *hash_table = NULL;
++ EngineFocusCategory category = ENGINE_FOCUS_CATEGORY_NONE;
++
+ g_assert (path);
+ g_assert (IBUS_IS_ENGINE_DESC (desc));
+ g_assert (G_IS_DBUS_CONNECTION (connection));
+
+- GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
+- BusEngineProxy *engine =
+- (BusEngineProxy *) g_initable_new (BUS_TYPE_ENGINE_PROXY,
+- NULL,
+- NULL,
+- "desc", desc,
+- "g-connection", connection,
+- "g-interface-name", IBUS_INTERFACE_ENGINE,
+- "g-object-path", path,
+- "g-default-timeout", g_gdbus_timeout,
+- "g-flags", flags,
+- NULL);
++ flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START;
++ engine = (BusEngineProxy *) g_initable_new (
++ BUS_TYPE_ENGINE_PROXY,
++ NULL,
++ NULL,
++ "desc", desc,
++ "g-connection", connection,
++ "g-interface-name", IBUS_INTERFACE_ENGINE,
++ "g-object-path", path,
++ "g-default-timeout", g_gdbus_timeout,
++ "g-flags", flags,
++ NULL);
+ const gchar *layout = ibus_engine_desc_get_layout (desc);
+ if (layout != NULL && layout[0] != '\0') {
+ engine->keymap = ibus_keymap_get (layout);
+ }
++ if (ibus)
++ hash_table = bus_ibus_impl_get_engine_focus_id_table (ibus);
++ if (hash_table) {
++ category = (EngineFocusCategory)GPOINTER_TO_INT (
++ g_hash_table_lookup (hash_table,
++ ibus_engine_desc_get_name (desc)));
++ if (category == ENGINE_FOCUS_CATEGORY_HAS_ID)
++ engine->has_focus_id = TRUE;
++ else if (category == ENGINE_FOCUS_CATEGORY_NO_ID)
++ engine->has_focus_id = FALSE;
++ else
++ bus_engine_proxy_get_has_focus_id (engine);
++ }
+ return engine;
+ }
+
+@@ -740,7 +789,8 @@ engine_proxy_new_data_free (EngineProxyNewData *data)
+ /**
+ * create_engine_ready_cb:
+ *
+- * A callback function to be called when bus_factory_proxy_create_engine finishes.
++ * A callback function to be called when bus_factory_proxy_create_engine
++ * finishes.
+ * Create an BusEngineProxy object and call the GAsyncReadyCallback.
+ */
+ static void
+@@ -775,8 +825,10 @@ create_engine_ready_cb (BusFactoryProxy *factory,
+ /**
+ * notify_factory_cb:
+ *
+- * A callback function to be called when bus_component_start() emits "notify::factory" signal within 5 seconds.
+- * Call bus_factory_proxy_create_engine to create the engine proxy asynchronously.
++ * A callback function to be called when bus_component_start() emits
++ * "notify::factory" signal within 5 seconds.
++ * Call bus_factory_proxy_create_engine to create the engine proxy
++ * asynchronously.
+ */
+ static void
+ notify_factory_cb (BusComponent *component,
+@@ -798,22 +850,25 @@ notify_factory_cb (BusComponent *component,
+ data->handler_id = 0;
+ }
+
+- /* We *have to* disconnect the cancelled_cb here, since g_dbus_proxy_call
+- * calls create_engine_ready_cb even if the proxy call is cancelled, and
+- * in this case, create_engine_ready_cb itself will return error using
+- * g_task_return_error(). */
++ /* We *have to* disconnect the cancelled_cb here, since
++ * g_dbus_proxy_call calls create_engine_ready_cb even if the proxy
++ * call is cancelled, and in this case, create_engine_ready_cb itself
++ * will return error using g_task_return_error().
++ */
+ if (data->cancellable && data->cancelled_handler_id != 0) {
+- g_cancellable_disconnect (data->cancellable, data->cancelled_handler_id);
++ g_cancellable_disconnect (data->cancellable,
++ data->cancelled_handler_id);
+ data->cancelled_handler_id = 0;
+ }
+
+ /* Create engine from factory. */
+- bus_factory_proxy_create_engine (data->factory,
+- data->desc,
+- data->timeout,
+- data->cancellable,
+- (GAsyncReadyCallback) create_engine_ready_cb,
+- data);
++ bus_factory_proxy_create_engine (
++ data->factory,
++ data->desc,
++ data->timeout,
++ data->cancellable,
++ (GAsyncReadyCallback) create_engine_ready_cb,
++ data);
+ }
+ /* If factory is NULL, we will continue wait for
+ * factory notify signal or timeout */
+@@ -822,7 +877,8 @@ notify_factory_cb (BusComponent *component,
+ /**
+ * timeout_cb:
+ *
+- * A callback function to be called when bus_component_start() does not emit "notify::factory" signal within 5 seconds.
++ * A callback function to be called when bus_component_start() does not emit
++ * "notify::factory" signal within 5 seconds.
+ * Call the GAsyncReadyCallback and stop the 5 sec timer.
+ */
+ static gboolean
+@@ -927,16 +983,18 @@ bus_engine_proxy_new (IBusEngineDesc *desc,
+ /* The factory is ready. We'll create the engine proxy directly. */
+ g_object_ref (data->factory);
+
+- /* We don't have to connect to cancelled_cb here, since g_dbus_proxy_call
+- * calls create_engine_ready_cb even if the proxy call is cancelled, and
+- * in this case, create_engine_ready_cb itself can return error using
+- * g_task_return_error(). */
+- bus_factory_proxy_create_engine (data->factory,
+- data->desc,
+- timeout,
+- cancellable,
+- (GAsyncReadyCallback) create_engine_ready_cb,
+- data);
++ /* We don't have to connect to cancelled_cb here, since
++ * g_dbus_proxy_call calls create_engine_ready_cb even if the proxy
++ * call is cancelled, and in this case, create_engine_ready_cb itself
++ * can return error using g_task_return_error().
++ */
++ bus_factory_proxy_create_engine (
++ data->factory,
++ data->desc,
++ timeout,
++ cancellable,
++ (GAsyncReadyCallback) create_engine_ready_cb,
++ data);
+ }
+ }
+
+@@ -978,8 +1036,11 @@ bus_engine_proxy_process_key_event (BusEngineProxy *engine,
+ {
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+
+- if (keycode != 0 && bus_ibus_impl_is_use_sys_layout (BUS_DEFAULT_IBUS) == FALSE) {
+- /* Since use_sys_layout is false, we don't rely on XKB. Try to convert keyval from keycode by using our own mapping. */
++ if (keycode != 0 &&
++ bus_ibus_impl_is_use_sys_layout (BUS_DEFAULT_IBUS) == FALSE) {
++ /* Since use_sys_layout is false, we don't rely on XKB. Try to convert
++ * keyval from keycode by using our own mapping.
++ */
+ IBusKeymap *keymap = engine->keymap;
+ if (keymap == NULL)
+ keymap = BUS_DEFAULT_KEYMAP;
+@@ -1142,7 +1203,8 @@ void bus_engine_proxy_set_surrounding_text (BusEngineProxy *engine,
+ g_strcmp0 (text->text, engine->surrounding_text->text) != 0 ||
+ cursor_pos != engine->surrounding_cursor_pos ||
+ anchor_pos != engine->selection_anchor_pos) {
+- GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
++ GVariant *variant =
++ ibus_serializable_serialize ((IBusSerializable *)text);
+ if (engine->surrounding_text)
+ g_object_unref (engine->surrounding_text);
+ engine->surrounding_text = (IBusText *) g_object_ref_sink (text);
+@@ -1201,6 +1263,61 @@ bus_engine_proxy_set_content_type (BusEngineProxy *engine,
+ g_variant_unref (content_type);
+ }
+
++static void
++_get_has_focus_id_cb (GObject *object,
++ GAsyncResult *res,
++ gpointer user_data)
++{
++ GHashTable *hash_table = (GHashTable*)user_data;
++ BusEngineProxy *engine;
++ GError *error = NULL;
++ GVariant *result;
++
++ g_return_if_fail (BUS_IS_ENGINE_PROXY (object));
++ engine = BUS_ENGINE_PROXY (object);
++ result = g_dbus_proxy_call_finish (G_DBUS_PROXY (object), res, &error);
++
++ if (result != NULL) {
++ GVariant *variant = NULL;
++ gpointer value;
++ g_variant_get (result, "(v)", &variant);
++ engine->has_focus_id = g_variant_get_boolean (variant);
++ g_variant_unref (variant);
++ g_variant_unref (result);
++ value = GINT_TO_POINTER (engine->has_focus_id
++ ? ENGINE_FOCUS_CATEGORY_HAS_ID
++ : ENGINE_FOCUS_CATEGORY_NO_ID);
++ g_hash_table_replace (
++ hash_table,
++ (gpointer)ibus_engine_desc_get_name (engine->desc),
++ value);
++ }
++ g_hash_table_unref (hash_table);
++}
++
++static void
++bus_engine_proxy_get_has_focus_id (BusEngineProxy *engine)
++{
++ BusIBusImpl *ibus = BUS_DEFAULT_IBUS;
++ GHashTable *hash_table;
++
++ g_assert (BUS_IS_ENGINE_PROXY (engine));
++ g_assert (ibus);
++
++ hash_table = bus_ibus_impl_get_engine_focus_id_table (ibus);
++ g_assert (hash_table);
++ g_dbus_proxy_call ((GDBusProxy *) engine,
++ "org.freedesktop.DBus.Properties.Get",
++ g_variant_new ("(ss)",
++ IBUS_INTERFACE_ENGINE,
++ "FocusId"),
++ G_DBUS_CALL_FLAGS_NONE,
++ -1,
++ NULL,
++ _get_has_focus_id_cb,
++ g_hash_table_ref (hash_table));
++}
++
+ /* a macro to generate a function to call a nullary D-Bus method. */
+ #define DEFINE_FUNCTION(Name, name) \
+ void \
+@@ -1223,11 +1340,24 @@ DEFINE_FUNCTION (CursorDown, cursor_down)
+ #undef DEFINE_FUNCTION
+
+ void
+-bus_engine_proxy_focus_in (BusEngineProxy *engine)
++bus_engine_proxy_focus_in (BusEngineProxy *engine,
++ const gchar *object_path,
++ const gchar *client)
+ {
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+- if (!engine->has_focus) {
+- engine->has_focus = TRUE;
++ if (engine->has_focus)
++ return;
++ engine->has_focus = TRUE;
++ if (engine->has_focus_id) {
++ g_dbus_proxy_call ((GDBusProxy *)engine,
++ "FocusInId",
++ g_variant_new ("(ss)", object_path, client),
++ G_DBUS_CALL_FLAGS_NONE,
++ -1,
++ NULL,
++ NULL,
++ NULL);
++ } else {
+ g_dbus_proxy_call ((GDBusProxy *)engine,
+ "FocusIn",
+ NULL,
+@@ -1240,11 +1370,23 @@ bus_engine_proxy_focus_in (BusEngineProxy *engine)
+ }
+
+ void
+-bus_engine_proxy_focus_out (BusEngineProxy *engine)
++bus_engine_proxy_focus_out (BusEngineProxy *engine,
++ const gchar *object_path)
+ {
+ g_assert (BUS_IS_ENGINE_PROXY (engine));
+- if (engine->has_focus) {
+- engine->has_focus = FALSE;
++ if (!engine->has_focus)
++ return;
++ engine->has_focus = FALSE;
++ if (engine->has_focus_id) {
++ g_dbus_proxy_call ((GDBusProxy *)engine,
++ "FocusOutId",
++ g_variant_new ("(s)", object_path),
++ G_DBUS_CALL_FLAGS_NONE,
++ -1,
++ NULL,
++ NULL,
++ NULL);
++ } else {
+ g_dbus_proxy_call ((GDBusProxy *)engine,
+ "FocusOut",
+ NULL,
+diff --git a/bus/engineproxy.h b/bus/engineproxy.h
+index a3006b47..957b7851 100644
+--- a/bus/engineproxy.h
++++ b/bus/engineproxy.h
+@@ -2,7 +2,7 @@
+ /* vim:set et sts=4: */
+ /* ibus - The Input Bus
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+- * Copyright (C) 2018 Takao Fujiwara <takao.fujiwara@gmail.com>
++ * Copyright (C) 2018-2022 Takao Fujiwara <takao.fujiwara@gmail.com>
+ * Copyright (C) 2008-2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+@@ -126,20 +126,26 @@ void bus_engine_proxy_set_cursor_location
+ /**
+ * bus_engine_proxy_focus_in:
+ * @engine: A #BusEngineProxy.
++ * @object_path: An object path.
++ * @client: A client name.
+ *
+ * Call "FocusIn" method of an engine asynchronously. Do nothing if
+ * the engine already has a focus.
+ */
+-void bus_engine_proxy_focus_in (BusEngineProxy *engine);
++void bus_engine_proxy_focus_in (BusEngineProxy *engine,
++ const gchar *object_path,
++ const gchar *client);
+
+ /**
+ * bus_engine_proxy_focus_out:
+ * @engine: A #BusEngineProxy.
++ * @object_path: An object path.
+ *
+ * Call "FocusOut" method of an engine asynchronously. Do nothing if
+ * the engine does not have a focus.
+ */
+-void bus_engine_proxy_focus_out (BusEngineProxy *engine);
++void bus_engine_proxy_focus_out (BusEngineProxy *engine,
++ const gchar *object_path);
+
+ /**
+ * bus_engine_proxy_reset:
+diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
+index 49a138fe..8a443545 100644
+--- a/bus/ibusimpl.c
++++ b/bus/ibusimpl.c
+@@ -72,6 +72,8 @@ struct _BusIBusImpl {
+ * IBusEngineDesc object. */
+ GHashTable *engine_table;
+
++ GHashTable *engine_focus_id_table;
++
+ BusInputContext *focused_context;
+ BusPanelProxy *panel;
+ BusPanelProxy *emoji_extension;
+@@ -596,6 +598,7 @@ bus_ibus_impl_init (BusIBusImpl *ibus)
+ ibus->use_global_engine = TRUE;
+ ibus->global_engine_name = NULL;
+ ibus->global_previous_engine_name = NULL;
++ ibus->engine_focus_id_table = g_hash_table_new (g_str_hash, g_str_equal);
+
+ /* focus the fake_context, if use_global_engine is enabled. */
+ if (ibus->use_global_engine)
+@@ -2384,3 +2387,13 @@ bus_ibus_impl_get_focused_input_context (BusIBusImpl *ibus)
+
+ return ibus->focused_context;
+ }
++
++GHashTable *
++bus_ibus_impl_get_engine_focus_id_table (BusIBusImpl *ibus)
++{
++
++ g_assert (BUS_IS_IBUS_IMPL (ibus));
++
++ return ibus->engine_focus_id_table;
++}
++
+diff --git a/bus/ibusimpl.h b/bus/ibusimpl.h
+index 0bb18daf..cbe6856d 100644
+--- a/bus/ibusimpl.h
++++ b/bus/ibusimpl.h
+@@ -2,7 +2,8 @@
+ /* vim:set et sts=4: */
+ /* bus - The Input Bus
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+- * Copyright (C) 2008-2013 Red Hat, Inc.
++ * Copyright (C) 2022 Takao Fujiwara <takao.fujiwara1@gmail.com>
++ * 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
+@@ -58,6 +59,13 @@ G_BEGIN_DECLS
+ typedef struct _BusIBusImpl BusIBusImpl;
+ typedef struct _BusIBusImplClass BusIBusImplClass;
+
++typedef enum
++{
++ ENGINE_FOCUS_CATEGORY_NONE = 0,
++ ENGINE_FOCUS_CATEGORY_NO_ID,
++ ENGINE_FOCUS_CATEGORY_HAS_ID
++} EngineFocusCategory;
++
+ GType bus_ibus_impl_get_type (void);
+
+ /**
+@@ -81,6 +89,7 @@ gboolean bus_ibus_impl_is_embed_preedit_text
+ (BusIBusImpl *ibus);
+ BusInputContext *bus_ibus_impl_get_focused_input_context
+ (BusIBusImpl *ibus);
+-
++GHashTable *bus_ibus_impl_get_engine_focus_id_table
++ (BusIBusImpl *ibus);
+ G_END_DECLS
+ #endif
+diff --git a/bus/inputcontext.c b/bus/inputcontext.c
+index 8d84fd05..72041ecb 100644
+--- a/bus/inputcontext.c
++++ b/bus/inputcontext.c
+@@ -846,7 +846,8 @@ _ic_process_key_event_reply_cb (GObject *source,
+ /**
+ * _ic_process_key_event:
+ *
+- * Implement the "ProcessKeyEvent" method call of the org.freedesktop.IBus.InputContext interface.
++ * Implement the "ProcessKeyEvent" method call of the
++ * org.freedesktop.IBus.InputContext interface.
+ */
+ static void
+ _ic_process_key_event (BusInputContext *context,
+@@ -860,11 +861,13 @@ _ic_process_key_event (BusInputContext *context,
+ g_variant_get (parameters, "(uuu)", &keyval, &keycode, &modifiers);
+ if (G_UNLIKELY (!context->has_focus)) {
+ /* workaround: set focus if context does not have focus */
+- BusInputContext *focused_context = bus_ibus_impl_get_focused_input_context (BUS_DEFAULT_IBUS);
++ BusInputContext *focused_context =
++ bus_ibus_impl_get_focused_input_context (BUS_DEFAULT_IBUS);
+ if (focused_context == NULL ||
+ focused_context->fake == TRUE ||
+ context->fake == FALSE) {
+- /* grab focus, if context is a real IC or current focused IC is fake */
++ /* grab focus, if context is a real IC or current focused IC is
++ * fake */
+ bus_input_context_focus_in (context);
+ }
+ }
+@@ -914,7 +917,8 @@ _ic_process_key_event (BusInputContext *context,
+ data);
+ }
+ else {
+- g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", FALSE));
++ g_dbus_method_invocation_return_value (invocation,
++ g_variant_new ("(b)", FALSE));
+ }
+ }
+
+@@ -1438,7 +1442,9 @@ bus_input_context_focus_in (BusInputContext *context)
+ context->prev_modifiers = 0;
+
+ if (context->engine) {
+- bus_engine_proxy_focus_in (context->engine);
++ const gchar *path =
++ ibus_service_get_object_path ((IBusService *)context);
++ bus_engine_proxy_focus_in (context->engine, path, context->client);
+ bus_engine_proxy_enable (context->engine);
+ bus_engine_proxy_set_capabilities (context->engine, context->capabilities);
+ bus_engine_proxy_set_cursor_location (context->engine, context->x, context->y, context->w, context->h);
+@@ -1538,7 +1544,9 @@ bus_input_context_focus_out (BusInputContext *context)
+ bus_input_context_register_properties (context, props_empty);
+
+ if (context->engine) {
+- bus_engine_proxy_focus_out (context->engine);
++ const gchar *path =
++ ibus_service_get_object_path ((IBusService *)context);
++ bus_engine_proxy_focus_out (context->engine, path);
+ }
+
+ context->has_focus = FALSE;
+@@ -2376,11 +2384,19 @@ bus_input_context_enable (BusInputContext *context)
+ if (context->engine == NULL)
+ return;
+
+- bus_engine_proxy_focus_in (context->engine);
+- bus_engine_proxy_enable (context->engine);
+- bus_engine_proxy_set_capabilities (context->engine, context->capabilities);
+- bus_engine_proxy_set_cursor_location (context->engine, context->x, context->y, context->w, context->h);
+- bus_engine_proxy_set_content_type (context->engine, context->purpose, context->hints);
++ {
++ const gchar *path =
++ ibus_service_get_object_path ((IBusService *)context);
++ bus_engine_proxy_focus_in (context->engine, path, context->client);
++ bus_engine_proxy_enable (context->engine);
++ bus_engine_proxy_set_capabilities (context->engine,
++ context->capabilities);
++ bus_engine_proxy_set_cursor_location (context->engine,
++ context->x, context->y,
++ context->w, context->h);
++ bus_engine_proxy_set_content_type (context->engine,
++ context->purpose, context->hints);
++ }
+ }
+
+ void
+@@ -2397,7 +2413,9 @@ bus_input_context_disable (BusInputContext *context)
+ bus_input_context_register_properties (context, props_empty);
+
+ if (context->engine) {
+- bus_engine_proxy_focus_out (context->engine);
++ const gchar *path =
++ ibus_service_get_object_path ((IBusService *)context);
++ bus_engine_proxy_focus_out (context->engine, path);
+ bus_engine_proxy_disable (context->engine);
+ }
+ }
+@@ -2445,6 +2463,8 @@ bus_input_context_unset_engine (BusInputContext *context)
+
+ if (context->engine) {
+ gint i;
++ const gchar *path =
++ ibus_service_get_object_path ((IBusService *)context);
+ /* uninstall signal handlers for the engine. */
+ for (i = 0; i < G_N_ELEMENTS(engine_signals); i++) {
+ g_signal_handlers_disconnect_by_func (context->engine,
+@@ -2453,7 +2473,7 @@ bus_input_context_unset_engine (BusInputContext *context)
+ /* focus out engine so that the next call of
+ bus_engine_proxy_focus_in() will take effect and trigger
+ RegisterProperties. */
+- bus_engine_proxy_focus_out (context->engine);
++ bus_engine_proxy_focus_out (context->engine, path);
+ g_object_unref (context->engine);
+ context->engine = NULL;
+ }
+@@ -2488,7 +2508,9 @@ bus_input_context_set_engine (BusInputContext *context,
+ context);
+ }
+ if (context->has_focus) {
+- bus_engine_proxy_focus_in (context->engine);
++ const gchar *path =
++ ibus_service_get_object_path ((IBusService *)context);
++ bus_engine_proxy_focus_in (context->engine, path, context->client);
+ bus_engine_proxy_enable (context->engine);
+ bus_engine_proxy_set_capabilities (context->engine, context->capabilities);
+ bus_engine_proxy_set_cursor_location (context->engine, context->x, context->y, context->w, context->h);
+diff --git a/src/ibusengine.c b/src/ibusengine.c
+index 7e844838..7c797103 100644
+--- a/src/ibusengine.c
++++ b/src/ibusengine.c
+@@ -2,7 +2,7 @@
+ /* vim:set et sts=4: */
+ /* ibus - The Input Bus
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+- * Copyright (C) 2018-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
++ * Copyright (C) 2018-2022 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2021 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+@@ -37,7 +37,9 @@
+ enum {
+ PROCESS_KEY_EVENT,
+ FOCUS_IN,
++ FOCUS_IN_ID,
+ FOCUS_OUT,
++ FOCUS_OUT_ID,
+ RESET,
+ ENABLE,
+ DISABLE,
+@@ -61,6 +63,7 @@ enum {
+ enum {
+ PROP_0,
+ PROP_ENGINE_NAME,
++ PROP_HAS_FOCUS_ID,
+ };
+
+
+@@ -82,6 +85,7 @@ struct _IBusEnginePrivate {
+ GHashTable *extension_keybindings;
+ gboolean enable_extension;
+ gchar *current_extension_name;
++ gboolean has_focus_id;
+ };
+
+
+@@ -104,7 +108,8 @@ static void ibus_engine_service_method_call
+ GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+- const gchar *interface_name,
++ const gchar
++ *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation
+@@ -132,7 +137,12 @@ static gboolean ibus_engine_process_key_event
+ guint keycode,
+ guint state);
+ static void ibus_engine_focus_in (IBusEngine *engine);
++static void ibus_engine_focus_in_id (IBusEngine *engine,
++ const gchar *object_path,
++ const gchar *client);
+ static void ibus_engine_focus_out (IBusEngine *engine);
++static void ibus_engine_focus_out_id (IBusEngine *engine,
++ const gchar *object_path);
+ static void ibus_engine_reset (IBusEngine *engine);
+ static void ibus_engine_enable (IBusEngine *engine);
+ static void ibus_engine_disable (IBusEngine *engine);
+@@ -170,7 +180,8 @@ static void ibus_engine_set_surrounding_text
+ static void ibus_engine_process_hand_writing_event
+ (IBusEngine *engine,
+ const gdouble *coordinates,
+- guint coordinates_len);
++ guint
++ coordinates_len);
+ static void ibus_engine_cancel_hand_writing
+ (IBusEngine *engine,
+ guint n_strokes);
+@@ -230,7 +241,15 @@ static const gchar introspection_xml[] =
+ " <arg direction='in' type='u' name='state' />"
+ " </method>"
+ " <method name='FocusIn' />"
++ " <method name='FocusInId'>"
++ " <arg direction='in' type='s' name='object_path' />"
++ " <arg direction='in' type='s' name='client' />"
++ " </method>"
++ " <method name='FocusIn' />"
+ " <method name='FocusOut' />"
++ " <method name='FocusOutId'>"
++ " <arg direction='in' type='s' name='object_path' />"
++ " </method>"
+ " <method name='Reset' />"
+ " <method name='Enable' />"
+ " <method name='Disable' />"
+@@ -283,6 +302,7 @@ static const gchar introspection_xml[] =
+ " </signal>"
+ /* FIXME properties */
+ " <property name='ContentType' type='(uu)' access='write' />"
++ " <property name='FocusId' type='(b)' access='read' />"
+ " </interface>"
+ "</node>";
+
+@@ -324,7 +344,9 @@ ibus_engine_class_init (IBusEngineClass *class)
+
+ class->process_key_event = ibus_engine_process_key_event;
+ class->focus_in = ibus_engine_focus_in;
++ class->focus_in_id = ibus_engine_focus_in_id;
+ class->focus_out = ibus_engine_focus_out;
++ class->focus_out_id = ibus_engine_focus_out_id;
+ class->reset = ibus_engine_reset;
+ class->enable = ibus_engine_enable;
+ class->disable = ibus_engine_disable;
+@@ -360,6 +382,15 @@ ibus_engine_class_init (IBusEngineClass *class)
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
++ g_object_class_install_property (gobject_class,
++ PROP_HAS_FOCUS_ID,
++ g_param_spec_boolean ("has-focus-id",
++ "has focus id",
++ "Has focus ID",
++ FALSE,
++ G_PARAM_READWRITE |
++ G_PARAM_CONSTRUCT_ONLY));
++
+ /* install signals */
+ /**
+ * IBusEngine::process-key-event:
+@@ -378,7 +409,8 @@ ibus_engine_class_init (IBusEngineClass *class)
+ * Returns: %TRUE for successfully process the key; %FALSE otherwise.
+ * See also: ibus_input_context_process_key_event().
+ *
+- * <note><para>Argument @user_data is ignored in this function.</para></note>
++ * <note><para>Argument @user_data is ignored in this function.</para>
++ * </note>
+ */
+ engine_signals[PROCESS_KEY_EVENT] =
+ g_signal_new (I_("process-key-event"),
+@@ -402,7 +434,8 @@ ibus_engine_class_init (IBusEngineClass *class)
+ * in extended class to receive this signal.
+ *
+ * See also: ibus_input_context_focus_in()
+- * <note><para>Argument @user_data is ignored in this function.</para></note>
++ * <note><para>Argument @user_data is ignored in this function.</para>
++ * </note>
+ */
+ engine_signals[FOCUS_IN] =
+ g_signal_new (I_("focus-in"),
+@@ -414,6 +447,58 @@ ibus_engine_class_init (IBusEngineClass *class)
+ G_TYPE_NONE,
+ 0);
+
++ /**
++ * IBusEngine::focus-in-id:
++ * @engine: An IBusEngine.
++ * @object_path: An object path.
++ * @client: An client name.
++ *
++ * Emitted when the client application get the focus.
++ * Implement the member function IBusEngineClass::focus_in
++ * in extended class to receive this signal.
++ * @object_path is a unique id by input context.
++ * @client indicates a client type:
++ * 'fake': focus is on desktop background or other programs where no
++ * input is possible
++ * 'xim': old X11 programs like xterm, emacs, ...
++ * GTK3 programs in a Gnome Xorg session when GTK_IM_MODULE
++ * is unset also use xim
++ * 'gtk-im:<client-name>': Gtk2 input module is used
++ * 'gtk3-im:<client-name>': Gtk3 input module is used
++ * 'gtk4-im:<client-name>': Gtk4 input module is used
++ * In case of the Gtk input modules, the name of the
++ * client is also shown after the “:”, for example
++ * like 'gtk3-im:firefox', 'gtk4-im:gnome-text-editor', …
++ * 'gnome-shell': Entries handled by gnome-shell
++ * (like the command line dialog opened with Alt+F2
++ * or the search field when pressing the Super key.)
++ * When GTK_IM_MODULE is unset in a Gnome Wayland session
++ * all programs which would show 'gtk3-im' or 'gtk4-im'
++ * with GTK_IM_MODULE=ibus then show 'gnome-shell'
++ * instead.
++ * 'Qt': Qt4 programs like keepassx-2.0.3 …
++ * 'QIBusInputContext': Qt5 programs like keepassxc-2.7.1, anki-2.1.15
++ * telegram-desktop-3.7.3,
++ *
++ * You need to set #IBusEngine::has-focus-id property to %TRUE when you
++ * construct an #IBusEngine to use this class method.
++ *
++ * See also: ibus_input_context_focus_in()
++ * <note><para>Argument @user_data is ignored in this function.</para>
++ * </note>
++ */
++ engine_signals[FOCUS_IN_ID] =
++ g_signal_new (I_("focus-in-id"),
++ G_TYPE_FROM_CLASS (gobject_class),
++ G_SIGNAL_RUN_LAST,
++ G_STRUCT_OFFSET (IBusEngineClass, focus_in_id),
++ NULL, NULL,
++ _ibus_marshal_VOID__STRING_STRING,
++ G_TYPE_NONE,
++ 2,
++ G_TYPE_STRING,
++ G_TYPE_STRING);
++
+ /**
+ * IBusEngine::focus-out:
+ * @engine: An IBusEngine.
+@@ -423,7 +508,8 @@ ibus_engine_class_init (IBusEngineClass *class)
+ * in extended class to receive this signal.
+ *
+ * See also: ibus_input_context_focus_out()
+- * <note><para>Argument @user_data is ignored in this function.</para></note>
++ * <note><para>Argument @user_data is ignored in this function.</para>
++ * </note>
+ */
+ engine_signals[FOCUS_OUT] =
+ g_signal_new (I_("focus-out"),
+@@ -435,6 +521,33 @@ ibus_engine_class_init (IBusEngineClass *class)
+ G_TYPE_NONE,
+ 0);
+
++ /**
++ * IBusEngine::focus-out-id:
++ * @engine: An IBusEngine.
++ * @object_path: An object path.
++ *
++ * Emitted when the client application lost the focus.
++ * Implement the member function IBusEngineClass::focus_out
++ * in extended class to receive this signal.
++ * @object_path is a unique id by input context.
++ * You need to set #IBusEngine::has-focus-id property to %TRUE when you
++ * construct an #IBusEngine to use this class method.
++ *
++ * See also: ibus_input_context_focus_out()
++ * <note><para>Argument @user_data is ignored in this function.</para>
++ * </note>
++ */
++ engine_signals[FOCUS_OUT_ID] =
++ g_signal_new (I_("focus-out-id"),
++ G_TYPE_FROM_CLASS (gobject_class),
++ G_SIGNAL_RUN_LAST,
++ G_STRUCT_OFFSET (IBusEngineClass, focus_out_id),
++ NULL, NULL,
++ _ibus_marshal_VOID__STRING,
++ G_TYPE_NONE,
++ 1,
++ G_TYPE_STRING);
++
+ /**
+ * IBusEngine::reset:
+ * @engine: An IBusEngine.
+@@ -872,6 +985,9 @@ ibus_engine_set_property (IBusEngine *engine,
+ case PROP_ENGINE_NAME:
+ engine->priv->engine_name = g_value_dup_string (value);
+ break;
++ case PROP_HAS_FOCUS_ID:
++ engine->priv->has_focus_id = g_value_get_boolean (value);
++ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
+ }
+@@ -887,7 +1003,9 @@ ibus_engine_get_property (IBusEngine *engine,
+ case PROP_ENGINE_NAME:
+ g_value_set_string (value, engine->priv->engine_name);
+ break;
+-
++ case PROP_HAS_FOCUS_ID:
++ g_value_set_boolean (value, engine->priv->has_focus_id);
++ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (engine, prop_id, pspec);
+ }
+@@ -1176,6 +1294,30 @@ ibus_engine_service_method_call (IBusService *service,
+ }
+ }
+
++ if (g_strcmp0 (method_name, "FocusInId") == 0) {
++ gchar *object_path = NULL;
++ gchar *client = NULL;
++ g_variant_get (parameters, "(&s&s)", &object_path, &client);
++ g_signal_emit (engine,
++ engine_signals[FOCUS_IN_ID],
++ 0,
++ object_path,
++ client);
++ g_dbus_method_invocation_return_value (invocation, NULL);
++ return;
++ }
++
++ if (g_strcmp0 (method_name, "FocusOutId") == 0) {
++ gchar *object_path = NULL;
++ g_variant_get (parameters, "(&s)", &object_path);
++ g_signal_emit (engine,
++ engine_signals[FOCUS_OUT_ID],
++ 0,
++ object_path);
++ g_dbus_method_invocation_return_value (invocation, NULL);
++ return;
++ }
++
+ if (g_strcmp0 (method_name, "CandidateClicked") == 0) {
+ guint index, button, state;
+ g_variant_get (parameters, "(uuu)", &index, &button, &state);
+@@ -1303,6 +1445,23 @@ ibus_engine_service_method_call (IBusService *service,
+ g_return_if_reached ();
+ }
+
++/**
++ * _ibus_engine_has_focus_id:
++ *
++ * Implement the "FocusId" method call of the org.freedesktop.IBus interface.
++ */
++static GVariant *
++_ibus_engine_has_focus_id (IBusEngine *engine,
++ GDBusConnection *connection,
++ GError **error)
++{
++ if (error) {
++ *error = NULL;
++ }
++
++ return g_variant_new_boolean (engine->priv->has_focus_id);
++}
++
+ static GVariant *
+ ibus_engine_service_get_property (IBusService *service,
+ GDBusConnection *connection,
+@@ -1312,7 +1471,18 @@ ibus_engine_service_get_property (IBusService *service,
+ const gchar *property_name,
+ GError **error)
+ {
+- return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
++ int i;
++ static const struct {
++ const gchar *method_name;
++ GVariant * (* method_callback) (IBusEngine *,
++ GDBusConnection *,
++ GError **);
++ } methods [] = {
++ { "FocusId", _ibus_engine_has_focus_id },
++ };
++
++ if (g_strcmp0 (interface_name, IBUS_INTERFACE_ENGINE) != 0) {
++ return IBUS_SERVICE_CLASS (ibus_engine_parent_class)->
+ service_get_property (service,
+ connection,
+ sender,
+@@ -1320,6 +1490,19 @@ ibus_engine_service_get_property (IBusService *service,
+ interface_name,
+ property_name,
+ error);
++ }
++
++ for (i = 0; i < G_N_ELEMENTS (methods); i++) {
++ if (g_strcmp0 (methods[i].method_name, property_name) == 0) {
++ return methods[i].method_callback ((IBusEngine *) service,
++ connection,
++ error);
++ }
++ }
++
++ g_warning ("service_get_property received an unknown property: %s",
++ property_name ? property_name : "(null)");
++ return NULL;
+ }
+
+ static gboolean
+@@ -1386,31 +1569,39 @@ ibus_engine_process_key_event (IBusEngine *engine,
+ static void
+ ibus_engine_focus_in (IBusEngine *engine)
+ {
+- // g_debug ("focus-in");
++}
++
++static void
++ibus_engine_focus_in_id (IBusEngine *engine,
++ const gchar *object_path,
++ const gchar *client)
++{
+ }
+
+ static void
+ ibus_engine_focus_out (IBusEngine *engine)
+ {
+- // g_debug ("focus-out");
++}
++
++static void
++ibus_engine_focus_out_id (IBusEngine *engine,
++ const gchar *object_path)
++{
+ }
+
+ static void
+ ibus_engine_reset (IBusEngine *engine)
+ {
+- // g_debug ("reset");
+ }
+
+ static void
+ ibus_engine_enable (IBusEngine *engine)
+ {
+- // g_debug ("enable");
+ }
+
+ static void
+ ibus_engine_disable (IBusEngine *engine)
+ {
+- // g_debug ("disable");
+ }
+
+ static void
+diff --git a/src/ibusengine.h b/src/ibusengine.h
+index 43eaa554..6af0e856 100644
+--- a/src/ibusengine.h
++++ b/src/ibusengine.h
+@@ -2,7 +2,8 @@
+ /* vim:set et sts=4: */
+ /* ibus - The Input Bus
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+- * Copyright (C) 2008-2013 Red Hat, Inc.
++ * Copyright (C) 2012-2022 Takao Fujiwara <takao.fujiwara1@gmail.com>
++ * 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
+@@ -153,10 +154,15 @@ struct _IBusEngineClass {
+ (IBusEngine *engine,
+ guint purpose,
+ guint hints);
++ void (* focus_in_id) (IBusEngine *engine,
++ const gchar *object_path,
++ const gchar *client);
++ void (* focus_out_id) (IBusEngine *engine,
++ const gchar *object_path);
+
+ /*< private >*/
+ /* padding */
+- gpointer pdummy[4];
++ gpointer pdummy[2];
+ };
+
+ GType ibus_engine_get_type (void);
+diff --git a/src/ibusmarshalers.list b/src/ibusmarshalers.list
+index aa9ea82a..7489f842 100644
+--- a/src/ibusmarshalers.list
++++ b/src/ibusmarshalers.list
+@@ -19,6 +19,7 @@ VOID:OBJECT,UINT,UINT
+ VOID:OBJECT,BOOLEAN
+ VOID:BOXED,BOOLEAN
+ VOID:BOXED
++VOID:STRING,STRING
+ VOID:STRING,STRING,VARIANT
+ VOID:STRING,STRING,STRING
+ VOID:UINT
+--
+2.35.3
+
+From 59c13597918db98ec8120ccdac09f1e2dc576e1b Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Thu, 7 Jul 2022 08:22:48 +0900
+Subject: [PATCH] src/tests: Unset G_MESSAGES_DEBUG for gsettings in
+ xkb-latin-layouts
+
+gsettings cannot get the key value when G_MESSAGES_DEBUG is enabled.
+Add denylist.txt to engine/Makefile.am
+---
+ engine/Makefile.am | 3 ++-
+ src/tests/xkb-latin-layouts | 7 +++++++
+ 2 files changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/engine/Makefile.am b/engine/Makefile.am
+index 03867f52..7256fbc8 100644
+--- a/engine/Makefile.am
++++ b/engine/Makefile.am
+@@ -4,7 +4,7 @@
+ #
+ # Copyright (c) 2010-2016, Google Inc. All rights reserved.
+ # Copyright (c) 2007-2016 Peng Huang <shawn.p.huang@gmail.com>
+-# Copyright (c) 2013-2020 Takao Fujiwara <takao.fujiwara1@gmail.com>
++# Copyright (c) 2013-2021 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ #
+ # This library is free software; you can redistribute it and/or
+ # modify it under the terms of the GNU Lesser General Public
+@@ -88,6 +88,7 @@ CLEANFILES = \
+ $(NULL)
+
+ EXTRA_DIST = \
++ denylist.txt \
+ gensimple.py \
+ iso639converter.py \
+ simple.xml.in \
+diff --git a/src/tests/xkb-latin-layouts b/src/tests/xkb-latin-layouts
+index f8dced6b..92464234 100755
+--- a/src/tests/xkb-latin-layouts
++++ b/src/tests/xkb-latin-layouts
+@@ -82,9 +82,16 @@ finit()
+
+ test_xkb_keymaps()
+ {
++ # G_MESSAGES_DEBUG=all or G_MESSAGES_DEBUG=GLib-GIO-DEBUG would append
++ # debug messages to gsettings output and could not get the result correctly.
++ backup_G_MESSAGES_DEBUG="$G_MESSAGES_DEBUG"
++ unset G_MESSAGES_DEBUG
+ # Loop over top level schemas since "gsettings list-recursively" only
+ # looks for direct children.
+ xkb_latin_layouts=`gsettings get org.freedesktop.ibus.general xkb-latin-layouts`
++ if [ x"$backup_G_MESSAGES_DEBUG" != x ] ; then
++ export G_MESSAGES_DEBUG=$backup_G_MESSAGES_DEBUG
++ fi
+ while read keymap ; do
+ eval keymap="$keymap"
+ HAS_VARIANT=$($ECHO "$keymap" | grep '(' 2> /dev/null) ||:
+--
+2.35.3
+
diff --git a/ibus.spec b/ibus.spec
index 47585f1..6958ddf 100644
--- a/ibus.spec
+++ b/ibus.spec
@@ -39,7 +39,7 @@
Name: ibus
Version: 1.5.26
-Release: 12%{?dist}
+Release: 13%{?dist}
Summary: Intelligent Input Bus for Linux OS
License: LGPLv2+
URL: https://github.com/ibus/%name/wiki
@@ -524,6 +524,13 @@ dconf update || :
%{_datadir}/installed-tests/ibus
%changelog
+* Thu Jul 07 2022 Takao Fujiwara <tfujiwar@redhat.com> - 1.5.26-13
+- Add IBUS_CAP_OSK to IBusCapabilite
+- Update ibus restart for --service-file option
+- Update manpage for ibus im-module command
+- Implement new process_key_event for GTK4
+- Add focus_in_id()/focus_out_id() class methods in IBusEngine
+
* Wed Jun 29 2022 Takao Fujiwara <tfujiwar@redhat.com> - 1.5.26-12
- Add ibus im-module command
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-05-31 2:07 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-31 2:07 [rpms/ibus] autotool: Add some new features Takao Fujiwara
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox