From 1c5ffb1a7e11b85b2e1f0c16fc34b0322c929fd5 Mon Sep 17 00:00:00 2001 From: Takao Fujiwara Date: Wed, 25 Oct 2023 17:55:00 +0900 Subject: [PATCH] Add preedit D-Bus signals to PostProcessKeyEvent --- ibus-HEAD.patch | 513 ++++++++++++++++++++++++++++++++++++++++++++++++ ibus.spec | 6 +- 2 files changed, 518 insertions(+), 1 deletion(-) diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch index 3f3eae3..a72a0a4 100644 --- a/ibus-HEAD.patch +++ b/ibus-HEAD.patch @@ -1412,3 +1412,516 @@ index def23b25..c6a030fe 100644 -- 2.41.0 +From ef0d29d8bf4e533c428b2cd9d3ee9fa42e9e20e7 Mon Sep 17 00:00:00 2001 +From: fujiwarat +Date: Wed, 25 Oct 2023 16:46:07 +0900 +Subject: [PATCH] src: Add preedit D-Bus signals to PostProcessKeyEvent + +ibus-hangul calls UpdatePreeditText signal during pressing Enter key +to hide the current preedit text and this also causes the reorder issue +in sync process-key-event and need to move the preedit signals +to PostProcessKeyEvent. + +Also refactor PostProcessKeyEvent codes. + +Fixes: https://github.com/ibus/ibus/commit/38f09c6 + +BUG=https://github.com/ibus/ibus/pull/2575 +--- + bus/inputcontext.c | 176 +++++++++++++++++++++++++++-------------- + src/ibusinputcontext.c | 162 +++++++++++++++++++++++++++++-------- + 2 files changed, 248 insertions(+), 90 deletions(-) + +diff --git a/bus/inputcontext.c b/bus/inputcontext.c +index 64430fe4..c914fbd2 100644 +--- a/bus/inputcontext.c ++++ b/bus/inputcontext.c +@@ -48,11 +48,25 @@ struct _SetEngineByDescData { + }; + typedef struct _SetEngineByDescData SetEngineByDescData; + ++typedef struct _DeleteSurroundingData { ++ gint offset; ++ guint nchars; ++} DeleteSurroundingData; ++ + typedef struct _SyncForwardingData { +- gchar key; +- IBusText *text; ++ char key; ++ IBusText *text; + } SyncForwardingData; + ++typedef struct _SyncForwardingPreData { ++ char key; ++ IBusText *text; ++ union { ++ guint uints[3]; ++ DeleteSurroundingData deleting; ++ } u; ++} SyncForwardingPreData; ++ + struct _BusInputContext { + IBusService parent; + +@@ -943,6 +957,7 @@ _ic_process_key_event (BusInputContext *context, + */ + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(b)", TRUE)); ++ context->processing_key_event = FALSE; + return; + } + if (G_UNLIKELY (!context->has_focus)) { +@@ -1005,6 +1020,7 @@ _ic_process_key_event (BusInputContext *context, + else { + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(b)", FALSE)); ++ context->processing_key_event = FALSE; + } + } + +@@ -1654,6 +1670,71 @@ bus_input_context_service_set_property (IBusService *service, + } + + ++static gboolean ++bus_input_context_make_post_process_key_event (BusInputContext *context, ++ SyncForwardingPreData *pre_data) ++{ ++ SyncForwardingData *data; ++ if (context->processing_key_event && g_queue_get_length ( ++ context->queue_during_process_key_event) <= MAX_SYNC_DATA) { ++ if (g_queue_get_length (context->queue_during_process_key_event) ++ == MAX_SYNC_DATA) { ++ g_warning ("Exceed max number of post process_key_event data"); ++ } ++ data = g_slice_new (SyncForwardingData); ++ data->key = pre_data->key; ++ switch (pre_data->key) { ++ case 'c': ++ data->text = g_object_ref (pre_data->text); ++ break; ++ case 'd': ++ data->text = ibus_text_new_from_printf ( ++ "%d,%u", ++ pre_data->u.deleting.offset, ++ pre_data->u.deleting.nchars); ++ break; ++ case 'f': ++ data->text = ibus_text_new_from_printf ("%u,%u,%u", ++ pre_data->u.uints[0], ++ pre_data->u.uints[1], ++ pre_data->u.uints[2]); ++ break; ++ case 'h': ++ case 'r': ++ case 's': ++ data->text = ibus_text_new_from_static_string (""); ++ break; ++ case 'u': ++ case 'm': ++ data->text = g_object_ref (pre_data->text); ++ g_queue_push_tail (context->queue_during_process_key_event, data); ++ data = g_slice_new (SyncForwardingData); ++ data->key = pre_data->key; ++ if (pre_data->key == 'u') { ++ data->text = ibus_text_new_from_printf ( ++ "%u,%u", ++ pre_data->u.uints[0], ++ pre_data->u.uints[1]); ++ } else { ++ data->text = ibus_text_new_from_printf ( ++ "%u,%u,%u", ++ pre_data->u.uints[0], ++ pre_data->u.uints[1], ++ pre_data->u.uints[2]); ++ } ++ break; ++ default: ++ g_warning ("Type %c of SyncForwardingData is not supported", ++ pre_data->key); ++ g_slice_free (SyncForwardingData, data); ++ return FALSE; ++ } ++ g_queue_push_tail (context->queue_during_process_key_event, data); ++ return TRUE; ++ } ++ return FALSE; ++} ++ + gboolean + bus_input_context_has_focus (BusInputContext *context) + { +@@ -1893,6 +1974,9 @@ bus_input_context_show_preedit_text (BusInputContext *context, + } + + if (PREEDIT_CONDITION) { ++ SyncForwardingPreData pre_data = { 's', }; ++ if (bus_input_context_make_post_process_key_event (context, &pre_data)) ++ return; + bus_input_context_emit_signal (context, + "ShowPreeditText", + NULL, +@@ -1933,6 +2017,9 @@ bus_input_context_hide_preedit_text (BusInputContext *context, + } + + if (PREEDIT_CONDITION) { ++ SyncForwardingPreData pre_data = { 'h', }; ++ if (bus_input_context_make_post_process_key_event (context, &pre_data)) ++ return; + bus_input_context_emit_signal (context, + "HidePreeditText", + NULL, +@@ -2375,27 +2462,18 @@ _engine_forward_key_event_cb (BusEngineProxy *engine, + guint state, + BusInputContext *context) + { ++ SyncForwardingPreData pre_data = { 'f', }; ++ + g_assert (BUS_IS_ENGINE_PROXY (engine)); + g_assert (BUS_IS_INPUT_CONTEXT (context)); +- + g_assert (context->engine == engine); + g_assert (context->queue_during_process_key_event); + +- if (context->processing_key_event && g_queue_get_length ( +- context->queue_during_process_key_event) <= MAX_SYNC_DATA) { +- SyncForwardingData *data; +- IBusText *text = ibus_text_new_from_printf ("%u,%u,%u", +- keyval, keycode, state); +- if (g_queue_get_length (context->queue_during_process_key_event) +- == MAX_SYNC_DATA) { +- g_warning ("Exceed max number of post process_key_event data"); +- } +- data = g_slice_new (SyncForwardingData); +- data->key = 'f'; +- data->text = text; +- g_queue_push_tail (context->queue_during_process_key_event, data); ++ pre_data.u.uints[0] = keyval; ++ pre_data.u.uints[1] = keycode; ++ pre_data.u.uints[2] = state; ++ if (bus_input_context_make_post_process_key_event (context, &pre_data)) + return; +- } + bus_input_context_emit_signal (context, + "ForwardKeyEvent", + g_variant_new ("(uuu)", +@@ -2415,26 +2493,16 @@ _engine_delete_surrounding_text_cb (BusEngineProxy *engine, + guint nchars, + BusInputContext *context) + { ++ SyncForwardingPreData pre_data = { 'd', }; ++ + g_assert (BUS_IS_ENGINE_PROXY (engine)); + g_assert (BUS_IS_INPUT_CONTEXT (context)); +- + g_assert (context->engine == engine); + +- if (context->processing_key_event && g_queue_get_length ( +- context->queue_during_process_key_event) <= MAX_SYNC_DATA) { +- SyncForwardingData *data; +- IBusText *text = ibus_text_new_from_printf ("%d,%u", +- offset_from_cursor, nchars); +- if (g_queue_get_length (context->queue_during_process_key_event) +- == MAX_SYNC_DATA) { +- g_warning ("Exceed max number of sync process_key_event data"); +- } +- data = g_slice_new (SyncForwardingData); +- data->key = 'd'; +- data->text = g_object_ref (text); +- g_queue_push_tail (context->queue_during_process_key_event, data); ++ pre_data.u.deleting.offset = offset_from_cursor; ++ pre_data.u.deleting.nchars = nchars; ++ if (bus_input_context_make_post_process_key_event (context, &pre_data)) + return; +- } + bus_input_context_emit_signal (context, + "DeleteSurroundingText", + g_variant_new ("(iu)", +@@ -2452,25 +2520,14 @@ static void + _engine_require_surrounding_text_cb (BusEngineProxy *engine, + BusInputContext *context) + { ++ SyncForwardingPreData pre_data = { 'r', }; ++ + g_assert (BUS_IS_ENGINE_PROXY (engine)); + g_assert (BUS_IS_INPUT_CONTEXT (context)); +- + g_assert (context->engine == engine); + +- if (context->processing_key_event && g_queue_get_length ( +- context->queue_during_process_key_event) <= MAX_SYNC_DATA) { +- SyncForwardingData *data; +- IBusText *text = ibus_text_new_from_static_string (""); +- if (g_queue_get_length (context->queue_during_process_key_event) +- == MAX_SYNC_DATA) { +- g_warning ("Exceed max number of post process_key_event data"); +- } +- data = g_slice_new (SyncForwardingData); +- data->key = 'r'; +- data->text = text; +- g_queue_push_tail (context->queue_during_process_key_event, data); ++ if (bus_input_context_make_post_process_key_event (context, &pre_data)) + return; +- } + bus_input_context_emit_signal (context, + "RequireSurroundingText", + NULL, +@@ -3178,6 +3235,8 @@ bus_input_context_commit_text_use_extension (BusInputContext *context, + IBusText *text, + gboolean use_extension) + { ++ SyncForwardingPreData pre_data = { 'c', text, }; ++ + g_assert (BUS_IS_INPUT_CONTEXT (context)); + g_assert (context->queue_during_process_key_event); + +@@ -3186,17 +3245,9 @@ bus_input_context_commit_text_use_extension (BusInputContext *context, + + if (use_extension && context->emoji_extension) { + bus_panel_proxy_commit_text_received (context->emoji_extension, text); +- } else if (context->processing_key_event && g_queue_get_length ( +- context->queue_during_process_key_event) <= MAX_SYNC_DATA) { +- SyncForwardingData *data; +- if (g_queue_get_length (context->queue_during_process_key_event) +- == MAX_SYNC_DATA) { +- g_warning ("Exceed max number of sync process_key_event data"); +- } +- data = g_slice_new (SyncForwardingData); +- data->key = 'c'; +- data->text = g_object_ref (text); +- g_queue_push_tail (context->queue_during_process_key_event, data); ++ } else if (bus_input_context_make_post_process_key_event (context, ++ &pre_data)) { ++ return; + } else { + GVariant *variant = ibus_serializable_serialize ( + (IBusSerializable *)text); +@@ -3245,9 +3296,18 @@ bus_input_context_update_preedit_text (BusInputContext *context, + context->preedit_cursor_pos, + context->preedit_visible); + } else if (PREEDIT_CONDITION) { ++ SyncForwardingPreData pre_data = { 'u', context->preedit_text, }; + GVariant *variant = ibus_serializable_serialize ( + (IBusSerializable *)context->preedit_text); +- if (context->client_commit_preedit) { ++ pre_data.u.uints[0] = context->preedit_cursor_pos; ++ pre_data.u.uints[1] = extension_visible ? 1 : 0; ++ pre_data.u.uints[2] = context->preedit_mode; ++ if (context->client_commit_preedit) ++ pre_data.key = 'm'; ++ if (bus_input_context_make_post_process_key_event (context, ++ &pre_data)) { ++ return; ++ } else if (context->client_commit_preedit) { + bus_input_context_emit_signal ( + context, + "UpdatePreeditTextWithMode", +diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c +index c6a030fe..1b62f656 100644 +--- a/src/ibusinputcontext.c ++++ b/src/ibusinputcontext.c +@@ -1403,10 +1403,104 @@ ibus_input_context_set_post_process_key_event (IBusInputContext *context, + g_variant_unref (var_post); + } + ++ ++static void ++ibus_input_context_fwd_text_to_commit (IBusInputContext *context, ++ IBusText *text) ++{ ++ g_signal_emit (context, context_signals[COMMIT_TEXT], 0, text); ++} ++ ++ ++static void ++ibus_input_context_fwd_text_to_forward_key_event (IBusInputContext *context, ++ IBusText *text) ++{ ++ gchar **array = NULL; ++ guint keyval, keycode, state; ++ array = g_strsplit (text->text, ",", -1); ++ keyval = g_ascii_strtoull (array[0], NULL, 10); ++ keycode = g_ascii_strtoull (array[1], NULL, 10); ++ state = g_ascii_strtoull (array[2], NULL, 10); ++ g_strfreev (array); ++ g_signal_emit (context, ++ context_signals[FORWARD_KEY_EVENT], ++ 0, ++ keyval, ++ keycode, ++ state | IBUS_FORWARD_MASK); ++} ++ ++ ++static void ++ibus_input_context_fwd_text_to_require_surrounding (IBusInputContext *context, ++ IBusText *text) ++{ ++ IBusInputContextPrivate *priv; ++ g_assert (IBUS_IS_INPUT_CONTEXT (context)); ++ priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context)); ++ priv->needs_surrounding_text = TRUE; ++ g_signal_emit (context, context_signals[REQUIRE_SURROUNDING_TEXT], 0); ++} ++ ++ ++static void ++ibus_input_context_fwd_text_to_delete_surrounding (IBusInputContext *context, ++ IBusText *text) ++{ ++ gchar **array = NULL; ++ gint offset_from_cursor; ++ guint nchars; ++ array = g_strsplit (text->text, ",", -1); ++ offset_from_cursor = g_ascii_strtoll (array[0], NULL, 10); ++ nchars = g_ascii_strtoull (array[1], NULL, 10); ++ g_strfreev (array); ++ g_signal_emit (context, ++ context_signals[DELETE_SURROUNDING_TEXT], ++ 0, ++ offset_from_cursor, ++ nchars); ++} ++ ++ ++static void ++ibus_input_context_fwd_text_to_update_preedit (IBusInputContext *context, ++ IBusText *text, ++ IBusText *position, ++ char type) ++{ ++ gchar **array = NULL; ++ guint32 cursor_pos; ++ gboolean visible; ++ guint mode = 0; ++ ++ array = g_strsplit (position->text, ",", -1); ++ cursor_pos = g_ascii_strtoull (array[0], NULL, 10); ++ visible = g_ascii_strtoull (array[1], NULL, 10) ? TRUE : FALSE; ++ if (type == 'u') { ++ g_signal_emit (context, ++ context_signals[UPDATE_PREEDIT_TEXT], ++ 0, ++ text, ++ cursor_pos, ++ visible); ++ } else { ++ mode = g_ascii_strtoull (array[2], NULL, 10); ++ g_signal_emit (context, ++ context_signals[UPDATE_PREEDIT_TEXT_WITH_MODE], ++ 0, ++ text, ++ cursor_pos, ++ visible, ++ mode); ++ } ++ g_strfreev (array); ++} ++ ++ + void + ibus_input_context_post_process_key_event (IBusInputContext *context) + { +- IBusInputContextPrivate *priv; + GVariant *cached_var_post; + gboolean enable = FALSE; + GVariant *result; +@@ -1419,7 +1513,6 @@ ibus_input_context_post_process_key_event (IBusInputContext *context) + + g_assert (IBUS_IS_INPUT_CONTEXT (context)); + +- priv = IBUS_INPUT_CONTEXT_GET_PRIVATE (IBUS_INPUT_CONTEXT (context)); + cached_var_post = + g_dbus_proxy_get_cached_property ((GDBusProxy *)context, + "EffectivePostProcessKeyEvent"); +@@ -1454,7 +1547,7 @@ ibus_input_context_post_process_key_event (IBusInputContext *context) + g_assert (variant); + g_variant_iter_init (&iter, variant); + size = g_variant_iter_n_children (&iter); +- while (size >0 && g_variant_iter_loop (&iter, "(yv)", &type, &vtext)) { ++ while (size > 0 && g_variant_iter_loop (&iter, "(yv)", &type, &vtext)) { + IBusText *text = + (IBusText *)ibus_serializable_deserialize_object (vtext); + if (!IBUS_IS_TEXT (text)) { +@@ -1463,43 +1556,48 @@ ibus_input_context_post_process_key_event (IBusInputContext *context) + } + switch (type) { + case 'c': +- g_signal_emit (context, context_signals[COMMIT_TEXT], 0, text); ++ ibus_input_context_fwd_text_to_commit (context, text); + break; + case 'f': { +- gchar **array = NULL; +- guint keyval, keycode, state; +- array = g_strsplit (text->text, ",", -1); +- keyval = g_ascii_strtoull (array[0], NULL, 10); +- keycode = g_ascii_strtoull (array[1], NULL, 10); +- state = g_ascii_strtoull (array[2], NULL, 10); +- g_strfreev (array); +- g_signal_emit (context, +- context_signals[FORWARD_KEY_EVENT], +- 0, +- keyval, +- keycode, +- state | IBUS_FORWARD_MASK); ++ ibus_input_context_fwd_text_to_forward_key_event (context, text); + break; + } + case 'r': { +- priv->needs_surrounding_text = TRUE; +- g_signal_emit (context, +- context_signals[REQUIRE_SURROUNDING_TEXT], 0); ++ ibus_input_context_fwd_text_to_require_surrounding (context, text); + break; + } + case 'd': { +- gchar **array = NULL; +- gint offset_from_cursor; +- guint nchars; +- array = g_strsplit (text->text, ",", -1); +- offset_from_cursor = g_ascii_strtoll (array[0], NULL, 10); +- nchars = g_ascii_strtoull (array[1], NULL, 10); +- g_strfreev (array); +- g_signal_emit (context, +- context_signals[DELETE_SURROUNDING_TEXT], +- 0, +- offset_from_cursor, +- nchars); ++ ibus_input_context_fwd_text_to_delete_surrounding (context, text); ++ break; ++ } ++ case 'u': ++ case 'm': { ++ IBusText *position; ++ g_clear_pointer (&vtext, g_variant_unref); ++ if (!g_variant_iter_loop (&iter, "(yv)", &type, &vtext)) { ++ g_warning ("%s: %s", G_STRFUNC, ++ "Type 'u' requires next type 'u'"); ++ break; ++ } ++ if (type != 'u' && type != 'm') { ++ g_warning ("%s: %s", G_STRFUNC, ++ "The next of type 'u' should be type 'u'"); ++ break; ++ } ++ position = ++ (IBusText *)ibus_serializable_deserialize_object (vtext); ++ if (!IBUS_IS_TEXT (position)) { ++ g_warning ("%s: %s", G_STRFUNC, "text is not IBusText"); ++ break; ++ } ++ ibus_input_context_fwd_text_to_update_preedit (context, ++ text, ++ position, ++ type); ++ if (g_object_is_floating (position)) { ++ g_object_ref_sink (position); ++ g_object_unref (position); ++ } + break; + } + default: +-- +2.41.0 + diff --git a/ibus.spec b/ibus.spec index 428a934..839ddec 100644 --- a/ibus.spec +++ b/ibus.spec @@ -58,7 +58,7 @@ Name: ibus Version: 1.5.29~rc1 -Release: 5%{?dist} +Release: 6%{?dist} Summary: Intelligent Input Bus for Linux OS License: LGPL-2.1-or-later URL: https://github.com/ibus/%name/wiki @@ -257,6 +257,7 @@ This package contains IBus IM module for Wayland %package panel Summary: IBus Panel icon Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: %{name}-libs%{?_isa} = %{version}-%{release} BuildRequires: libdbusmenu-gtk3-devel %description panel @@ -579,6 +580,9 @@ dconf update || : %{_datadir}/installed-tests/ibus %changelog +* Wed Oct 25 2023 Takao Fujiwara - 1.5.29~rc1-6 +- Add preedit D-Bus signals to PostProcessKeyEvent + * Mon Oct 23 2023 Takao Fujiwara - 1.5.29~rc1-5 - Add DeleteSurroundingText to PostProcessKeyEvent