diff --git a/modules/input/imwayland.c b/modules/input/imwayland.c index 021f556877..f5e23f4888 100644 --- a/modules/input/imwayland.c +++ b/modules/input/imwayland.c @@ -28,6 +28,11 @@ #include "gdk/wayland/gdkwayland.h" #include "text-input-unstable-v3-client-protocol.h" +typedef enum { + IBUS_ENGINE_PREEDIT_CLEAR = 0, + IBUS_ENGINE_PREEDIT_COMMIT = 1, +} IBusPreeditFocusMode; + typedef struct _GtkIMContextWaylandGlobal GtkIMContextWaylandGlobal; typedef struct _GtkIMContextWayland GtkIMContextWayland; typedef struct _GtkIMContextWaylandClass GtkIMContextWaylandClass; @@ -58,6 +63,7 @@ struct preedit { gchar *text; gint cursor_begin; gint cursor_end; + guint mode; }; struct surrounding_delete { @@ -120,6 +126,15 @@ static const GtkIMContextInfo *info_list[] = #define MODULE_ENTRY(type, function) type _gtk_immodule_wayland_ ## function #endif +static void +notify_surrounding_text (GtkIMContextWayland *context); +static void +commit_state (GtkIMContextWayland *context); +static void +clear_preedit_text (GtkIMContextWayland *context); +static void +gtk_im_context_wayland_reset (GtkIMContext *context); + static void notify_external_change (GtkIMContextWayland *context) { @@ -133,11 +148,12 @@ notify_external_change (GtkIMContextWayland *context) } static void -text_input_preedit (void *data, - struct zwp_text_input_v3 *text_input, - const char *text, - gint cursor_begin, - gint cursor_end) +text_input_preedit_with_mode (void *data, + struct zwp_text_input_v3 *text_input, + const char *text, + gint cursor_begin, + gint cursor_end, + guint mode) { GtkIMContextWayland *context; GtkIMContextWaylandGlobal *global = data; @@ -151,6 +167,19 @@ text_input_preedit (void *data, context->pending_preedit.text = g_strdup (text); context->pending_preedit.cursor_begin = cursor_begin; context->pending_preedit.cursor_end = cursor_end; + context->pending_preedit.mode = mode; +} + +static void +text_input_preedit (void *data, + struct zwp_text_input_v3 *text_input, + const char *text, + gint cursor_begin, + gint cursor_end) +{ + text_input_preedit_with_mode (data, text_input, text, + cursor_begin, cursor_end, + IBUS_ENGINE_PREEDIT_CLEAR); } static void @@ -266,6 +295,35 @@ text_input_done (void *data, text_input_preedit_apply(global); } +static void +clear_preedit_text (GtkIMContextWayland *context) +{ + gchar *preedit_string = NULL; + + if (!global || !global->text_input) + return; + if (global->current != GTK_IM_CONTEXT (context)) + return; + + if (context->current_preedit.text && + context->current_preedit.mode == IBUS_ENGINE_PREEDIT_COMMIT) + { + preedit_string = g_strdup (context->current_preedit.text); + } + + text_input_preedit_with_mode (global, global->text_input, NULL, 0, 0, IBUS_ENGINE_PREEDIT_CLEAR); + text_input_preedit_apply (global); + + if (preedit_string) + { + text_input_commit (global, global->text_input, preedit_string); + text_input_commit_apply (global, TRUE); + g_free (preedit_string); + notify_surrounding_text (context); + commit_state (context); + } +} + static void notify_surrounding_text (GtkIMContextWayland *context) { @@ -479,6 +537,13 @@ pressed_cb (GtkGestureMultiPress *gesture, { context->press_x = x; context->press_y = y; + + /* clear the preedit text before the client commit. */ + if (global->current == GTK_IM_CONTEXT (context)) + { + clear_preedit_text (context); + gtk_im_context_wayland_reset (GTK_IM_CONTEXT (context)); + } } } @@ -608,6 +673,15 @@ gtk_im_context_wayland_filter_keypress (GtkIMContext *context, return GTK_IM_CONTEXT_CLASS (parent_class)->filter_keypress (context, key); } +static void +notify_reset (GtkIMContextWayland *context_wayland) +{ + if (global->current != GTK_IM_CONTEXT (context_wayland)) + return; + + zwp_text_input_v3_reset (global->text_input); +} + static void enable (GtkIMContextWayland *context_wayland) { @@ -628,7 +702,7 @@ disable (GtkIMContextWayland *context_wayland) /* after disable, incoming state changes won't take effect anyway */ if (context_wayland->current_preedit.text) { - text_input_preedit (global, global->text_input, NULL, 0, 0); + text_input_preedit_with_mode (global, global->text_input, NULL, 0, 0, IBUS_ENGINE_PREEDIT_CLEAR); text_input_preedit_apply (global); } } @@ -663,6 +737,7 @@ static const struct zwp_text_input_v3_listener text_input_listener = { text_input_commit, text_input_delete_surrounding_text, text_input_done, + text_input_preedit_with_mode, }; static void @@ -748,7 +823,10 @@ gtk_im_context_wayland_focus_out (GtkIMContext *context) return; if (global->focused) - disable (context_wayland); + { + clear_preedit_text (context_wayland); + disable (context_wayland); + } global->current = NULL; } @@ -756,6 +834,13 @@ gtk_im_context_wayland_focus_out (GtkIMContext *context) static void gtk_im_context_wayland_reset (GtkIMContext *context) { + GtkIMContextWayland *context_wayland; + + context_wayland = GTK_IM_CONTEXT_WAYLAND (context); + + notify_reset (context_wayland); + commit_state (context_wayland); + notify_external_change (GTK_IM_CONTEXT_WAYLAND (context)); GTK_IM_CONTEXT_CLASS (parent_class)->reset (context); diff --git a/modules/input/text-input-unstable-v3.xml b/modules/input/text-input-unstable-v3.xml index 8b710fd68b..44786bf586 100644 --- a/modules/input/text-input-unstable-v3.xml +++ b/modules/input/text-input-unstable-v3.xml @@ -303,6 +303,12 @@ + + + Reset the input method state. + + + Notification that this seat's text-input focus is on a certain surface. @@ -417,6 +423,44 @@ + + + + Pre-edit commit mode when the focus is lost. + + + + + + + + Notify when a new composing text (pre-edit) should be set at the + current cursor position. Any previously set composing text must be + removed. Any previously existing selected text must be removed. + + The argument text contains the pre-edit string buffer. + + The parameters cursor_begin and cursor_end are counted in bytes + relative to the beginning of the submitted text buffer. Cursor should + be hidden when both are equal to -1. + + The parameter mode is the commit mode to specify the behavior + on focus out when the pre-edit buffer is visible. + + They could be represented by the client as a line if both values are + the same, or as a text highlight otherwise. + + Values set with this event are double-buffered. They must be applied + and reset to initial on the next zwp_text_input_v3.done event. + + The initial value of text is an empty string, and cursor_begin, + cursor_end and cursor_hidden are all 0. + + + + + +