diff --git a/modules/input/gtk-text-input.xml b/modules/input/gtk-text-input.xml index a134a19f61..fdc03e077b 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. @@ -251,6 +257,17 @@ + + + Notify when a new composing text (pre-edit) should be set around the + current cursor position. Any previously set composing text should + be removed. + + + + + + Notify when text should be inserted into the editor widget. The text to diff --git a/modules/input/imwayland.c b/modules/input/imwayland.c index 021f556877..5e1a2f00ce 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) { @@ -639,7 +713,6 @@ text_input_enter (void *data, struct wl_surface *surface) { global->focused = TRUE; - if (global->current) enable (GTK_IM_CONTEXT_WAYLAND (global->current)); } @@ -660,6 +733,7 @@ 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 +822,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 +833,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..c806733827 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"); @@ -166,6 +181,16 @@ text_input_preedit (void *data, g_signal_emit_by_name (context, "preedit-end"); } +static void +text_input_preedit (void *data, + struct gtk_text_input *text_input, + const char *text, + guint cursor) +{ + text_input_preedit_with_mode (data, text_input, text, + cursor, IBUS_ENGINE_PREEDIT_CLEAR); +} + static void text_input_commit (void *data, struct gtk_text_input *text_input, @@ -193,6 +218,7 @@ 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 +278,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 +428,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 +474,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 +619,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 +627,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..800262ec48 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. @@ -355,6 +361,35 @@ + + + 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. + + 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. + + + + + + + Notify when text should be inserted into the editor widget. The text to