From 9f8438f1e764afc0e9cbb44a5c82cecb2a442d7c Mon Sep 17 00:00:00 2001
From: Peng Wu <pwu@redhat.com>
Date: Fri, 27 Mar 2020 15:35:25 +0800
Subject: [PATCH 1/3] Update the wayland text input protocol

Copy the new text input v3 protocol from the wayland-protocols project.

https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/71
---
 modules/input/text-input-unstable-v3.xml | 43 ++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 3 deletions(-)

diff --git a/modules/input/text-input-unstable-v3.xml b/modules/input/text-input-unstable-v3.xml
index 8b710fd68b..6d602adf7d 100644
--- a/modules/input/text-input-unstable-v3.xml
+++ b/modules/input/text-input-unstable-v3.xml
@@ -47,7 +47,7 @@
     interface version number is reset.
   </description>
 
-  <interface name="zwp_text_input_v3" version="1">
+  <interface name="zwp_text_input_v3" version="2">
     <description summary="text input">
       The zwp_text_input_v3 interface represents text input and input methods
       associated with a seat. It provides enter/leave events to follow the
@@ -94,6 +94,12 @@
         zwp_text_input_v3.disable when there is no longer any input focus on
         the current surface.
 
+        Clients must not enable more than one text input on the single seat
+        and should disable the current text input before enabling the new one.
+        At most one instance of text input may be in enabled state per instance,
+        Requests to enable the another text input when some text input is active
+        must be ignored by compositor.
+
         This request resets all state associated with previous enable, disable,
         set_surrounding_text, set_text_change_cause, set_content_type, and
         set_cursor_rectangle requests, as well as the state associated with
@@ -307,6 +313,9 @@
       <description summary="enter event">
         Notification that this seat's text-input focus is on a certain surface.
 
+        If client has created multiple text input objects, compositor must send
+        this event to all of them.
+
         When the seat has the keyboard capability the text-input focus follows
         the keyboard focus. This event sets the current surface for the
         text-input object.
@@ -321,7 +330,9 @@
         set.
 
         The leave notification clears the current surface. It is sent before
-        the enter notification for the new focus.
+        the enter notification for the new focus. After leave event, compositor
+        must ignore requests from any text input instances until next enter
+        event.
 
         When the seat has the keyboard capability the text-input focus follows
         the keyboard focus.
@@ -417,9 +428,35 @@
       </description>
       <arg name="serial" type="uint"/>
     </event>
+
+    <enum name="commit_mode">
+      <description summary="focus commit mode">
+        Pre-edit commit mode when the focus widget or the cursor position
+        is changed.
+      </description>
+      <entry name="clear" value="0" summary="pre-edit text is cleared."/>
+      <entry name="commit" value="1" summary="pre-edit text is committed."/>
+    </enum>
+
+    <event name="preedit_commit_mode" since="2">
+      <description summary="pre-edit commit mode">
+        Specify how the visible preedit should be handled
+        when switching the focus widget or changing the cursor position,
+        whether to commit the preedit text or clear the preedit text.
+
+        This is usually used together with the preedit_string event.
+
+        The commit behavior is the same for focus switch and
+        cursor position change.
+
+        The parameter mode selects the desired behavior and
+        its value is one from the commit mode enum.
+      </description>
+      <arg name="mode" type="uint" enum="commit_mode"/>
+    </event>
   </interface>
 
-  <interface name="zwp_text_input_manager_v3" version="1">
+  <interface name="zwp_text_input_manager_v3" version="2">
     <description summary="text input manager">
       A factory for text-input objects. This object is a global singleton.
     </description>
-- 
2.30.2


From 058c386136a6e6909bd9c67ec379711f5549a1ef Mon Sep 17 00:00:00 2001
From: Peng Wu <pwu@redhat.com>
Date: Sat, 9 May 2020 11:44:14 +0800
Subject: [PATCH 2/3] imwayland: Support ibus update_preedit_string_with_mode
 feature

The ibus_engine_update_preedit_text_with_mode function allows to specify
the behavior of focus out when the pre-edit buffer is visible.

Switch to use ibus_engine_update_preedit_text_with_mode instead of
ibus_engine_update_preedit_text in the gtk project.
---
 modules/input/imwayland.c | 95 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 92 insertions(+), 3 deletions(-)

