diff --git a/modules/input/gtk-text-input.xml b/modules/input/gtk-text-input.xml index a134a19f61..acd77dc250 100644 --- a/modules/input/gtk-text-input.xml +++ b/modules/input/gtk-text-input.xml @@ -214,6 +214,12 @@ + + + Reset the input method state. + + + Notification that this seat's text-input focus is on a certain surface. @@ -241,14 +247,15 @@ - - + + Notify when a new composing text (pre-edit) should be set around the current cursor position. Any previously set composing text should be removed. + diff --git a/modules/input/imwayland.c b/modules/input/imwayland.c index 021f556877..9bc2fe2530 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,7 @@ 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 @@ -266,6 +283,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 +525,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 +661,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 +690,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); } } @@ -659,7 +721,7 @@ text_input_leave (void *data, static const struct zwp_text_input_v3_listener text_input_listener = { text_input_enter, text_input_leave, - text_input_preedit, + text_input_preedit_with_mode, text_input_commit, text_input_delete_surrounding_text, text_input_done, @@ -748,7 +810,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 +821,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/imwaylandgtk.c b/modules/input/imwaylandgtk.c index 1d5050496a..0a26678949 100644 --- a/modules/input/imwaylandgtk.c +++ b/modules/input/imwaylandgtk.c @@ -27,6 +27,11 @@ #include "gdk/wayland/gdkwayland.h" #include "gtk-text-input-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; @@ -66,6 +71,7 @@ struct _GtkIMContextWayland struct { gchar *text; gint cursor_idx; + guint mode; } preedit; cairo_rectangle_int_t cursor_rect; @@ -98,6 +104,13 @@ static const GtkIMContextInfo *info_list[] = #define MODULE_ENTRY(type, function) type _gtk_immodule_wayland_ ## function #endif +static void +commit_state (GtkIMContextWayland *context); +static void +notify_surrounding_text (GtkIMContextWayland *context); +static void +gtk_im_context_wayland_reset (GtkIMContext *context); + static void reset_preedit (GtkIMContextWayland *context) { @@ -136,10 +149,11 @@ text_input_leave (void *data, } static void -text_input_preedit (void *data, - struct gtk_text_input *text_input, - const char *text, - guint cursor) +text_input_preedit_with_mode (void *data, + struct gtk_text_input *text_input, + const char *text, + guint cursor, + guint mode) { GtkIMContextWayland *context; gboolean state_change; @@ -159,6 +173,7 @@ text_input_preedit (void *data, g_free (context->preedit.text); context->preedit.text = g_strdup (text); context->preedit.cursor_idx = cursor; + context->preedit.mode = mode; g_signal_emit_by_name (context, "preedit-changed"); @@ -192,7 +207,7 @@ text_input_delete_surrounding_text (void *data, static const struct gtk_text_input_listener text_input_listener = { text_input_enter, text_input_leave, - text_input_preedit, + text_input_preedit_with_mode, text_input_commit, text_input_delete_surrounding_text }; @@ -252,6 +267,33 @@ gtk_im_context_wayland_global_init (GdkDisplay *display) wl_registry_add_listener (global->registry, ®istry_listener, 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->preedit.text && + context->preedit.mode == IBUS_ENGINE_PREEDIT_COMMIT) + { + preedit_string = g_strdup (context->preedit.text); + } + + text_input_preedit_with_mode (global, global->text_input, NULL, 0, IBUS_ENGINE_PREEDIT_CLEAR); + + if (preedit_string) + { + text_input_commit (global, global->text_input, preedit_string); + g_free (preedit_string); + notify_surrounding_text (context); + commit_state (context); + } +} + static void notify_surrounding_text (GtkIMContextWayland *context) { @@ -375,6 +417,14 @@ commit_state (GtkIMContextWayland *context) gtk_text_input_commit (global->text_input); } +static void +notify_reset (GtkIMContextWayland *context) +{ + if (global->current != GTK_IM_CONTEXT (context)) + return; + gtk_text_input_reset (global->text_input); +} + static void enable_text_input (GtkIMContextWayland *context, gboolean toggle_panel) @@ -413,6 +463,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)); + } } } @@ -551,6 +608,7 @@ gtk_im_context_wayland_focus_out (GtkIMContext *context) if (global->current != context) return; + clear_preedit_text (GTK_IM_CONTEXT_WAYLAND (context)); gtk_text_input_disable (global->text_input); global->current = NULL; } @@ -558,6 +616,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); + reset_preedit (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..a9d96cde51 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. @@ -329,8 +335,16 @@ - - + + + 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. @@ -341,6 +355,9 @@ 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. @@ -353,6 +370,7 @@ +