From ebbfbeae2909e68c3b6f8165302a2620fb55e45f Mon Sep 17 00:00:00 2001 From: Takao Fujiwara Date: Thu, 7 Jul 2022 08:47:31 +0900 Subject: [PATCH] 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 --- ibus-1385349-segv-bus-proxy.patch | 51 +- ibus-HEAD.patch | 2107 ++++++++++++++++++++++++++--- ibus.spec | 9 +- 3 files changed, 1948 insertions(+), 219 deletions(-) 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 -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 -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 +- * “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.35.3 + +From 4e48e7237d73d20f0426265dbb6b692b14891932 Mon Sep 17 00:00:00 2001 +From: fujiwarat +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 , 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 get_ibus_schemas() { string[] ids = {}; if (engine_id != null) { -@@ -342,6 +552,7 @@ private GLib.SList get_ibus_schemas() { +@@ -342,6 +582,7 @@ private GLib.SList 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 5b441fabc9d766e694b992e0e2f28924d00a7402 Mon Sep 17 00:00:00 2001 From: fujiwarat -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 --# Copyright (c) 2013-2020 Takao Fujiwara -+# Copyright (c) 2013-2021 Takao Fujiwara - # - # 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: fujiwarat -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,70 +2470,74 @@ 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 - $(AM_V_GEN) gzip -c $< > $@.tmp && mv $@.tmp $@ - - EXTRA_DIST = \ -- $(man_one_in_files) \ -- ibus.bash \ +- --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) -+ $(man_one_in_files) \ -+ ibus.bash \ -+ ibusimmodule.c \ -+ ibusimmodule.h \ -+ IBusIMModule-1.0.metadata \ -+ $(NULL) - - CLEANFILES = \ -- $(man_one_DATA) \ -- $(man_one_files) \ -- $(NULL) -+ $(man_one_DATA) \ -+ $(man_one_files) \ -+ $(NULL) - - if ENABLE_EMOJI_DICT - if ENABLE_UI -@@ -108,4 +119,73 @@ 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 \ ++ --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 \ @@ -2502,6 +2555,44 @@ index e380a9aa..f96f2ba2 100644 + -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-1.0.metadata \ ++ $(NULL) + + CLEANFILES = \ +- $(man_one_DATA) \ +- $(man_one_files) \ +- $(NULL) ++ $(man_one_DATA) \ ++ $(man_one_files) \ ++ $(NULL) + + if ENABLE_EMOJI_DICT + if ENABLE_UI +@@ -108,4 +143,43 @@ AM_VALAFLAGS += \ + endif + endif + ++if HAVE_INTROSPECTION ++BUILT_SOURCES = $(INTROSPECTION_GIRS) $(VAPIGEN_VAPIS) + +-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 +#include +#include @@ -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 +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 +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 +- * Copyright (C) 2015-2018 Takao Fujiwara ++ * Copyright (C) 2015-2022 Takao Fujiwara + * 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 +- * Copyright (C) 2018 Takao Fujiwara ++ * Copyright (C) 2018-2022 Takao Fujiwara + * 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 +- * Copyright (C) 2008-2013 Red Hat, Inc. ++ * Copyright (C) 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 +@@ -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 +- * Copyright (C) 2018-2021 Takao Fujiwara ++ * Copyright (C) 2018-2022 Takao Fujiwara + * 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[] = + " " + " " + " " ++ " " ++ " " ++ " " ++ " " ++ " " + " " ++ " " ++ " " ++ " " + " " + " " + " " +@@ -283,6 +302,7 @@ static const gchar introspection_xml[] = + " " + /* FIXME properties */ + " " ++ " " + " " + ""; + +@@ -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(). + * +- * Argument @user_data is ignored in this function. ++ * Argument @user_data is ignored in this function. ++ * + */ + 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() +- * Argument @user_data is ignored in this function. ++ * Argument @user_data is ignored in this function. ++ * + */ + 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() ++ * Argument @user_data is ignored in this function. ++ * ++ */ ++ 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() +- * Argument @user_data is ignored in this function. ++ * Argument @user_data is ignored in this function. ++ * + */ + 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() ++ * Argument @user_data is ignored in this function. ++ * ++ */ ++ 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 +- * Copyright (C) 2008-2013 Red Hat, Inc. ++ * Copyright (C) 2012-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 +@@ -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 +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 +-# Copyright (c) 2013-2020 Takao Fujiwara ++# Copyright (c) 2013-2021 Takao Fujiwara + # + # 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 - 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 - 1.5.26-12 - Add ibus im-module command