diff --git a/modules/input/imwayland.c b/modules/input/imwayland.c
index cf0b1e2144..075951c3cd 100644
--- a/modules/input/imwayland.c
+++ b/modules/input/imwayland.c
@@ -58,6 +58,7 @@ struct preedit {
   gchar *text;
   gint cursor_begin;
   gint cursor_end;
+  guint mode;
 };
 
 struct surrounding_delete {
@@ -123,6 +124,15 @@ static void gtk_im_context_wayland_focus_out (GtkIMContext *context);
 #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)
 {
@@ -157,6 +167,23 @@ 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 = ZWP_TEXT_INPUT_V3_COMMIT_MODE_CLEAR;
+}
+
+static void
+text_input_preedit_commit_mode (void                     *data,
+                                struct zwp_text_input_v3 *text_input,
+                                guint                     mode)
+{
+  GtkIMContextWayland *context;
+  GtkIMContextWaylandGlobal *global = data;
+
+  if (!global->current)
+    return;
+
+  context = GTK_IM_CONTEXT_WAYLAND (global->current);
+
+  context->pending_preedit.mode = mode;
 }
 
 static void
@@ -272,6 +299,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 == ZWP_TEXT_INPUT_V3_COMMIT_MODE_COMMIT)
+    {
+      preedit_string = g_strdup (context->current_preedit.text);
+    }
+
+  text_input_preedit (global, global->text_input, NULL, 0, 0);
+  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)
 {
@@ -579,6 +635,16 @@ 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_disable (global->text_input);
+  zwp_text_input_v3_enable (global->text_input);
+}
+
 static void
 enable (GtkIMContextWayland *context_wayland)
 {
@@ -605,11 +671,11 @@ disable (GtkIMContextWayland *context_wayland)
   if (context_wayland->current_preedit.text)
     {
       text_input_preedit (global, global->text_input, NULL, 0, 0);
+      text_input_preedit_commit_mode (global, global->text_input, ZWP_TEXT_INPUT_V3_COMMIT_MODE_CLEAR);
       text_input_preedit_apply (global);
     }
 }
 
-
 static void
 pressed_cb (GtkGestureMultiPress *gesture,
             gint                  n_press,
@@ -621,6 +687,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));
+        }
     }
 }
 
@@ -707,7 +780,12 @@ text_input_leave (void                     *data,
   global->focused = FALSE;
 
   if (global->current)
-    disable (GTK_IM_CONTEXT_WAYLAND (global->current));
+    {
+      GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (global->current);
+
+      clear_preedit_text (context_wayland);
+      disable (context_wayland);
+    }
 }
 
 
@@ -718,6 +796,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_commit_mode,
 };
 
 static void
@@ -803,7 +882,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;
 }
@@ -811,6 +893,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);
-- 
2.30.2


From b9ce44971e5b943954e078e515b10d2469f1ecda Mon Sep 17 00:00:00 2001
From: Peng Wu <pwu@redhat.com>
Date: Tue, 23 Feb 2021 17:39:34 +0800
Subject: [PATCH 3/3] imwayland: negotiate the text input protocol version

Negotiate with the server about to use which version of the text input
protocol.
---
 modules/input/imwayland.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/modules/input/imwayland.c b/modules/input/imwayland.c
index 075951c3cd..df56f226bd 100644
--- a/modules/input/imwayland.c
+++ b/modules/input/imwayland.c
@@ -804,17 +804,19 @@ registry_handle_global (void               *data,
                         struct wl_registry *registry,
                         uint32_t            id,
                         const char         *interface,
-                        uint32_t            version)
+                        uint32_t            server_version)
 {
   GtkIMContextWaylandGlobal *global = data;
   GdkSeat *seat = gdk_display_get_default_seat (gdk_display_get_default ());
 
   if (strcmp (interface, "zwp_text_input_manager_v3") == 0)
     {
+      const uint32_t client_version = 2;
+      uint32_t bind_version = MIN(client_version, server_version);
       global->text_input_manager_wl_id = id;
       global->text_input_manager =
         wl_registry_bind (global->registry, global->text_input_manager_wl_id,
-                          &zwp_text_input_manager_v3_interface, 1);
+                          &zwp_text_input_manager_v3_interface, bind_version);
       global->text_input =
         zwp_text_input_manager_v3_get_text_input (global->text_input_manager,
                                                   gdk_wayland_seat_get_wl_seat (seat));
-- 
2.30.2

