public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Takao Fujiwara <tfujiwar@redhat.com>
To: git-commits@fedoraproject.org
Subject: [rpms/ibus] autotool: Fix sync ibus_input_context_process_key_event()
Date: Sun, 31 May 2026 02:08:11 GMT [thread overview]
Message-ID: <178019329196.1.15673619065037637688.rpms-ibus-25ad70d24586@fedoraproject.org> (raw)
A new commit has been pushed.
Repo : rpms/ibus
Branch : autotool
Commit : 25ad70d2458691ff9d1210c04c910cb2a07acd49
Author : Takao Fujiwara <tfujiwar@redhat.com>
Date : 2023-07-07T09:39:39+09:00
Stats : +1907/-1 in 2 file(s)
URL : https://src.fedoraproject.org/rpms/ibus/c/25ad70d2458691ff9d1210c04c910cb2a07acd49?branch=autotool
Log:
Fix sync ibus_input_context_process_key_event()
---
diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch
index a691af7..9f2ae56 100644
--- a/ibus-HEAD.patch
+++ b/ibus-HEAD.patch
@@ -2336,3 +2336,1906 @@ index 68dde2f3..fee0b3ee 100644
--
2.41.0
+From 8a1bd5ff72b7edf47526cfa19325f7e1dab85f59 Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Fri, 7 Jul 2023 08:49:49 +0900
+Subject: [PATCH 1/2] src: Fix sync ibus_input_context_process_key_event()
+
+The synchronous "ProcessKeyEvent" D-Bus method cannot receive
+"CommitText" and "ForwardKeyEvent" D-Bus signals during calling the method.
+To resolve the issue, now
+ibus_input_context_set_post_process_key_event() and
+ibus_input_context_post_process_key_event() are added newly.
+
+ibus_input_context_post_process_key_event() retries "CommitText" and
+"ForwardKeyEvent" D-Bus signals during calling the "ProcessKeyEvent" D-Bus
+method and ibus-daemon does not handle those signals.
+
+BUG=https://github.com/ibus/ibus/issues/2486
+---
+ bus/inputcontext.c | 587 +++++++++++++++++++++++++++---------
+ client/gtk2/ibusimcontext.c | 51 ++--
+ src/ibusinputcontext.c | 162 +++++++++-
+ src/ibusinputcontext.h | 30 +-
+ 4 files changed, 652 insertions(+), 178 deletions(-)
+
+diff --git a/bus/inputcontext.c b/bus/inputcontext.c
+index e76bbdfc..2110af87 100644
+--- a/bus/inputcontext.c
++++ b/bus/inputcontext.c
+@@ -31,6 +31,8 @@
+ #include "marshalers.h"
+ #include "types.h"
+
++#define MAX_SYNC_DATA 30
++
+ struct _SetEngineByDescData {
+ /* context related to the data */
+ BusInputContext *context;
+@@ -38,13 +40,19 @@ struct _SetEngineByDescData {
+ GTask *task;
+ /* a object to cancel bus_engine_proxy_new call */
+ GCancellable *cancellable;
+- /* a object being passed to the bus_input_context_set_engine_by_desc function. if origin_cancellable is cancelled by someone,
++ /* a object being passed to the bus_input_context_set_engine_by_desc
++ * function. if origin_cancellable is cancelled by someone,
+ * we cancel the cancellable above as well. */
+ GCancellable *origin_cancellable;
+ gulong cancelled_handler_id;
+ };
+ typedef struct _SetEngineByDescData SetEngineByDescData;
+
++typedef struct _SyncForwardingData {
++ gchar key;
++ IBusText *text;
++} SyncForwardingData;
++
+ struct _BusInputContext {
+ IBusService parent;
+
+@@ -98,6 +106,9 @@ struct _BusInputContext {
+
+ BusPanelProxy *emoji_extension;
+ gboolean is_extension_lookup_table;
++ GQueue *queue_during_process_key_event;
++ gboolean use_post_process_key_event;
++ gboolean processing_key_event;
+ };
+
+ struct _BusInputContextClass {
+@@ -155,6 +166,15 @@ static void bus_input_context_service_method_call
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation);
++static GVariant *
++ bus_input_context_service_get_property
++ (IBusService *service,
++ GDBusConnection *connection,
++ const gchar *sender,
++ const gchar *object_path,
++ const gchar *interface_name,
++ const gchar *property_name,
++ GError **error);
+ static gboolean bus_input_context_service_set_property
+ (IBusService *service,
+ GDBusConnection *connection,
+@@ -214,8 +234,11 @@ static const gchar introspection_xml[] =
+ "<node>"
+ " <interface name='org.freedesktop.IBus.InputContext'>"
+ /* properties */
++ " <property name='PostProcessKeyEvent' type='(a(yv))' access='read' />\n"
+ " <property name='ContentType' type='(uu)' access='write' />"
+ " <property name='ClientCommitPreedit' type='(b)' access='write' />\n"
++ " <property name='EffectivePostProcessKeyEvent' type='(b)' "
++ " access='write' />\n"
+ /* methods */
+ " <method name='ProcessKeyEvent'>"
+ " <arg direction='in' type='u' name='keyval' />"
+@@ -223,6 +246,12 @@ static const gchar introspection_xml[] =
+ " <arg direction='in' type='u' name='state' />"
+ " <arg direction='out' type='b' name='handled' />"
+ " </method>"
++ " <method name='ProcessKeyEventSync'>"
++ " <arg direction='in' type='u' name='keyval' />"
++ " <arg direction='in' type='u' name='keycode' />"
++ " <arg direction='in' type='u' name='state' />"
++ " <arg direction='out' type='ba(yv)' name='handled' />"
++ " </method>"
+ " <method name='SetCursorLocation'>"
+ " <arg direction='in' type='i' name='x' />"
+ " <arg direction='in' type='i' name='y' />"
+@@ -312,11 +341,14 @@ static const gchar introspection_xml[] =
+
+ G_DEFINE_TYPE (BusInputContext, bus_input_context, IBUS_TYPE_SERVICE)
+
+-/* TRUE if we can send preedit text to client. FALSE if the panel has to handle it. Note that we check IBUS_CAP_FOCUS here since
+- * when the capability is not set, the client has to handle a preedit text regardless of the embed_preedit_text config. */
++/* TRUE if we can send preedit text to client. FALSE if the panel has to handle
++ * it. Note that we check IBUS_CAP_FOCUS here since
++ * when the capability is not set, the client has to handle a preedit text
++ * regardless of the embed_preedit_text config. */
+ #define PREEDIT_CONDITION \
+ ((context->capabilities & IBUS_CAP_PREEDIT_TEXT) && \
+- (bus_ibus_impl_is_embed_preedit_text (BUS_DEFAULT_IBUS) || (context->capabilities & IBUS_CAP_FOCUS) == 0))
++ (bus_ibus_impl_is_embed_preedit_text (\
++ BUS_DEFAULT_IBUS) || (context->capabilities & IBUS_CAP_FOCUS) == 0))
+
+ static void
+ _connection_destroy_cb (BusConnection *connection,
+@@ -343,17 +375,23 @@ bus_input_context_class_init (BusInputContextClass *class)
+ "");
+ g_object_ref_sink (class->default_engine_desc);
+
+- ibus_object_class->destroy = (IBusObjectDestroyFunc) bus_input_context_destroy;
++ ibus_object_class->destroy =
++ (IBusObjectDestroyFunc)bus_input_context_destroy;
+
+ /* override the parent class's implementation. */
+ IBUS_SERVICE_CLASS (class)->service_method_call =
+ bus_input_context_service_method_call;
++ IBUS_SERVICE_CLASS (class)->service_get_property =
++ bus_input_context_service_get_property;
+ IBUS_SERVICE_CLASS (class)->service_set_property =
+ bus_input_context_service_set_property;
+- /* register the xml so that bus_ibus_impl_service_method_call will be called on a method call defined in the xml (e.g. 'FocusIn'.) */
++ /* register the xml so that bus_ibus_impl_service_method_call will be
++ * called on a method call defined in the xml (e.g. 'FocusIn'.) */
+ ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
+
+- /* install glib signals that would be handled by other classes like ibusimpl.c and panelproxy.c. */
++ /* install glib signals that would be handled by other classes like
++ * ibusimpl.c and panelproxy.c.
++ */
+ context_signals[PROCESS_KEY_EVENT] =
+ g_signal_new (I_("process-key-event"),
+ G_TYPE_FROM_CLASS (class),
+@@ -576,8 +614,11 @@ bus_input_context_class_init (BusInputContextClass *class)
+ G_TYPE_NONE,
+ 0);
+
+- /* This signal is not for notifying an event on this object, but is for requesting an engine as the name shows.
+- * On the signal emission, ibusimpl.c will immediately update the context->engine variable. */
++ /* This signal is not for notifying an event on this object, but is for
++ * requesting an engine as the name shows.
++ * On the signal emission, ibusimpl.c will immediately update the
++ * context->engine variable.
++ */
+ context_signals[REQUEST_ENGINE] =
+ g_signal_new (I_("request-engine"),
+ G_TYPE_FROM_CLASS (class),
+@@ -614,7 +655,8 @@ bus_input_context_class_init (BusInputContextClass *class)
+
+ text_empty = ibus_text_new_from_string ("");
+ g_object_ref_sink (text_empty);
+- lookup_table_empty = ibus_lookup_table_new (9 /* page size */, 0, FALSE, FALSE);
++ lookup_table_empty = ibus_lookup_table_new (9 /* page size */,
++ 0, FALSE, FALSE);
+ g_object_ref_sink (lookup_table_empty);
+ props_empty = ibus_prop_list_new ();
+ g_object_ref_sink (props_empty);
+@@ -662,9 +704,10 @@ bus_input_context_destroy (BusInputContext *context)
+ }
+
+ if (context->connection) {
+- g_signal_handlers_disconnect_by_func (context->connection,
+- (GCallback) _connection_destroy_cb,
+- context);
++ g_signal_handlers_disconnect_by_func (
++ context->connection,
++ (GCallback) _connection_destroy_cb,
++ context);
+ g_object_unref (context->connection);
+ context->connection = NULL;
+ }
+@@ -674,7 +717,8 @@ bus_input_context_destroy (BusInputContext *context)
+ context->client = NULL;
+ }
+
+- IBUS_OBJECT_CLASS (bus_input_context_parent_class)->destroy (IBUS_OBJECT (context));
++ IBUS_OBJECT_CLASS (bus_input_context_parent_class)->
++ destroy (IBUS_OBJECT (context));
+ }
+
+ static gboolean
+@@ -689,25 +733,30 @@ bus_input_context_send_signal (BusInputContext *context,
+ return TRUE;
+ }
+
+- GDBusMessage *message = g_dbus_message_new_signal (ibus_service_get_object_path ((IBusService *)context),
+- interface_name,
+- signal_name);
++ GDBusMessage *message = g_dbus_message_new_signal (
++ ibus_service_get_object_path ((IBusService *)context),
++ interface_name,
++ signal_name);
+ g_dbus_message_set_sender (message, "org.freedesktop.IBus");
+- g_dbus_message_set_destination (message, bus_connection_get_unique_name (context->connection));
++ g_dbus_message_set_destination (
++ message,
++ bus_connection_get_unique_name (context->connection));
+ if (parameters != NULL)
+ g_dbus_message_set_body (message, parameters);
+
+- gboolean retval = g_dbus_connection_send_message (bus_connection_get_dbus_connection (context->connection),
+- message,
+- G_DBUS_SEND_MESSAGE_FLAGS_NONE,
+- NULL, error);
++ gboolean retval = g_dbus_connection_send_message (
++ bus_connection_get_dbus_connection (context->connection),
++ message,
++ G_DBUS_SEND_MESSAGE_FLAGS_NONE,
++ NULL, error);
+ g_object_unref (message);
+ return retval;
+ }
+
+ /**
+ * bus_input_context_emit_signal:
+- * @signal_name: The D-Bus signal name to emit which is in the introspection_xml.
++ * @signal_name: The D-Bus signal name to emit which is in the
++ * introspection_xml.
+ *
+ * Emit the D-Bus signal.
+ */
+@@ -763,6 +812,11 @@ bus_input_context_property_changed (BusInputContext *context,
+ }
+
+
++typedef struct _PanelProcessKeyEventData {
++ GDBusMethodInvocation *invocation;
++ BusInputContext *context;
++} PanelProcessKeyEventData;
++
+ /**
+ * _panel_process_key_event_cb:
+ *
+@@ -770,14 +824,21 @@ bus_input_context_property_changed (BusInputContext *context,
+ * bus_panel_proxy_process_key_event() is finished.
+ */
+ static void
+-_panel_process_key_event_cb (GObject *source,
+- GAsyncResult *res,
+- GDBusMethodInvocation *invocation)
++_panel_process_key_event_cb (GObject *source,
++ GAsyncResult *res,
++ PanelProcessKeyEventData *data)
+ {
+ GError *error = NULL;
+ GVariant *value = g_dbus_proxy_call_finish ((GDBusProxy *)source,
+ res,
+ &error);
++ GDBusMethodInvocation *invocation;
++ BusInputContext *context;
++
++ g_assert (data);
++ invocation = data->invocation;
++ context = data->context;
++ g_slice_free (PanelProcessKeyEventData, data);
+ if (value != NULL) {
+ g_dbus_method_invocation_return_value (invocation, value);
+ g_variant_unref (value);
+@@ -786,6 +847,7 @@ _panel_process_key_event_cb (GObject *source,
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ }
++ context->processing_key_event = FALSE;
+ }
+
+ typedef struct _ProcessKeyEventData ProcessKeyEventData;
+@@ -822,21 +884,27 @@ _ic_process_key_event_reply_cb (GObject *source,
+ gboolean retval = FALSE;
+ g_variant_get (value, "(b)", &retval);
+ if (context->emoji_extension && !retval) {
++ PanelProcessKeyEventData *pdata =
++ g_slice_new (PanelProcessKeyEventData);
++ pdata->invocation = invocation;
++ pdata->context = context;
+ bus_panel_proxy_process_key_event (context->emoji_extension,
+ keyval,
+ keycode,
+ modifiers,
+ (GAsyncReadyCallback)
+ _panel_process_key_event_cb,
+- invocation);
++ pdata);
+ } else {
+ g_dbus_method_invocation_return_value (invocation, value);
++ context->processing_key_event = FALSE;
+ }
+ g_variant_unref (value);
+ }
+ else {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
++ context->processing_key_event = FALSE;
+ }
+
+ g_object_unref (context);
+@@ -850,14 +918,16 @@ _ic_process_key_event_reply_cb (GObject *source,
+ * org.freedesktop.IBus.InputContext interface.
+ */
+ static void
+-_ic_process_key_event (BusInputContext *context,
+- GVariant *parameters,
+- GDBusMethodInvocation *invocation)
++_ic_process_key_event (BusInputContext *context,
++ GVariant *parameters,
++ GDBusMethodInvocation *invocation)
+ {
+ guint keyval = IBUS_KEY_VoidSymbol;
+ guint keycode = 0;
+ guint modifiers = 0;
+
++ if (context->use_post_process_key_event)
++ context->processing_key_event = TRUE;
+ g_variant_get (parameters, "(uuu)", &keyval, &keycode, &modifiers);
+ if (G_UNLIKELY (!context->has_focus)) {
+ /* workaround: set focus if context does not have focus */
+@@ -925,7 +995,8 @@ _ic_process_key_event (BusInputContext *context,
+ /**
+ * _ic_set_cursor_location:
+ *
+- * Implement the "SetCursorLocation" method call of the org.freedesktop.IBus.InputContext interface.
++ * Implement the "SetCursorLocation" method call of the
++ * org.freedesktop.IBus.InputContext interface.
+ */
+ static void
+ _ic_set_cursor_location (BusInputContext *context,
+@@ -1008,7 +1079,8 @@ _ic_process_hand_writing_event (BusInputContext *context,
+ /* do nothing if it is a fake input context */
+ if (context->has_focus &&
+ context->engine && context->fake == FALSE) {
+- bus_engine_proxy_process_hand_writing_event (context->engine, parameters);
++ bus_engine_proxy_process_hand_writing_event (context->engine,
++ parameters);
+ }
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+@@ -1032,7 +1104,8 @@ _ic_cancel_hand_writing (BusInputContext *context,
+ /**
+ * _ic_focus_in:
+ *
+- * Implement the "FocusIn" method call of the org.freedesktop.IBus.InputContext interface.
++ * Implement the "FocusIn" method call of the org.freedesktop.IBus.InputContext
++ * interface.
+ */
+ static void
+ _ic_focus_in (BusInputContext *context,
+@@ -1044,15 +1117,17 @@ _ic_focus_in (BusInputContext *context,
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ else {
+- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+- "The input context does not support focus.");
++ g_dbus_method_invocation_return_error (
++ invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
++ "The input context does not support focus.");
+ }
+ }
+
+ /**
+ * _ic_focus_out:
+ *
+- * Implement the "FocusOut" method call of the org.freedesktop.IBus.InputContext interface.
++ * Implement the "FocusOut" method call of the org.freedesktop.IBus.InputContext
++ * interface.
+ */
+ static void
+ _ic_focus_out (BusInputContext *context,
+@@ -1064,15 +1139,17 @@ _ic_focus_out (BusInputContext *context,
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ else {
+- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+- "The input context does not support focus.");
++ g_dbus_method_invocation_return_error (
++ invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
++ "The input context does not support focus.");
+ }
+ }
+
+ /**
+ * _ic_reset:
+ *
+- * Implement the "Reset" method call of the org.freedesktop.IBus.InputContext interface.
++ * Implement the "Reset" method call of the org.freedesktop.IBus.InputContext
++ * interface.
+ */
+ static void
+ _ic_reset (BusInputContext *context,
+@@ -1094,7 +1171,8 @@ _ic_reset (BusInputContext *context,
+ /**
+ * _ic_set_capabilities:
+ *
+- * Implement the "SetCapabilities" method call of the org.freedesktop.IBus.InputContext interface.
++ * Implement the "SetCapabilities" method call of the
++ * org.freedesktop.IBus.InputContext interface.
+ */
+ static void
+ _ic_set_capabilities (BusInputContext *context,
+@@ -1112,7 +1190,8 @@ _ic_set_capabilities (BusInputContext *context,
+ /**
+ * _ic_property_activate:
+ *
+- * Implement the "PropertyActivate" method call of the org.freedesktop.IBus.InputContext interface.
++ * Implement the "PropertyActivate" method call of the
++ * org.freedesktop.IBus.InputContext interface.
+ */
+ static void
+ _ic_property_activate (BusInputContext *context,
+@@ -1124,7 +1203,9 @@ _ic_property_activate (BusInputContext *context,
+ g_variant_get (parameters, "(&su)", &prop_name, &prop_state);
+
+ if (context->engine) {
+- bus_engine_proxy_property_activate (context->engine, prop_name, prop_state);
++ bus_engine_proxy_property_activate (context->engine,
++ prop_name,
++ prop_state);
+ }
+
+ #ifdef OS_CHROMEOS
+@@ -1132,9 +1213,12 @@ _ic_property_activate (BusInputContext *context,
+ * so pass PropertyActivate signal to the focused context.
+ */
+ else if (context->fake) {
+- 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 && focused_context->engine)
+- bus_engine_proxy_property_activate (focused_context->engine, prop_name, prop_state);
++ bus_engine_proxy_property_activate (focused_context->engine,
++ prop_name,
++ prop_state);
+ }
+ #endif
+
+@@ -1164,7 +1248,8 @@ _ic_set_engine_done (BusInputContext *context,
+ /**
+ * _ic_set_engine:
+ *
+- * Implement the "SetEngine" method call of the org.freedesktop.IBus.InputContext interface.
++ * Implement the "SetEngine" method call of the
++ * org.freedesktop.IBus.InputContext interface.
+ */
+ static void
+ _ic_set_engine (BusInputContext *context,
+@@ -1205,7 +1290,8 @@ _ic_set_engine (BusInputContext *context,
+ /**
+ * _ic_get_engine:
+ *
+- * Implement the "GetEngine" method call of the org.freedesktop.IBus.InputContext interface.
++ * Implement the "GetEngine" method call of
++ * the org.freedesktop.IBus.InputContext interface.
+ */
+ static void
+ _ic_get_engine (BusInputContext *context,
+@@ -1218,7 +1304,9 @@ _ic_get_engine (BusInputContext *context,
+
+
+ g_dbus_method_invocation_return_value (invocation,
+- g_variant_new ("(v)", ibus_serializable_serialize ((IBusSerializable *)desc)));
++ g_variant_new ("(v)",
++ ibus_serializable_serialize (
++ (IBusSerializable *)desc)));
+ }
+
+ static void
+@@ -1270,7 +1358,8 @@ bus_input_context_service_authorized_method (IBusService *service,
+ /**
+ * bus_input_context_service_method_call:
+ *
+- * Handle a D-Bus method call whose destination and interface name are both "org.freedesktop.IBus.InputContext"
++ * Handle a D-Bus method call whose destination and interface name are both
++ * "org.freedesktop.IBus.InputContext"
+ */
+ static void
+ bus_input_context_service_method_call (IBusService *service,
+@@ -1283,21 +1372,23 @@ bus_input_context_service_method_call (IBusService *service,
+ GDBusMethodInvocation *invocation)
+ {
+ if (g_strcmp0 (interface_name, IBUS_INTERFACE_INPUT_CONTEXT) != 0) {
+- IBUS_SERVICE_CLASS (bus_input_context_parent_class)->service_method_call (
+- service,
+- connection,
+- sender,
+- object_path,
+- interface_name,
+- method_name,
+- parameters,
+- invocation);
++ IBUS_SERVICE_CLASS (bus_input_context_parent_class)->
++ service_method_call (service,
++ connection,
++ sender,
++ object_path,
++ interface_name,
++ method_name,
++ parameters,
++ invocation);
+ return;
+ }
+
+ static const struct {
+ const gchar *method_name;
+- void (* method_callback) (BusInputContext *, GVariant *, GDBusMethodInvocation *);
++ void (* method_callback) (BusInputContext *,
++ GVariant *,
++ GDBusMethodInvocation *);
+ } methods [] = {
+ { "ProcessKeyEvent", _ic_process_key_event },
+ { "SetCursorLocation", _ic_set_cursor_location },
+@@ -1322,7 +1413,9 @@ bus_input_context_service_method_call (IBusService *service,
+
+ for (i = 0; i < G_N_ELEMENTS (methods); i++) {
+ if (g_strcmp0 (method_name, methods[i].method_name) == 0) {
+- methods[i].method_callback ((BusInputContext *)service, parameters, invocation);
++ methods[i].method_callback ((BusInputContext *)service,
++ parameters,
++ invocation);
+ return;
+ }
+ }
+@@ -1330,17 +1423,109 @@ bus_input_context_service_method_call (IBusService *service,
+ g_return_if_reached ();
+ }
+
+-static void
++/**
++ * _ic_get_post_process_key_event:
++ *
++ * Implement the "PostProcessKeyEvent" get property of the
++ * org.freedesktop.IBus.InputContext interface because currently the Gio
++ * D-Bus method calls don't support multiple nested tuples likes
++ * G_VARIANT_TYPE ("((ba(yv)))")) in "ProcessKeyEvent" D-Bus method
++ * So these post events are separated from the return value "b" of
++ * the "ProcessKeyEvent" D-Bus method call.
++ */
++static GVariant *
++_ic_get_post_process_key_event (BusInputContext *context,
++ GDBusConnection *connection,
++ GError **error)
++{
++ const char *error_message = NULL;
++ GVariantBuilder array;
++ SyncForwardingData *data;
++
++ do {
++ if (!BUS_IS_INPUT_CONTEXT (context)) {
++ error_message = "BusInputContext is freed";
++ break;
++ }
++ if (context->processing_key_event) {
++ error_message = "Another ProcessKeyEvent is called.";
++ break;
++ }
++ g_variant_builder_init (&array, G_VARIANT_TYPE ("a(yv)"));
++ while ((data =
++ g_queue_pop_head (context->queue_during_process_key_event))) {
++ GVariant *variant = ibus_serializable_serialize_object (
++ IBUS_SERIALIZABLE (data->text));
++ g_variant_builder_add (&array, "(yv)", data->key, variant);
++ g_object_unref (data->text);
++ g_slice_free (SyncForwardingData, data);
++ }
++ } while (FALSE);
++ if (error_message) {
++ g_set_error (error,
++ G_DBUS_ERROR,
++ G_DBUS_ERROR_FAILED,
++ "%s", error_message);
++ return NULL;
++ }
++ return g_variant_builder_end (&array);
++}
++
++static GVariant *
++bus_input_context_service_get_property (IBusService *service,
++ GDBusConnection *connection,
++ const gchar *sender,
++ const gchar *object_path,
++ const gchar *interface_name,
++ const gchar *property_name,
++ GError **error)
++{
++ int i;
++ static const struct {
++ const char *property_name;
++ GVariant * (* property_callback) (BusInputContext *,
++ GDBusConnection *,
++ GError **);
++ } properties [] = {
++ { "PostProcessKeyEvent", _ic_get_post_process_key_event },
++ };
++
++ if (error)
++ *error = NULL;
++ if (g_strcmp0 (interface_name, IBUS_INTERFACE_INPUT_CONTEXT) != 0) {
++ return IBUS_SERVICE_CLASS (bus_input_context_parent_class)->
++ service_get_property (
++ service, connection, sender, object_path,
++ interface_name, property_name,
++ error);
++ }
++ for (i = 0; i < G_N_ELEMENTS (properties); i++) {
++ if (g_strcmp0 (properties[i].property_name, property_name) == 0) {
++ return properties[i].property_callback ((BusInputContext *)service,
++ connection,
++ error);
++ }
++ }
++
++ g_set_error (error,
++ G_DBUS_ERROR,
++ G_DBUS_ERROR_FAILED,
++ "service_get_property received an unknown property: %s",
++ property_name ? property_name : "(null)");
++ g_return_val_if_reached (NULL);
++}
++
++static gboolean
+ _ic_set_content_type (BusInputContext *context,
+- GVariant *value)
++ GVariant *value,
++ GError **error)
+ {
+ guint purpose = 0;
+ guint hints = 0;
++ gboolean retval = TRUE;
+
+ g_variant_get (value, "(uu)", &purpose, &hints);
+ if (purpose != context->purpose || hints != context->hints) {
+- GError *error;
+- gboolean retval;
+
+ context->purpose = purpose;
+ context->hints = hints;
+@@ -1358,24 +1543,30 @@ _ic_set_content_type (BusInputContext *context,
+ context->hints);
+ }
+
+- error = NULL;
+ retval = bus_input_context_property_changed (context,
+ "ContentType",
+ value,
+- &error);
+- if (!retval) {
+- g_warning ("Failed to emit PropertiesChanged signal: %s",
+- error->message);
+- g_error_free (error);
+- }
++ error);
+ }
++ return retval;
+ }
+
+-static void
++static gboolean
+ _ic_set_client_commit_preedit (BusInputContext *context,
+- GVariant *value)
++ GVariant *value,
++ GError **error)
+ {
+ g_variant_get (value, "(b)", &context->client_commit_preedit);
++ return TRUE;
++}
++
++static gboolean
++_ic_set_use_post_process_key_event (BusInputContext *context,
++ GVariant *value,
++ GError **error)
++{
++ g_variant_get (value, "(b)", &context->use_post_process_key_event);
++ return TRUE;
+ }
+
+ static gboolean
+@@ -1388,6 +1579,18 @@ bus_input_context_service_set_property (IBusService *service,
+ GVariant *value,
+ GError **error)
+ {
++ int i;
++ static const struct {
++ const char *property_name;
++ gboolean (* property_callback) (BusInputContext *,
++ GVariant *,
++ GError **);
++ } properties [] = {
++ { "ContentType", _ic_set_content_type },
++ { "ClientCommitPreedit", _ic_set_client_commit_preedit },
++ { "EffectivePostProcessKeyEvent", _ic_set_use_post_process_key_event },
++ };
++
+ if (error)
+ *error = NULL;
+ if (g_strcmp0 (interface_name, IBUS_INTERFACE_INPUT_CONTEXT) != 0) {
+@@ -1418,14 +1621,12 @@ bus_input_context_service_set_property (IBusService *service,
+ " ");
+ return FALSE;
+ }
+-
+- if (g_strcmp0 (property_name, "ContentType") == 0) {
+- _ic_set_content_type (BUS_INPUT_CONTEXT (service), value);
+- return TRUE;
+- }
+- if (g_strcmp0 (property_name, "ClientCommitPreedit") == 0) {
+- _ic_set_client_commit_preedit (BUS_INPUT_CONTEXT (service), value);
+- return TRUE;
++ for (i = 0; i < G_N_ELEMENTS (properties); i++) {
++ if (g_strcmp0 (properties[i].property_name, property_name) == 0) {
++ return properties[i].property_callback ((BusInputContext *) service,
++ value,
++ error);
++ }
+ }
+
+ g_set_error (error,
+@@ -1465,15 +1666,23 @@ bus_input_context_focus_in (BusInputContext *context)
+ 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);
++ 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);
+ }
+
+ if (context->capabilities & IBUS_CAP_FOCUS) {
+ g_signal_emit (context, context_signals[FOCUS_IN], 0);
+ if (context->engine) {
+- /* if necessary, emit glib signals to the context object to update panel status. see the comment for PREEDIT_CONDITION
++ /* if necessary, emit glib signals to the context object to update
++ * panel status. see the comment for PREEDIT_CONDITION
+ * for details. */
+ if (context->preedit_visible && !PREEDIT_CONDITION) {
+ g_signal_emit (context,
+@@ -1483,14 +1692,16 @@ bus_input_context_focus_in (BusInputContext *context)
+ context->preedit_cursor_pos,
+ context->preedit_visible);
+ }
+- if (context->auxiliary_visible && (context->capabilities & IBUS_CAP_AUXILIARY_TEXT) == 0) {
++ if (context->auxiliary_visible &&
++ (context->capabilities & IBUS_CAP_AUXILIARY_TEXT) == 0) {
+ g_signal_emit (context,
+ context_signals[UPDATE_AUXILIARY_TEXT],
+ 0,
+ context->auxiliary_text,
+ context->auxiliary_visible);
+ }
+- if (context->lookup_table_visible && (context->capabilities & IBUS_CAP_LOOKUP_TABLE) == 0) {
++ if (context->lookup_table_visible &&
++ (context->capabilities & IBUS_CAP_LOOKUP_TABLE) == 0) {
+ g_signal_emit (context,
+ context_signals[UPDATE_LOOKUP_TABLE],
+ 0,
+@@ -1630,14 +1841,17 @@ bus_input_context_property_activate (BusInputContext *context,
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ if (context->engine) {
+- bus_engine_proxy_property_activate (context->engine, prop_name, prop_state);
++ bus_engine_proxy_property_activate (context->engine,
++ prop_name,
++ prop_state);
+ }
+ }
+
+ /**
+ * bus_input_context_show_preedit_text:
+ *
+- * Show a preedit text. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Show a preedit text. Send D-Bus signal to update status of client or send
++ * glib signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_show_preedit_text (BusInputContext *context,
+@@ -1678,7 +1892,8 @@ bus_input_context_show_preedit_text (BusInputContext *context,
+ /**
+ * bus_input_context_hide_preedit_text:
+ *
+- * Hide a preedit text. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Hide a preedit text. Send D-Bus signal to update status of client or send
++ * glib signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_hide_preedit_text (BusInputContext *context,
+@@ -1717,7 +1932,8 @@ bus_input_context_hide_preedit_text (BusInputContext *context,
+ /**
+ * bus_input_context_update_auxiliary_text:
+ *
+- * Update an aux text. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Update an aux text. Send D-Bus signal to update status of client or send
++ * glib signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_update_auxiliary_text (BusInputContext *context,
+@@ -1730,11 +1946,13 @@ bus_input_context_update_auxiliary_text (BusInputContext *context,
+ g_object_unref (context->auxiliary_text);
+ }
+
+- context->auxiliary_text = (IBusText *) g_object_ref_sink (text ? text : text_empty);
++ context->auxiliary_text = (IBusText *)g_object_ref_sink (
++ text ? text : text_empty);
+ context->auxiliary_visible = visible;
+
+ if (context->capabilities & IBUS_CAP_AUXILIARY_TEXT) {
+- GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)text);
++ GVariant *variant =
++ ibus_serializable_serialize ((IBusSerializable *)text);
+ bus_input_context_emit_signal (context,
+ "UpdateAuxiliaryText",
+ g_variant_new ("(vb)", variant, visible),
+@@ -1752,7 +1970,8 @@ bus_input_context_update_auxiliary_text (BusInputContext *context,
+ /**
+ * bus_input_context_show_auxiliary_text:
+ *
+- * Show an aux text. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Show an aux text. Send D-Bus signal to update status of client or send glib
++ * signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_show_auxiliary_text (BusInputContext *context)
+@@ -1765,7 +1984,8 @@ bus_input_context_show_auxiliary_text (BusInputContext *context)
+
+ context->auxiliary_visible = TRUE;
+
+- if ((context->capabilities & IBUS_CAP_AUXILIARY_TEXT) == IBUS_CAP_AUXILIARY_TEXT) {
++ if ((context->capabilities & IBUS_CAP_AUXILIARY_TEXT)
++ == IBUS_CAP_AUXILIARY_TEXT) {
+ bus_input_context_emit_signal (context,
+ "ShowAuxiliaryText",
+ NULL,
+@@ -1781,7 +2001,8 @@ bus_input_context_show_auxiliary_text (BusInputContext *context)
+ /**
+ * bus_input_context_hide_auxiliary_text:
+ *
+- * Hide an aux text. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Hide an aux text. Send D-Bus signal to update status of client or send glib
++ * signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_hide_auxiliary_text (BusInputContext *context)
+@@ -1794,7 +2015,8 @@ bus_input_context_hide_auxiliary_text (BusInputContext *context)
+
+ context->auxiliary_visible = FALSE;
+
+- if ((context->capabilities & IBUS_CAP_AUXILIARY_TEXT) == IBUS_CAP_AUXILIARY_TEXT) {
++ if ((context->capabilities & IBUS_CAP_AUXILIARY_TEXT)
++ == IBUS_CAP_AUXILIARY_TEXT) {
+ bus_input_context_emit_signal (context,
+ "HideAuxiliaryText",
+ NULL,
+@@ -1829,11 +2051,13 @@ bus_input_context_update_lookup_table (BusInputContext *context,
+ g_object_unref (context->lookup_table);
+ }
+
+- context->lookup_table = (IBusLookupTable *) g_object_ref_sink (table ? table : lookup_table_empty);
++ context->lookup_table = (IBusLookupTable *)g_object_ref_sink (
++ table ? table : lookup_table_empty);
+ context->lookup_table_visible = visible;
+
+ if (context->capabilities & IBUS_CAP_LOOKUP_TABLE) {
+- GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)table);
++ GVariant *variant =
++ ibus_serializable_serialize ((IBusSerializable *)table);
+ bus_input_context_emit_signal (context,
+ "UpdateLookupTable",
+ g_variant_new ("(vb)", variant, visible),
+@@ -1851,7 +2075,8 @@ bus_input_context_update_lookup_table (BusInputContext *context,
+ /**
+ * bus_input_context_show_lookup_table:
+ *
+- * Show the lookup table. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Show the lookup table. Send D-Bus signal to update status of client or send
++ * glib signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_show_lookup_table (BusInputContext *context)
+@@ -1864,7 +2089,8 @@ bus_input_context_show_lookup_table (BusInputContext *context)
+
+ context->lookup_table_visible = TRUE;
+
+- if ((context->capabilities & IBUS_CAP_LOOKUP_TABLE) == IBUS_CAP_LOOKUP_TABLE) {
++ if ((context->capabilities & IBUS_CAP_LOOKUP_TABLE)
++ == IBUS_CAP_LOOKUP_TABLE) {
+ bus_input_context_emit_signal (context,
+ "ShowLookupTable",
+ NULL,
+@@ -1880,7 +2106,8 @@ bus_input_context_show_lookup_table (BusInputContext *context)
+ /**
+ * bus_input_context_hide_lookup_table:
+ *
+- * Hide the lookup table. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Hide the lookup table. Send D-Bus signal to update status of client or send
++ * glib signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_hide_lookup_table (BusInputContext *context)
+@@ -1893,7 +2120,8 @@ bus_input_context_hide_lookup_table (BusInputContext *context)
+
+ context->lookup_table_visible = FALSE;
+
+- if ((context->capabilities & IBUS_CAP_LOOKUP_TABLE) == IBUS_CAP_LOOKUP_TABLE) {
++ if ((context->capabilities & IBUS_CAP_LOOKUP_TABLE)
++ == IBUS_CAP_LOOKUP_TABLE) {
+ bus_input_context_emit_signal (context,
+ "HideLookupTable",
+ NULL,
+@@ -1909,7 +2137,8 @@ bus_input_context_hide_lookup_table (BusInputContext *context)
+ /**
+ * bus_input_context_page_up_lookup_table:
+ *
+- * Change cursor position. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Change cursor position. Send D-Bus signal to update status of client or send
++ * glib signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_page_up_lookup_table (BusInputContext *context)
+@@ -1920,7 +2149,8 @@ bus_input_context_page_up_lookup_table (BusInputContext *context)
+ return;
+ }
+
+- if ((context->capabilities & IBUS_CAP_LOOKUP_TABLE) == IBUS_CAP_LOOKUP_TABLE) {
++ if ((context->capabilities & IBUS_CAP_LOOKUP_TABLE)
++ == IBUS_CAP_LOOKUP_TABLE) {
+ bus_input_context_emit_signal (context,
+ "PageUpLookupTable",
+ NULL,
+@@ -1936,7 +2166,8 @@ bus_input_context_page_up_lookup_table (BusInputContext *context)
+ /**
+ * bus_input_context_page_down_lookup_table:
+ *
+- * Change cursor position. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Change cursor position. Send D-Bus signal to update status of client or send
++ * glib signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_page_down_lookup_table (BusInputContext *context)
+@@ -1947,7 +2178,8 @@ bus_input_context_page_down_lookup_table (BusInputContext *context)
+ return;
+ }
+
+- if ((context->capabilities & IBUS_CAP_LOOKUP_TABLE) == IBUS_CAP_LOOKUP_TABLE) {
++ if ((context->capabilities & IBUS_CAP_LOOKUP_TABLE)
++ == IBUS_CAP_LOOKUP_TABLE) {
+ bus_input_context_emit_signal (context,
+ "PageDownLookupTable",
+ NULL,
+@@ -1963,7 +2195,8 @@ bus_input_context_page_down_lookup_table (BusInputContext *context)
+ /**
+ * bus_input_context_cursor_up_lookup_table:
+ *
+- * Change cursor position. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Change cursor position. Send D-Bus signal to update status of client or send
++ * glib signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_cursor_up_lookup_table (BusInputContext *context)
+@@ -1974,7 +2207,8 @@ bus_input_context_cursor_up_lookup_table (BusInputContext *context)
+ return;
+ }
+
+- if ((context->capabilities & IBUS_CAP_LOOKUP_TABLE) == IBUS_CAP_LOOKUP_TABLE) {
++ if ((context->capabilities & IBUS_CAP_LOOKUP_TABLE)
++ == IBUS_CAP_LOOKUP_TABLE) {
+ bus_input_context_emit_signal (context,
+ "CursorUpLookupTable",
+ NULL,
+@@ -1990,7 +2224,8 @@ bus_input_context_cursor_up_lookup_table (BusInputContext *context)
+ /**
+ * bus_input_context_cursor_down_lookup_table:
+ *
+- * Change cursor position. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Change cursor position. Send D-Bus signal to update status of client or send
++ * glib signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_cursor_down_lookup_table (BusInputContext *context)
+@@ -2001,7 +2236,8 @@ bus_input_context_cursor_down_lookup_table (BusInputContext *context)
+ return;
+ }
+
+- if ((context->capabilities & IBUS_CAP_LOOKUP_TABLE) == IBUS_CAP_LOOKUP_TABLE) {
++ if ((context->capabilities & IBUS_CAP_LOOKUP_TABLE)
++ == IBUS_CAP_LOOKUP_TABLE) {
+ bus_input_context_emit_signal (context,
+ "CursorDownLookupTable",
+ NULL,
+@@ -2017,7 +2253,8 @@ bus_input_context_cursor_down_lookup_table (BusInputContext *context)
+ /**
+ * bus_input_context_register_properties:
+ *
+- * Register properties. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Register properties. Send D-Bus signal to update status of client or send
++ * glib signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_register_properties (BusInputContext *context,
+@@ -2027,7 +2264,8 @@ bus_input_context_register_properties (BusInputContext *context,
+ g_assert (IBUS_IS_PROP_LIST (props));
+
+ if (context->capabilities & IBUS_CAP_PROPERTY) {
+- GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)props);
++ GVariant *variant =
++ ibus_serializable_serialize ((IBusSerializable *)props);
+ bus_input_context_emit_signal (context,
+ "RegisterProperties",
+ g_variant_new ("(v)", variant),
+@@ -2044,7 +2282,8 @@ bus_input_context_register_properties (BusInputContext *context,
+ /**
+ * bus_input_context_update_property:
+ *
+- * Update property. Send D-Bus signal to update status of client or send glib signal to the panel, depending on capabilities of the client.
++ * Update property. Send D-Bus signal to update status of client or send glib
++ * signal to the panel, depending on capabilities of the client.
+ */
+ static void
+ bus_input_context_update_property (BusInputContext *context,
+@@ -2054,7 +2293,8 @@ bus_input_context_update_property (BusInputContext *context,
+ g_assert (IBUS_IS_PROPERTY (prop));
+
+ if (context->capabilities & IBUS_CAP_PROPERTY) {
+- GVariant *variant = ibus_serializable_serialize ((IBusSerializable *)prop);
++ GVariant *variant =
++ ibus_serializable_serialize ((IBusSerializable *)prop);
+ bus_input_context_emit_signal (context,
+ "UpdateProperty",
+ g_variant_new ("(v)", variant),
+@@ -2089,7 +2329,8 @@ _engine_destroy_cb (BusEngineProxy *engine,
+ /**
+ * _engine_commit_text_cb:
+ *
+- * A function to be called when "commit-text" glib signal is sent to the engine object.
++ * A function to be called when "commit-text" glib signal is sent to the engine
++ * object.
+ */
+ static void
+ _engine_commit_text_cb (BusEngineProxy *engine,
+@@ -2108,7 +2349,8 @@ _engine_commit_text_cb (BusEngineProxy *engine,
+ /**
+ * _engine_forward_key_event_cb:
+ *
+- * A function to be called when "forward-key-event" glib signal is sent to the engine object.
++ * A function to be called when "forward-key-event" glib signal is sent to the
++ * engine object.
+ */
+ static void
+ _engine_forward_key_event_cb (BusEngineProxy *engine,
+@@ -2122,16 +2364,33 @@ _engine_forward_key_event_cb (BusEngineProxy *engine,
+
+ g_assert (context->engine == engine);
+
++ if (context->processing_key_event && g_queue_get_length (
++ context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
++ SyncForwardingData *data;
++ IBusText *text = ibus_text_new_from_printf ("%u,%u,%u",
++ keyval, keycode, state);
++ if (g_queue_get_length (context->queue_during_process_key_event)
++ == MAX_SYNC_DATA) {
++ g_warning ("Exceed max number of post process_key_event data");
++ }
++ data = g_slice_new (SyncForwardingData);
++ data->key = 'f';
++ data->text = text;
++ g_queue_push_tail (context->queue_during_process_key_event, data);
++ return;
++ }
+ bus_input_context_emit_signal (context,
+ "ForwardKeyEvent",
+- g_variant_new ("(uuu)", keyval, keycode, state),
++ g_variant_new ("(uuu)",
++ keyval, keycode, state),
+ NULL);
+ }
+
+ /**
+ * _engine_delete_surrounding_text_cb:
+ *
+- * A function to be called when "delete-surrounding-text" glib signal is sent to the engine object.
++ * A function to be called when "delete-surrounding-text" glib signal is sent
++ * to the engine object.
+ */
+ static void
+ _engine_delete_surrounding_text_cb (BusEngineProxy *engine,
+@@ -2146,14 +2405,16 @@ _engine_delete_surrounding_text_cb (BusEngineProxy *engine,
+
+ bus_input_context_emit_signal (context,
+ "DeleteSurroundingText",
+- g_variant_new ("(iu)", offset_from_cursor, nchars),
++ g_variant_new ("(iu)",
++ offset_from_cursor, nchars),
+ NULL);
+ }
+
+ /**
+ * _engine_require_surrounding_text_cb:
+ *
+- * A function to be called when "require-surrounding-text" glib signal is sent to the engine object.
++ * A function to be called when "require-surrounding-text" glib signal is sent
++ * to the engine object.
+ */
+ static void
+ _engine_require_surrounding_text_cb (BusEngineProxy *engine,
+@@ -2173,7 +2434,8 @@ _engine_require_surrounding_text_cb (BusEngineProxy *engine,
+ /**
+ * _engine_update_preedit_text_cb:
+ *
+- * A function to be called when "update-preedit-text" glib signal is sent to the engine object.
++ * A function to be called when "update-preedit-text" glib signal is sent to
++ * the engine object.
+ */
+ static void
+ _engine_update_preedit_text_cb (BusEngineProxy *engine,
+@@ -2197,7 +2459,8 @@ _engine_update_preedit_text_cb (BusEngineProxy *engine,
+ /**
+ * _engine_update_auxiliary_text_cb:
+ *
+- * A function to be called when "update-auxiliary-text" glib signal is sent to the engine object.
++ * A function to be called when "update-auxiliary-text" glib signal is sent to
++ * the engine object.
+ */
+ static void
+ _engine_update_auxiliary_text_cb (BusEngineProxy *engine,
+@@ -2217,7 +2480,8 @@ _engine_update_auxiliary_text_cb (BusEngineProxy *engine,
+ /**
+ * _engine_update_lookup_table_cb:
+ *
+- * A function to be called when "update-lookup-table" glib signal is sent to the engine object.
++ * A function to be called when "update-lookup-table" glib signal is sent to
++ * the engine object.
+ */
+ static void
+ _engine_update_lookup_table_cb (BusEngineProxy *engine,
+@@ -2237,7 +2501,8 @@ _engine_update_lookup_table_cb (BusEngineProxy *engine,
+ /**
+ * _engine_register_properties_cb:
+ *
+- * A function to be called when "register-properties" glib signal is sent to the engine object.
++ * A function to be called when "register-properties" glib signal is sent to
++ * the engine object.
+ */
+ static void
+ _engine_register_properties_cb (BusEngineProxy *engine,
+@@ -2256,7 +2521,8 @@ _engine_register_properties_cb (BusEngineProxy *engine,
+ /**
+ * _engine_update_property_cb:
+ *
+- * A function to be called when "update-property" glib signal is sent to the engine object.
++ * A function to be called when "update-property" glib signal is sent to the
++ * engine object.
+ */
+ static void
+ _engine_update_property_cb (BusEngineProxy *engine,
+@@ -2346,10 +2612,11 @@ bus_input_context_new (BusConnection *connection,
+
+ BusInputContext *context = NULL;
+ if (connection) {
+- context = (BusInputContext *) g_object_new (BUS_TYPE_INPUT_CONTEXT,
+- "object-path", path,
+- "connection", bus_connection_get_dbus_connection (connection),
+- NULL);
++ context = (BusInputContext *) g_object_new (
++ BUS_TYPE_INPUT_CONTEXT,
++ "object-path", path,
++ "connection", bus_connection_get_dbus_connection (connection),
++ NULL);
+ }
+ else {
+ context = (BusInputContext *) g_object_new (BUS_TYPE_INPUT_CONTEXT,
+@@ -2362,6 +2629,7 @@ bus_input_context_new (BusConnection *connection,
+
+ /* it is a fake input context, just need process hotkey */
+ context->fake = (strncmp (client, "fake", 4) == 0);
++ context->queue_during_process_key_event = g_queue_new ();
+
+ if (connection) {
+ g_object_ref_sink (connection);
+@@ -2439,28 +2707,37 @@ bus_input_context_disable (BusInputContext *context)
+ }
+ }
+
+-/* A list of signals (and their handler functions) that could be emit by the engine proxy object. */
++/* A list of signals (and their handler functions) that could be emit by the
++ * engine proxy object.
++ */
+ const static struct {
+ const gchar *name;
+ GCallback callback;
+ } engine_signals [] = {
+ { "commit-text", G_CALLBACK (_engine_commit_text_cb) },
+ { "forward-key-event", G_CALLBACK (_engine_forward_key_event_cb) },
+- { "delete-surrounding-text", G_CALLBACK (_engine_delete_surrounding_text_cb) },
+- { "require-surrounding-text", G_CALLBACK (_engine_require_surrounding_text_cb) },
++ { "delete-surrounding-text",
++ G_CALLBACK (_engine_delete_surrounding_text_cb) },
++ { "require-surrounding-text",
++ G_CALLBACK (_engine_require_surrounding_text_cb) },
+ { "update-preedit-text", G_CALLBACK (_engine_update_preedit_text_cb) },
+ { "show-preedit-text", G_CALLBACK (_engine_show_preedit_text_cb) },
+ { "hide-preedit-text", G_CALLBACK (_engine_hide_preedit_text_cb) },
+- { "update-auxiliary-text", G_CALLBACK (_engine_update_auxiliary_text_cb) },
++ { "update-auxiliary-text",
++ G_CALLBACK (_engine_update_auxiliary_text_cb) },
+ { "show-auxiliary-text", G_CALLBACK (_engine_show_auxiliary_text_cb) },
+ { "hide-auxiliary-text", G_CALLBACK (_engine_hide_auxiliary_text_cb) },
+ { "update-lookup-table", G_CALLBACK (_engine_update_lookup_table_cb) },
+ { "show-lookup-table", G_CALLBACK (_engine_show_lookup_table_cb) },
+ { "hide-lookup-table", G_CALLBACK (_engine_hide_lookup_table_cb) },
+- { "page-up-lookup-table", G_CALLBACK (_engine_page_up_lookup_table_cb) },
+- { "page-down-lookup-table", G_CALLBACK (_engine_page_down_lookup_table_cb) },
+- { "cursor-up-lookup-table", G_CALLBACK (_engine_cursor_up_lookup_table_cb) },
+- { "cursor-down-lookup-table", G_CALLBACK (_engine_cursor_down_lookup_table_cb) },
++ { "page-up-lookup-table",
++ G_CALLBACK (_engine_page_up_lookup_table_cb) },
++ { "page-down-lookup-table",
++ G_CALLBACK (_engine_page_down_lookup_table_cb) },
++ { "cursor-up-lookup-table",
++ G_CALLBACK (_engine_cursor_up_lookup_table_cb) },
++ { "cursor-down-lookup-table",
++ G_CALLBACK (_engine_cursor_down_lookup_table_cb) },
+ { "register-properties", G_CALLBACK (_engine_register_properties_cb) },
+ { "update-property", G_CALLBACK (_engine_update_property_cb) },
+ { "panel-extension", G_CALLBACK (_engine_panel_extension_cb) },
+@@ -2531,9 +2808,16 @@ bus_input_context_set_engine (BusInputContext *context,
+ 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);
++ 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);
+ }
+ }
+ g_signal_emit (context,
+@@ -2779,7 +3063,8 @@ bus_input_context_set_capabilities (BusInputContext *context,
+ {
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+- /* If the context does not support IBUS_CAP_FOCUS, then the client application have to handle all information such as
++ /* If the context does not support IBUS_CAP_FOCUS, then the client
++ * application have to handle all information such as
+ * preedit and auxiliary text. */
+ if ((capabilities & IBUS_CAP_FOCUS) == 0) {
+ capabilities |= (IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_AUXILIARY_TEXT | IBUS_CAP_LOOKUP_TABLE | IBUS_CAP_PROPERTY);
+@@ -2828,11 +3113,17 @@ bus_input_context_set_content_type (BusInputContext *context,
+ guint hints)
+ {
+ GVariant *value;
++ GError *error = NULL;
+
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+
+ value = g_variant_ref_sink (g_variant_new ("(uu)", purpose, hints));
+- _ic_set_content_type (context, value);
++ _ic_set_content_type (context, value, &error);
++ if (error) {
++ g_warning ("Failed to emit PropertiesChanged signal: %s",
++ error->message);
++ g_error_free (error);
++ }
+ g_variant_unref (value);
+ }
+
+@@ -2842,12 +3133,24 @@ bus_input_context_commit_text_use_extension (BusInputContext *context,
+ gboolean use_extension)
+ {
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
++ g_assert (context->queue_during_process_key_event);
+
+ if (text == text_empty || text == NULL)
+ return;
+
+ if (use_extension && context->emoji_extension) {
+ bus_panel_proxy_commit_text_received (context->emoji_extension, text);
++ } else if (context->processing_key_event && g_queue_get_length (
++ context->queue_during_process_key_event) <= MAX_SYNC_DATA) {
++ SyncForwardingData *data;
++ if (g_queue_get_length (context->queue_during_process_key_event)
++ == MAX_SYNC_DATA) {
++ g_warning ("Exceed max number of sync process_key_event data");
++ }
++ data = g_slice_new (SyncForwardingData);
++ data->key = 'c';
++ data->text = g_object_ref (text);
++ g_queue_push_tail (context->queue_during_process_key_event, data);
+ } else {
+ GVariant *variant = ibus_serializable_serialize (
+ (IBusSerializable *)text);
+diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
+index ea8270bb..8ee85149 100644
+--- a/client/gtk2/ibusimcontext.c
++++ b/client/gtk2/ibusimcontext.c
+@@ -111,7 +111,7 @@ static guint _signal_delete_surrounding_id = 0;
+ static guint _signal_retrieve_surrounding_id = 0;
+
+ #if GTK_CHECK_VERSION (3, 98, 4)
+-static char _use_sync_mode = 2;
++static char _use_sync_mode = 1;
+ #else
+ static const gchar *_no_snooper_apps = NO_SNOOPER_APPS;
+ static gboolean _use_key_snooper = ENABLE_SNOOPER;
+@@ -386,6 +386,23 @@ typedef struct {
+ gboolean retval;
+ } ProcessKeyEventReplyData;
+
++static gboolean
++_process_key_event_sync (IBusInputContext *context,
++ guint keyval,
++ guint keycode,
++ guint state)
++{
++ gboolean retval;
++
++ g_assert (IBUS_IS_INPUT_CONTEXT (context));
++ retval = ibus_input_context_process_key_event (context,
++ keyval,
++ keycode - 8,
++ state);
++ ibus_input_context_post_process_key_event (context);
++ return retval;
++}
++
+ static void
+ _process_key_event_done (GObject *object,
+ GAsyncResult *res,
+@@ -505,10 +522,7 @@ _process_key_event (IBusInputContext *context,
+
+ switch (_use_sync_mode) {
+ case 1: {
+- retval = ibus_input_context_process_key_event (context,
+- keyval,
+- keycode - 8,
+- state);
++ retval = _process_key_event_sync (context, keyval, keycode, state);
+ break;
+ }
+ case 2: {
+@@ -519,10 +533,7 @@ _process_key_event (IBusInputContext *context,
+ 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);
++ retval = _process_key_event_sync (context, keyval, keycode, state);
+ if (source)
+ g_source_destroy (source);
+ break;
+@@ -542,17 +553,19 @@ _process_key_event (IBusInputContext *context,
+ g_source_set_callback (source, _process_key_event_count_cb, data, NULL);
+ while (data->count)
+ g_main_context_iteration (NULL, TRUE);
+- if (source->ref_count > 0) {
+- /* g_source_get_id() could causes a SEGV */
+- g_info ("Broken GSource.ref_count and maybe a timing issue in %p.",
+- source);
+- }
++ /* #2498 Checking source->ref_count might cause Nautilus hang up
++ */
+ retval = data->retval;
+ g_slice_free (ProcessKeyEventReplyData, data);
+ break;
+ }
+ default: {
+ ProcessKeyEventData *data = g_slice_new0 (ProcessKeyEventData);
++ if (!data) {
++ g_warning ("Cannot allocate async data");
++ retval = _process_key_event_sync (context, keyval, keycode, state);
++ break;
++ }
+ #if GTK_CHECK_VERSION (3, 98, 4)
+ data->event = gdk_event_ref (event);
+ #else
+@@ -877,7 +890,7 @@ ibus_im_context_class_init (IBusIMContextClass *class)
+ g_assert (_signal_retrieve_surrounding_id != 0);
+
+ #if GTK_CHECK_VERSION (3, 98, 4)
+- _use_sync_mode = _get_char_env ("IBUS_ENABLE_SYNC_MODE", 2);
++ _use_sync_mode = _get_char_env ("IBUS_ENABLE_SYNC_MODE", 1);
+ #else
+ _use_key_snooper = !_get_boolean_env ("IBUS_DISABLE_SNOOPER",
+ !(ENABLE_SNOOPER));
+@@ -1004,8 +1017,6 @@ ibus_im_context_init (GObject *obj)
+ #else
+ ibusimcontext->caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS;
+ #endif
+- if (_use_sync_mode == 1)
+- ibusimcontext->caps |= IBUS_CAP_SYNC_PROCESS_KEY_V2;
+
+ ibusimcontext->events_queue = g_queue_new ();
+
+@@ -2265,6 +2276,7 @@ _create_input_context_done (IBusBus *bus,
+ else {
+ gboolean requested_surrounding_text = FALSE;
+ ibus_input_context_set_client_commit_preedit (context, TRUE);
++ ibus_input_context_set_post_process_key_event (context, TRUE);
+ ibusimcontext->ibuscontext = context;
+
+ g_signal_connect (ibusimcontext->ibuscontext,
+@@ -2489,9 +2501,8 @@ _create_fake_input_context_done (IBusBus *bus,
+ G_CALLBACK (_ibus_fake_context_destroy_cb),
+ NULL);
+
+- guint32 caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT;
+- if (_use_sync_mode == 1)
+- caps |= IBUS_CAP_SYNC_PROCESS_KEY_V2;
++ guint32 caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS
++ | IBUS_CAP_SURROUNDING_TEXT;
+ ibus_input_context_set_capabilities (_fake_context, caps);
+
+ /* focus in/out the fake context */
+diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c
+index 28ae04ad..def23b25 100644
+--- a/src/ibusinputcontext.c
++++ b/src/ibusinputcontext.c
+@@ -2,7 +2,7 @@
+ /* vim:set et sts=4: */
+ /* ibus - The Input Bus
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+- * Copyright (C) 2018-2022 Takao Fujiwara <takao.fujiwara1@gmail.com>
++ * Copyright (C) 2018-2023 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+@@ -1190,14 +1190,14 @@ ibus_input_context_set_content_type (IBusInputContext *context,
+ g_assert (IBUS_IS_INPUT_CONTEXT (context));
+
+ cached_content_type =
+- g_dbus_proxy_get_cached_property ((GDBusProxy *) context,
++ g_dbus_proxy_get_cached_property ((GDBusProxy *)context,
+ "ContentType");
+ content_type = g_variant_new ("(uu)", purpose, hints);
+
+ g_variant_ref_sink (content_type);
+- if (cached_content_type == NULL ||
++ if (!cached_content_type ||
+ !g_variant_equal (content_type, cached_content_type)) {
+- g_dbus_proxy_call ((GDBusProxy *) context,
++ g_dbus_proxy_call ((GDBusProxy *)context,
+ "org.freedesktop.DBus.Properties.Set",
+ g_variant_new ("(ssv)",
+ IBUS_INTERFACE_INPUT_CONTEXT,
+@@ -1209,9 +1209,13 @@ ibus_input_context_set_content_type (IBusInputContext *context,
+ NULL, /* callback */
+ NULL /* user_data */
+ );
++ /* Need to update the cache by manual since there is a timing issue. */
++ g_dbus_proxy_set_cached_property ((GDBusProxy *)context,
++ "ContentType",
++ content_type);
+ }
+
+- if (cached_content_type != NULL)
++ if (cached_content_type)
+ g_variant_unref (cached_content_type);
+ g_variant_unref (content_type);
+ }
+@@ -1324,19 +1328,20 @@ void
+ ibus_input_context_set_client_commit_preedit (IBusInputContext *context,
+ gboolean client_commit)
+ {
+- GVariant *cached_content_type;
++ GVariant *cached_var_client_commit;
+ GVariant *var_client_commit;
+
+ g_assert (IBUS_IS_INPUT_CONTEXT (context));
+
+- cached_content_type =
+- g_dbus_proxy_get_cached_property ((GDBusProxy *) context,
++ cached_var_client_commit =
++ g_dbus_proxy_get_cached_property ((GDBusProxy *)context,
+ "ClientCommitPreedit");
+ var_client_commit = g_variant_new ("(b)", client_commit);
+
+ g_variant_ref_sink (var_client_commit);
+- if (cached_content_type == NULL) {
+- g_dbus_proxy_call ((GDBusProxy *) context,
++ if (!cached_var_client_commit ||
++ !g_variant_equal (var_client_commit, cached_var_client_commit)) {
++ g_dbus_proxy_call ((GDBusProxy *)context,
+ "org.freedesktop.DBus.Properties.Set",
+ g_variant_new ("(ssv)",
+ IBUS_INTERFACE_INPUT_CONTEXT,
+@@ -1348,13 +1353,146 @@ ibus_input_context_set_client_commit_preedit (IBusInputContext *context,
+ NULL, /* callback */
+ NULL /* user_data */
+ );
++ /* Need to update the cache by manual since there is a timing issue. */
++ g_dbus_proxy_set_cached_property ((GDBusProxy *)context,
++ "ClientCommitPreedit",
++ var_client_commit);
+ }
+
+- if (cached_content_type != NULL)
+- g_variant_unref (cached_content_type);
++ if (cached_var_client_commit)
++ g_variant_unref (cached_var_client_commit);
+ g_variant_unref (var_client_commit);
+ }
+
++void
++ibus_input_context_set_post_process_key_event (IBusInputContext *context,
++ gboolean enable)
++{
++ GVariant *cached_var_post;
++ GVariant *var_post;
++
++ g_assert (IBUS_IS_INPUT_CONTEXT (context));
++
++ cached_var_post =
++ g_dbus_proxy_get_cached_property ((GDBusProxy *)context,
++ "EffectivePostProcessKeyEvent");
++ var_post = g_variant_new ("(b)", enable);
++ g_variant_ref_sink (var_post);
++ if (!cached_var_post ||
++ !g_variant_equal (var_post, cached_var_post)) {
++ g_dbus_proxy_call ((GDBusProxy *)context,
++ "org.freedesktop.DBus.Properties.Set",
++ g_variant_new ("(ssv)",
++ IBUS_INTERFACE_INPUT_CONTEXT,
++ "EffectivePostProcessKeyEvent",
++ var_post),
++ G_DBUS_CALL_FLAGS_NONE,
++ -1,
++ NULL, /* cancellable */
++ NULL, /* callback */
++ NULL /* user_data */
++ );
++ /* Need to update the cache by manual since there is a timing issue. */
++ g_dbus_proxy_set_cached_property ((GDBusProxy *)context,
++ "EffectivePostProcessKeyEvent",
++ var_post);
++ }
++
++ if (cached_var_post)
++ g_variant_unref (cached_var_post);
++ g_variant_unref (var_post);
++}
++
++void
++ibus_input_context_post_process_key_event (IBusInputContext *context)
++{
++ GVariant *cached_var_post;
++ gboolean enable = FALSE;
++ GVariant *result;
++ GError *error = NULL;
++ GVariant *variant = NULL;
++ GVariantIter iter;
++ gsize size;
++ char type = 0;
++ GVariant *vtext = NULL;
++
++ g_assert (IBUS_IS_INPUT_CONTEXT (context));
++
++ cached_var_post =
++ g_dbus_proxy_get_cached_property ((GDBusProxy *)context,
++ "EffectivePostProcessKeyEvent");
++ if (cached_var_post)
++ g_variant_get (cached_var_post, "(b)", &enable);
++ if (!enable) {
++ g_warning ("%s: ibus_input_context_set_post_process_key_event() "
++ "needs to be called before.",
++ G_STRFUNC);
++ if (cached_var_post)
++ g_variant_unref (cached_var_post);
++ return;
++ }
++ g_variant_unref (cached_var_post);
++ result = g_dbus_proxy_call_sync (
++ (GDBusProxy *)context,
++ "org.freedesktop.DBus.Properties.Get",
++ g_variant_new ("(ss)",
++ IBUS_INTERFACE_INPUT_CONTEXT,
++ "PostProcessKeyEvent"),
++ G_DBUS_CALL_FLAGS_NONE,
++ -1,
++ NULL,
++ &error);
++ if (error) {
++ g_warning ("%s: %s", G_STRFUNC, error->message);
++ g_error_free (error);
++ return;
++ }
++
++ g_variant_get (result, "(v)", &variant);
++ g_assert (variant);
++ g_variant_iter_init (&iter, variant);
++ size = g_variant_iter_n_children (&iter);
++ while (size >0 && g_variant_iter_loop (&iter, "(yv)", &type, &vtext)) {
++ IBusText *text =
++ (IBusText *)ibus_serializable_deserialize_object (vtext);
++ if (!IBUS_IS_TEXT (text)) {
++ g_warning ("%s: %s", G_STRFUNC, "text is not IBusText");
++ break;
++ }
++ switch (type) {
++ case 'c':
++ g_signal_emit (context, context_signals[COMMIT_TEXT], 0, text);
++ break;
++ case 'f': {
++ gchar **array = NULL;
++ guint keyval, keycode, state;
++ array = g_strsplit (text->text, ",", -1);
++ keyval = g_ascii_strtoull (array[0], NULL, 10);
++ keycode = g_ascii_strtoull (array[1], NULL, 10);
++ state = g_ascii_strtoull (array[2], NULL, 10);
++ g_strfreev (array);
++ g_signal_emit (context,
++ context_signals[FORWARD_KEY_EVENT],
++ 0,
++ keyval,
++ keycode,
++ state | IBUS_FORWARD_MASK);
++ break;
++ }
++ default:
++ g_warning ("%s: Type '%c' is not supported.", G_STRFUNC, type);
++ }
++ if (g_object_is_floating (text)) {
++ g_object_ref_sink (text);
++ g_object_unref (text);
++ }
++ g_clear_pointer (&vtext, g_variant_unref);
++ }
++
++ g_variant_unref (variant);
++ g_variant_unref (result);
++}
++
+ #define DEFINE_FUNC(name, Name) \
+ void \
+ ibus_input_context_##name (IBusInputContext *context) \
+diff --git a/src/ibusinputcontext.h b/src/ibusinputcontext.h
+index 09992148..1cb5126a 100644
+--- a/src/ibusinputcontext.h
++++ b/src/ibusinputcontext.h
+@@ -2,7 +2,7 @@
+ /* vim:set et sts=4: */
+ /* ibus - The Input Bus
+ * Copyright (C) 2008-2013 Peng Huang <shawn.p.huang@gmail.com>
+- * Copyright (C) 2018 Takao Fujiwara <takao.fujiwara1@gmail.com>
++ * Copyright (C) 2018-2023 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+@@ -298,7 +298,6 @@ gboolean ibus_input_context_process_key_event
+ guint32 keycode,
+ guint32 state);
+
+-
+ /**
+ * ibus_input_context_set_cursor_location:
+ * @context: An IBusInputContext.
+@@ -519,9 +518,32 @@ void ibus_input_context_set_content_type
+ *
+ * See also ibus_engine_update_preedit_text_with_mode().
+ */
+-void ibus_input_context_set_client_commit_preedit (
+- IBusInputContext *context,
++void ibus_input_context_set_client_commit_preedit
++ (IBusInputContext *context,
+ gboolean client_commit);
+
++/**
++ * ibus_input_context_set_post_process_key_event:
++ * @context: An #IBusInputContext.
++ * @enable: Can use ibus_input_context_post_process_key_event() to retrieve
++ * commit-text and forwar-key-event signals during
++ * calling ibus_input_context_process_key_event() if it's %TRUE.
++ */
++void ibus_input_context_set_post_process_key_event
++ (IBusInputContext *context,
++ gboolean enable);
++/**
++ * ibus_input_context_post_process_key_event:
++ * @context: An #IBusInputContext.
++ *
++ * Call this API after ibus_input_context_process_key_event() returns
++ * to retrieve commit-text and forwar-key-event signals during
++ * calling ibus_input_context_process_key_event().
++ *
++ * See also ibus_input_context_set_post_process_key_event().
++ */
++void ibus_input_context_post_process_key_event
++ (IBusInputContext *context);
++
+ G_END_DECLS
+ #endif
+--
+2.41.0
+
+From 1092bfa619749a931d65f80ec49e93b7b31f60f5 Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1@gmail.com>
+Date: Fri, 7 Jul 2023 08:52:51 +0900
+Subject: [PATCH 2/2] client/x11: Fix sync
+ ibus_input_context_process_key_event()
+
+Fix the synchronous "ProcessKeyEvent" D-Bus method in ibus-x11 too.
+
+Fixes: https://github.com/ibus/ibus/commit/8a1bd5f
+
+BUG=https://github.com/ibus/ibus/issues/2486
+---
+ client/x11/main.c | 104 ++++++++++++++++++++++++----------------------
+ 1 file changed, 54 insertions(+), 50 deletions(-)
+
+diff --git a/client/x11/main.c b/client/x11/main.c
+index 83d95cb7..13e7a1cf 100644
+--- a/client/x11/main.c
++++ b/client/x11/main.c
+@@ -126,7 +126,7 @@ static gint g_debug_level = 0;
+
+ static IBusBus *_bus = NULL;
+
+-static char _use_sync_mode = 2;
++static char _use_sync_mode = 1;
+
+ static void
+ _xim_preedit_start (XIMS xims, const X11IC *x11ic)
+@@ -380,9 +380,8 @@ xim_create_ic (XIMS xims, IMChangeICStruct *call_data)
+
+ if (x11ic->input_style & XIMPreeditCallbacks)
+ capabilities |= IBUS_CAP_PREEDIT_TEXT;
+- if (_use_sync_mode == 1)
+- capabilities |= IBUS_CAP_SYNC_PROCESS_KEY_V2;
+ ibus_input_context_set_capabilities (x11ic->context, capabilities);
++ ibus_input_context_set_post_process_key_event (x11ic->context, TRUE);
+
+ g_hash_table_insert (_x11_ic_table,
+ GINT_TO_POINTER (x11ic->icid), (gpointer)x11ic);
+@@ -498,6 +497,26 @@ typedef struct {
+ XEvent event;
+ } ProcessKeyEventReplyData;
+
++static gboolean
++_process_key_event_sync (X11IC *x11ic,
++ IMForwardEventStruct *call_data,
++ GdkEventKey *event)
++{
++ gboolean retval = FALSE;
++
++ g_assert (x11ic);
++ g_assert (call_data);
++ g_assert (event);
++ retval = ibus_input_context_process_key_event (
++ x11ic->context,
++ event->keyval,
++ event->hardware_keycode - 8,
++ event->state);
++ ibus_input_context_post_process_key_event (x11ic->context);
++ _xim_forward_key_event_done (x11ic, &call_data->event, retval);
++ return TRUE;
++}
++
+ static void
+ _process_key_event_done (GObject *object,
+ GAsyncResult *res,
+@@ -609,14 +628,7 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
+
+ switch (_use_sync_mode) {
+ case 1: {
+- retval = ibus_input_context_process_key_event (
+- x11ic->context,
+- event.keyval,
+- event.hardware_keycode - 8,
+- event.state);
+- _xim_forward_key_event_done (x11ic, &call_data->event, retval);
+- retval = 1;
+- break;
++ return _process_key_event_sync (x11ic, call_data, &event);
+ }
+ case 2: {
+ GSource *source = g_timeout_source_new (1);
+@@ -626,44 +638,37 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
+ data = g_slice_new0 (ProcessKeyEventReplyData);
+ if (!data) {
+ g_warning ("Cannot wait for the reply of the process key event.");
+- retval = ibus_input_context_process_key_event (
+- x11ic->context,
+- event.keyval,
+- event.hardware_keycode - 8,
+- event.state);
++ retval = _process_key_event_sync (x11ic, call_data, &event);
+ if (source)
+ g_source_destroy (source);
+- } else {
+- data->count = 1;
+- g_source_attach (source, NULL);
+- g_source_unref (source);
+- data->count_cb_id = g_source_get_id (source);
+- data->connect_id = call_data->connect_id;
+- data->x11ic = x11ic;
+- data->event = *((XEvent*)xevent);
+- ibus_input_context_process_key_event_async (
+- x11ic->context,
+- event.keyval,
+- event.hardware_keycode - 8,
+- event.state,
+- -1,
+- NULL,
+- _process_key_event_reply_done,
+- data);
+- g_source_set_callback (source, _process_key_event_count_cb,
+- data, NULL);
+- while (data->count > 0 && data->count < MAX_WAIT_KEY_TIME)
+- g_main_context_iteration (NULL, TRUE);
+- if (source->ref_count > 0) {
+- /* g_source_get_id() could causes a SEGV */
+- g_info ("Broken GSource.ref_count and maybe a timing "
+- "issue in %p.", source);
+- }
+- retval = data->retval;
+- if (data->count == 0) {
+- g_slice_free (ProcessKeyEventReplyData, data);
+- return 1;
+- }
++ break;
++ }
++ data->count = 1;
++ g_source_attach (source, NULL);
++ g_source_unref (source);
++ data->count_cb_id = g_source_get_id (source);
++ data->connect_id = call_data->connect_id;
++ data->x11ic = x11ic;
++ data->event = *((XEvent*)xevent);
++ ibus_input_context_process_key_event_async (
++ x11ic->context,
++ event.keyval,
++ event.hardware_keycode - 8,
++ event.state,
++ -1,
++ NULL,
++ _process_key_event_reply_done,
++ data);
++ g_source_set_callback (source, _process_key_event_count_cb,
++ data, NULL);
++ while (data->count > 0 && data->count < MAX_WAIT_KEY_TIME)
++ g_main_context_iteration (NULL, TRUE);
++ /* #2498 Checking source->ref_count might cause Nautilus hang up
++ */
++ retval = data->retval;
++ if (data->count == 0) {
++ g_slice_free (ProcessKeyEventReplyData, data);
++ return 1;
+ }
+
+ g_slice_free (ProcessKeyEventReplyData, data);
+@@ -681,8 +686,7 @@ xim_forward_event (XIMS xims, IMForwardEventStruct *call_data)
+
+ if (!(data = g_slice_new0 (ProcessKeyEventReplyData))) {
+ g_warning ("Cannot allocate async data");
+- _xim_forward_key_event_done (x11ic, &call_data->event, 0);
+- return 1;
++ return _process_key_event_sync (x11ic, call_data, &event);
+ }
+ data->connect_id = call_data->connect_id;
+ data->x11ic = x11ic;
+@@ -1186,7 +1190,7 @@ _init_ibus (void)
+ G_CALLBACK (_bus_disconnected_cb), NULL);
+
+ /* https://github.com/ibus/ibus/issues/1713 */
+- _use_sync_mode = _get_char_env ("IBUS_ENABLE_SYNC_MODE", 2);
++ _use_sync_mode = _get_char_env ("IBUS_ENABLE_SYNC_MODE", 1);
+ }
+
+ static void
+--
+2.41.0
+
diff --git a/ibus.spec b/ibus.spec
index d7a6078..c59529a 100644
--- a/ibus.spec
+++ b/ibus.spec
@@ -50,7 +50,7 @@
Name: ibus
Version: 1.5.28
-Release: 10%{?dist}
+Release: 11%{?dist}
Summary: Intelligent Input Bus for Linux OS
License: LGPL-2.0-or-later
URL: https://github.com/ibus/%name/wiki
@@ -557,6 +557,9 @@ dconf update || :
%{_datadir}/installed-tests/ibus
%changelog
+* Fri Jul 07 2023 Takao Fujiwara <tfujiwar@redhat.com> - 1.5.28-11
+- Fix sync ibus_input_context_process_key_event()
+
* Wed Jul 05 2023 Python Maint <python-maint@redhat.com> - 1.5.28-10
- Rebuilt for Python 3.12
reply other threads:[~2026-05-31 2:08 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=178019329196.1.15673619065037637688.rpms-ibus-25ad70d24586@fedoraproject.org \
--to=tfujiwar@redhat.com \
--cc=git-commits@fedoraproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox