[gtk/gtk-3-24: 1/9] gtkimcontextwayland: Refactor handling of client updates




commit a2f579eca8fe1d9a3e8b4922727fd94cd11c0116
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu Aug 18 00:58:38 2022 +0200

    gtkimcontextwayland: Refactor handling of client updates
    
    Currently, the wayland IM context sends zwp_text_input_v3.commit from
    a number of places, and some of them with partial data. In order to
    make client state updates "atomic" and complete, make the communication
    happen over an unified notify_im_change() function that happens on
    a narrower set of circumstances:
    
      - The GtkIMContext is reset
      - The GtkIMContext is just focused
      - The gesture to invoke the OSK is triggered
      - The IM context is reacting to changes coming from the compositor
    
    Notably, setting the cursor location or the surrounding text do not try
    to commit state on their own, and now will be flushed with the corresponding
    IM update or reset. But also, these requests won't be prevented from
    happening individually on serial mismatch, instead it will be the whole
    state commit which is held off.
    
    With these changes in place, all client-side updates are notified
    atomically to the compositor under a single .commit request.

 modules/input/imwayland.c | 51 +++++++++++++++++++++++++++++------------------
 1 file changed, 32 insertions(+), 19 deletions(-)
---
diff --git a/modules/input/imwayland.c b/modules/input/imwayland.c
index 1e93123aa2..facb9f2d31 100644
--- a/modules/input/imwayland.c
+++ b/modules/input/imwayland.c
@@ -116,6 +116,11 @@ static const GtkIMContextInfo *info_list[] =
 
 static void gtk_im_context_wayland_focus_out (GtkIMContext *context);
 
+static void commit_state (GtkIMContextWayland *context);
+static void notify_surrounding_text (GtkIMContextWayland *context);
+static void notify_cursor_location (GtkIMContextWayland *context);
+static void notify_content_type (GtkIMContextWayland *context);
+
 #define GTK_IM_CONTEXT_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), type_wayland, GtkIMContextWayland))
 
 #ifndef INCLUDE_IM_wayland
@@ -125,7 +130,8 @@ static void gtk_im_context_wayland_focus_out (GtkIMContext *context);
 #endif
 
 static void
-notify_external_change (GtkIMContextWayland *context)
+notify_im_change (GtkIMContextWayland                 *context,
+                  enum zwp_text_input_v3_change_cause  cause)
 {
   gboolean result;
 
@@ -135,8 +141,12 @@ notify_external_change (GtkIMContextWayland *context)
   if (!context->enabled)
     return;
 
-  context->surrounding_change = ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_OTHER;
+  context->surrounding_change = cause;
   g_signal_emit_by_name (global->current, "retrieve-surrounding", &result);
+  notify_surrounding_text (context);
+  notify_content_type (context);
+  notify_cursor_location (context);
+  commit_state (context);
 }
 
 static void
@@ -262,17 +272,25 @@ text_input_done (void                     *data,
                  uint32_t                  serial)
 {
   GtkIMContextWaylandGlobal *global = data;
-  gboolean result;
+  GtkIMContextWayland *context;
+  gboolean update_im;
 
   global->done_serial = serial;
 
   if (!global->current)
     return;
 
+  context = GTK_IM_CONTEXT_WAYLAND (global->current);
+  update_im = (context->pending_commit != NULL ||
+               g_strcmp0 (context->pending_preedit.text,
+                          context->current_preedit.text) != 0);
+
   text_input_delete_surrounding_text_apply (global);
   text_input_commit_apply (global);
-  g_signal_emit_by_name (global->current, "retrieve-surrounding", &result);
   text_input_preedit_apply (global);
+
+  if (update_im && global->serial == serial)
+    notify_im_change (context, ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD);
 }
 
 static void
@@ -289,8 +307,6 @@ notify_surrounding_text (GtkIMContextWayland *context)
     return;
   if (!context->enabled || !context->surrounding.text)
     return;
-  if (global->done_serial != global->serial)
-    return;
 
   len = strlen (context->surrounding.text);
   cursor = context->surrounding.cursor_idx;
@@ -366,8 +382,6 @@ notify_cursor_location (GtkIMContextWayland *context)
     return;
   if (!context->enabled || !context->window)
     return;
-  if (global->done_serial != global->serial)
-    return;
 
   rect = context->cursor_rect;
   gdk_window_get_root_coords (context->window, rect.x, rect.y,
@@ -450,8 +464,6 @@ notify_content_type (GtkIMContextWayland *context)
 
   if (!context->enabled)
     return;
-  if (global->done_serial != global->serial)
-    return;
 
   g_object_get (context,
                 "input-hints", &hints,
@@ -592,16 +604,13 @@ gtk_im_context_wayland_filter_keypress (GtkIMContext *context,
 static void
 enable (GtkIMContextWayland *context_wayland)
 {
-  gboolean result;
   /* Technically, text input isn't enabled until after the commit.
    * In reality, enable can't fail, and notify functions need to know
    * that they are free to send requests. */
   context_wayland->enabled = TRUE;
   zwp_text_input_v3_enable (global->text_input);
-  g_signal_emit_by_name (global->current, "retrieve-surrounding", &result);
-  notify_content_type (context_wayland);
-  notify_cursor_location (context_wayland);
-  commit_state (context_wayland);
+  notify_im_change (context_wayland,
+                    ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_OTHER);
 }
 
 static void
@@ -611,6 +620,12 @@ disable (GtkIMContextWayland *context_wayland)
   commit_state (context_wayland);
   context_wayland->enabled = FALSE;
 
+  /* The commit above will still count in the .done event accounting,
+   * we should account for it, lest the serial gets out of sync after
+   * a future focus_in/enable.
+   */
+  global->done_serial++;
+
   /* after disable, incoming state changes won't take effect anyway */
   if (context_wayland->current_preedit.text)
     {
@@ -821,7 +836,8 @@ gtk_im_context_wayland_focus_out (GtkIMContext *context)
 static void
 gtk_im_context_wayland_reset (GtkIMContext *context)
 {
-  notify_external_change (GTK_IM_CONTEXT_WAYLAND (context));
+  notify_im_change (GTK_IM_CONTEXT_WAYLAND (context),
+                    ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_OTHER);
 
   GTK_IM_CONTEXT_CLASS (parent_class)->reset (context);
 }
@@ -856,8 +872,6 @@ gtk_im_context_wayland_set_cursor_location (GtkIMContext *context,
     gtk_event_controller_reset (GTK_EVENT_CONTROLLER (context_wayland->gesture));
 
   context_wayland->cursor_rect = *rect;
-  notify_cursor_location (context_wayland);
-  commit_state (context_wayland);
 }
 
 static void
@@ -893,7 +907,6 @@ gtk_im_context_wayland_set_surrounding (GtkIMContext *context,
   context_wayland->surrounding.anchor_idx = cursor_index;
 
   notify_surrounding_text (context_wayland);
-  commit_state (context_wayland);
 }
 
 static gboolean


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]