From da866a79167fac79e59030d74a2af1999d934abd Mon Sep 17 00:00:00 2001
From: Peng Wu <pwu@redhat.com>
Date: Thu, 6 Aug 2020 15:39:40 +0800
Subject: [PATCH 1/2] wayland/text-input: Support ibus
 update_preedit_string_with_mode feature

The ibus_engine_update_preedit_text_with_mode function allows to specify
the behavior on 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 mutter project.
---
 clutter/clutter/clutter-event.h               |  2 ++
 clutter/clutter/clutter-input-focus-private.h |  4 +++
 clutter/clutter/clutter-input-focus.c         | 16 +++++++++--
 clutter/clutter/clutter-input-focus.h         |  7 +++--
 clutter/clutter/clutter-input-method.c        | 28 ++++++++++++++++---
 clutter/clutter/clutter-input-method.h        |  6 ++++
 clutter/clutter/clutter-text.c                |  9 +++---
 src/wayland/meta-wayland-text-input-legacy.c  |  9 +++---
 src/wayland/meta-wayland-text-input.c         | 26 ++++++++++++++---
 9 files changed, 85 insertions(+), 22 deletions(-)

diff --git a/clutter/clutter/clutter-event.h b/clutter/clutter/clutter-event.h
index b77e64d15..b536fee7e 100644
--- a/clutter/clutter/clutter-event.h
+++ b/clutter/clutter/clutter-event.h
@@ -561,6 +561,8 @@ struct _ClutterIMEvent
   char *text;
   int32_t offset;
   uint32_t len;
+  /* preedit_commit_mode */
+  uint32_t mode;
 };
 
 /**
diff --git a/clutter/clutter/clutter-input-focus-private.h b/clutter/clutter/clutter-input-focus-private.h
index ccde45d0e..bb3c59e13 100644
--- a/clutter/clutter/clutter-input-focus-private.h
+++ b/clutter/clutter/clutter-input-focus-private.h
@@ -36,5 +36,9 @@ void clutter_input_focus_request_surrounding (ClutterInputFocus *focus);
 void clutter_input_focus_set_preedit_text (ClutterInputFocus *focus,
                                            const gchar       *preedit,
                                            guint              cursor);
+void clutter_input_focus_set_preedit_text_with_mode (ClutterInputFocus *focus,
+                                                     const char        *preedit,
+                                                     unsigned int       cursor,
+                                                     unsigned int       mode);
 
 #endif /* __CLUTTER_INPUT_FOCUS_PRIVATE_H__ */
diff --git a/clutter/clutter/clutter-input-focus.c b/clutter/clutter/clutter-input-focus.c
index 2aea51e24..4061387d6 100644
--- a/clutter/clutter/clutter-input-focus.c
+++ b/clutter/clutter/clutter-input-focus.c
@@ -175,8 +175,9 @@ clutter_input_focus_filter_event (ClutterInputFocus  *focus,
     }
   else if (event->type == CLUTTER_IM_PREEDIT)
     {
-      clutter_input_focus_set_preedit_text (focus, event->im.text,
-                                            event->im.offset);
+      clutter_input_focus_set_preedit_text_with_mode (focus, event->im.text,
+                                                      event->im.offset,
+                                                      event->im.mode);
       return TRUE;
     }
 
@@ -260,8 +261,17 @@ void
 clutter_input_focus_set_preedit_text (ClutterInputFocus *focus,
                                       const gchar       *preedit,
                                       guint              cursor)
+{
+  clutter_input_focus_set_preedit_text_with_mode (focus, preedit, cursor, 0);
+}
+
+void
+clutter_input_focus_set_preedit_text_with_mode (ClutterInputFocus *focus,
+                                                const char        *preedit,
+                                                unsigned int       cursor,
+                                                unsigned int       mode)
 {
   g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
 
-  CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->set_preedit_text (focus, preedit, cursor);
+  CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->set_preedit_text_with_mode (focus, preedit, cursor, mode);
 }
diff --git a/clutter/clutter/clutter-input-focus.h b/clutter/clutter/clutter-input-focus.h
index 77f5d9076..4b9025b71 100644
--- a/clutter/clutter/clutter-input-focus.h
+++ b/clutter/clutter/clutter-input-focus.h
@@ -46,9 +46,10 @@ struct _ClutterInputFocusClass
   void (* commit_text) (ClutterInputFocus *focus,
                         const gchar       *text);
 
-  void (* set_preedit_text) (ClutterInputFocus *focus,
-                             const gchar       *preedit,
-                             guint              cursor);
+  void (* set_preedit_text_with_mode) (ClutterInputFocus *focus,
+                                       const gchar       *preedit,
+                                       guint              cursor,
+                                       guint              mode);
 };
 
 CLUTTER_EXPORT
diff --git a/clutter/clutter/clutter-input-method.c b/clutter/clutter/clutter-input-method.c
index b24df2e80..edeacd2f2 100644
--- a/clutter/clutter/clutter-input-method.c
+++ b/clutter/clutter/clutter-input-method.c
@@ -282,7 +282,8 @@ clutter_input_method_put_im_event (ClutterInputMethod *im,
                                    ClutterEventType    event_type,
                                    const char         *text,
                                    int32_t             offset,
-                                   uint32_t            len)
+                                   uint32_t            len,
+                                   uint32_t            mode)
 {
   ClutterInputDevice *keyboard;
   ClutterSeat *seat;
@@ -299,6 +300,7 @@ clutter_input_method_put_im_event (ClutterInputMethod *im,
   event->im.text = g_strdup (text);
   event->im.offset = offset;
   event->im.len = len;
+  event->im.mode = mode;
   clutter_event_set_device (event, keyboard);
   clutter_event_set_source_device (event, keyboard);
   clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_INPUT_METHOD);
@@ -315,7 +317,7 @@ clutter_input_method_commit (ClutterInputMethod *im,
 {
   g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
 
-  clutter_input_method_put_im_event (im, CLUTTER_IM_COMMIT, text, 0, 0);
+  clutter_input_method_put_im_event (im, CLUTTER_IM_COMMIT, text, 0, 0, 0);
 }
 
 void
@@ -325,7 +327,7 @@ clutter_input_method_delete_surrounding (ClutterInputMethod *im,
 {
   g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
 
-  clutter_input_method_put_im_event (im, CLUTTER_IM_DELETE, NULL, offset, len);
+  clutter_input_method_put_im_event (im, CLUTTER_IM_DELETE, NULL, offset, len, 0);
 }
 
 void
@@ -352,10 +354,28 @@ void
 clutter_input_method_set_preedit_text (ClutterInputMethod *im,
                                        const gchar        *preedit,
                                        guint               cursor)
+{
+  clutter_input_method_set_preedit_text_with_mode (im, preedit, cursor, 0);
+}
+
+/**
+ * clutter_input_method_set_preedit_text_with_mode:
+ * @im: a #ClutterInputMethod
+ * @preedit: (nullable): the preedit text, or %NULL
+ * @cursor: the cursor
+ * @mode: the commit mode
+ *
+ * Sets the preedit with commit mode on the current input focus.
+ **/
+void
+clutter_input_method_set_preedit_text_with_mode (ClutterInputMethod *im,
+                                                 const gchar        *preedit,
+                                                 guint               cursor,
+                                                 guint               mode)
 {
   g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
 
-  clutter_input_method_put_im_event (im, CLUTTER_IM_PREEDIT, preedit, cursor, 0);
+  clutter_input_method_put_im_event (im, CLUTTER_IM_PREEDIT, preedit, cursor, 0, mode);
 }
 
 void
diff --git a/clutter/clutter/clutter-input-method.h b/clutter/clutter/clutter-input-method.h
index b7f9a474e..82742e80d 100644
--- a/clutter/clutter/clutter-input-method.h
+++ b/clutter/clutter/clutter-input-method.h
@@ -78,6 +78,12 @@ void clutter_input_method_set_preedit_text (ClutterInputMethod *im,
                                             const gchar        *preedit,
                                             guint               cursor);
 
+CLUTTER_EXPORT
+void clutter_input_method_set_preedit_text_with_mode (ClutterInputMethod *im,
+                                                      const gchar        *preedit,
+                                                      guint               cursor,
+                                                      guint               mode);
+
 CLUTTER_EXPORT
 void clutter_input_method_notify_key_event (ClutterInputMethod *im,
                                             const ClutterEvent *event,
diff --git a/clutter/clutter/clutter-text.c b/clutter/clutter/clutter-text.c
index 45c7eac56..a48ad80fc 100644
--- a/clutter/clutter/clutter-text.c
+++ b/clutter/clutter/clutter-text.c
@@ -380,9 +380,10 @@ clutter_text_input_focus_commit_text (ClutterInputFocus *focus,
 }
 
 static void
-clutter_text_input_focus_set_preedit_text (ClutterInputFocus *focus,
-                                           const gchar       *preedit_text,
-                                           guint              cursor_pos)
+clutter_text_input_focus_set_preedit_text_with_mode (ClutterInputFocus *focus,
+                                                     const char        *preedit_text,
+                                                     unsigned int       cursor_pos,
+                                                     unsigned int       mode)
 {
   ClutterText *clutter_text = CLUTTER_TEXT_INPUT_FOCUS (focus)->text;
 
@@ -407,7 +408,7 @@ clutter_text_input_focus_class_init (ClutterTextInputFocusClass *klass)
   focus_class->request_surrounding = clutter_text_input_focus_request_surrounding;
   focus_class->delete_surrounding = clutter_text_input_focus_delete_surrounding;
   focus_class->commit_text = clutter_text_input_focus_commit_text;
-  focus_class->set_preedit_text = clutter_text_input_focus_set_preedit_text;
+  focus_class->set_preedit_text_with_mode = clutter_text_input_focus_set_preedit_text_with_mode;
 }
 
 static void
diff --git a/src/wayland/meta-wayland-text-input-legacy.c b/src/wayland/meta-wayland-text-input-legacy.c
index 442708e0f..38d63b4ef 100644
--- a/src/wayland/meta-wayland-text-input-legacy.c
+++ b/src/wayland/meta-wayland-text-input-legacy.c
@@ -132,9 +132,10 @@ meta_wayland_text_input_focus_commit_text (ClutterInputFocus *focus,
 }
 
 static void
-meta_wayland_text_input_focus_set_preedit_text (ClutterInputFocus *focus,
-                                                const gchar       *text,
-                                                guint              cursor)
+meta_wayland_text_input_focus_set_preedit_text_with_mode (ClutterInputFocus *focus,
+							  const char        *text,
+							  unsigned int       cursor,
+							  unsigned int       mode)
 {
   MetaWaylandGtkTextInput *text_input;
   struct wl_resource *resource;
@@ -155,7 +156,7 @@ meta_wayland_gtk_text_input_focus_class_init (MetaWaylandGtkTextInputFocusClass
   focus_class->request_surrounding = meta_wayland_text_input_focus_request_surrounding;
   focus_class->delete_surrounding = meta_wayland_text_input_focus_delete_surrounding;
   focus_class->commit_text = meta_wayland_text_input_focus_commit_text;
-  focus_class->set_preedit_text = meta_wayland_text_input_focus_set_preedit_text;
+  focus_class->set_preedit_text_with_mode = meta_wayland_text_input_focus_set_preedit_text_with_mode;
 }
 
 static void
diff --git a/src/wayland/meta-wayland-text-input.c b/src/wayland/meta-wayland-text-input.c
index b471e8e1a..b126f1f12 100644
--- a/src/wayland/meta-wayland-text-input.c
+++ b/src/wayland/meta-wayland-text-input.c
@@ -41,6 +41,7 @@ typedef enum
   META_WAYLAND_PENDING_STATE_SURROUNDING_TEXT = 1 << 2,
   META_WAYLAND_PENDING_STATE_CHANGE_CAUSE     = 1 << 3,
   META_WAYLAND_PENDING_STATE_ENABLED          = 1 << 4,
+  META_WAYLAND_PENDING_STATE_RESET            = 1 << 5,
 } MetaWaylandTextInputPendingState;
 
 typedef struct _MetaWaylandTextInput MetaWaylandTextInput;
@@ -221,6 +222,7 @@ meta_wayland_text_input_focus_commit_text (ClutterInputFocus *focus,
   wl_resource_for_each (resource, &text_input->focus_resource_list)
     {
       zwp_text_input_v3_send_preedit_string (resource, NULL, 0, 0);
+      zwp_text_input_v3_send_preedit_commit_mode (resource, ZWP_TEXT_INPUT_V3_COMMIT_MODE_CLEAR);
       zwp_text_input_v3_send_commit_string (resource, text);
     }
 
@@ -228,9 +230,10 @@ meta_wayland_text_input_focus_commit_text (ClutterInputFocus *focus,
 }
 
 static void
-meta_wayland_text_input_focus_set_preedit_text (ClutterInputFocus *focus,
-                                                const gchar       *text,
-                                                guint              cursor)
+meta_wayland_text_input_focus_set_preedit_text_with_mode (ClutterInputFocus *focus,
+                                                          const gchar       *text,
+                                                          guint              cursor,
+                                                          guint              mode)
 {
   MetaWaylandTextInput *text_input;
   struct wl_resource *resource;
@@ -244,6 +247,7 @@ meta_wayland_text_input_focus_set_preedit_text (ClutterInputFocus *focus,
   wl_resource_for_each (resource, &text_input->focus_resource_list)
     {
       zwp_text_input_v3_send_preedit_string (resource, text, pos, pos);
+      zwp_text_input_v3_send_preedit_commit_mode (resource, mode);
     }
 
   meta_wayland_text_input_focus_defer_done (focus);
@@ -257,7 +261,7 @@ meta_wayland_text_input_focus_class_init (MetaWaylandTextInputFocusClass *klass)
   focus_class->request_surrounding = meta_wayland_text_input_focus_request_surrounding;
   focus_class->delete_surrounding = meta_wayland_text_input_focus_delete_surrounding;
   focus_class->commit_text = meta_wayland_text_input_focus_commit_text;
-  focus_class->set_preedit_text = meta_wayland_text_input_focus_set_preedit_text;
+  focus_class->set_preedit_text_with_mode = meta_wayland_text_input_focus_set_preedit_text_with_mode;
 }
 
 static void
@@ -393,6 +397,17 @@ text_input_enable (struct wl_client   *client,
 {
   MetaWaylandTextInput *text_input = wl_resource_get_user_data (resource);
 
+  /* check whether this is the disable/enable/commit sequence.
+     if so, then send the reset request. */
+
+  if (text_input->pending_state & META_WAYLAND_PENDING_STATE_ENABLED &&
+      !text_input->enabled)
+    {
+      text_input->pending_state &= ~META_WAYLAND_PENDING_STATE_ENABLED;
+      text_input->pending_state |= META_WAYLAND_PENDING_STATE_RESET;
+      return;
+    }
+
   text_input->enabled = TRUE;
   text_input->pending_state |= META_WAYLAND_PENDING_STATE_ENABLED;
 }
@@ -621,6 +636,9 @@ text_input_commit_state (struct wl_client   *client,
                                                &cursor_rect);
     }
 
+  if (text_input->pending_state & META_WAYLAND_PENDING_STATE_RESET)
+    clutter_input_focus_reset (text_input->input_focus);
+
   meta_wayland_text_input_reset (text_input);
 
   if (enable_panel)
-- 
2.30.2


From e783d870ad82dcab98869f29c9ef76493302cc31 Mon Sep 17 00:00:00 2001
From: Peng Wu <pwu@redhat.com>
Date: Tue, 23 Feb 2021 17:26:14 +0800
Subject: [PATCH 2/2] wayland/text-input: Negotiate the text input protocol
 version

Negotiate with the client about to use which version of the text input
protocol.
---
 src/wayland/meta-wayland-text-input.c | 17 ++++++++++++-----
 src/wayland/meta-wayland-versions.h   |  2 +-
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/src/wayland/meta-wayland-text-input.c b/src/wayland/meta-wayland-text-input.c
index b126f1f12..e506e4de6 100644
--- a/src/wayland/meta-wayland-text-input.c
+++ b/src/wayland/meta-wayland-text-input.c
@@ -222,7 +222,9 @@ meta_wayland_text_input_focus_commit_text (ClutterInputFocus *focus,
   wl_resource_for_each (resource, &text_input->focus_resource_list)
     {
       zwp_text_input_v3_send_preedit_string (resource, NULL, 0, 0);
-      zwp_text_input_v3_send_preedit_commit_mode (resource, ZWP_TEXT_INPUT_V3_COMMIT_MODE_CLEAR);
+      if (wl_resource_get_version (resource) >=
+          ZWP_TEXT_INPUT_V3_PREEDIT_COMMIT_MODE_SINCE_VERSION)
+          zwp_text_input_v3_send_preedit_commit_mode (resource, ZWP_TEXT_INPUT_V3_COMMIT_MODE_CLEAR);
       zwp_text_input_v3_send_commit_string (resource, text);
     }
 
@@ -247,7 +249,9 @@ meta_wayland_text_input_focus_set_preedit_text_with_mode (ClutterInputFocus *foc
   wl_resource_for_each (resource, &text_input->focus_resource_list)
     {
       zwp_text_input_v3_send_preedit_string (resource, text, pos, pos);
-      zwp_text_input_v3_send_preedit_commit_mode (resource, mode);
+      if (wl_resource_get_version (resource) >=
+          ZWP_TEXT_INPUT_V3_PREEDIT_COMMIT_MODE_SINCE_VERSION)
+          zwp_text_input_v3_send_preedit_commit_mode (resource, mode);
     }
 
   meta_wayland_text_input_focus_defer_done (focus);
@@ -687,13 +691,14 @@ static void
 meta_wayland_text_input_create_new_resource (MetaWaylandTextInput *text_input,
                                              struct wl_client     *client,
                                              struct wl_resource   *seat_resource,
+                                             int                   version,
                                              uint32_t              id)
 {
   struct wl_resource *text_input_resource;
 
   text_input_resource = wl_resource_create (client,
                                             &zwp_text_input_v3_interface,
-                                            META_ZWP_TEXT_INPUT_V3_VERSION,
+                                            version,
                                             id);
 
   wl_resource_set_implementation (text_input_resource,
@@ -732,7 +737,9 @@ text_input_manager_get_text_input (struct wl_client   *client,
   MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
 
   meta_wayland_text_input_create_new_resource (seat->text_input, client,
-                                               seat_resource, id);
+                                               seat_resource,
+                                               wl_resource_get_version (resource),
+                                               id);
 }
 
 static struct zwp_text_input_manager_v3_interface meta_text_input_manager_interface = {
@@ -750,7 +757,7 @@ bind_text_input (struct wl_client *client,
 
   resource = wl_resource_create (client,
                                  &zwp_text_input_manager_v3_interface,
-                                 META_ZWP_TEXT_INPUT_V3_VERSION,
+                                 version,
                                  id);
   wl_resource_set_implementation (resource,
                                   &meta_text_input_manager_interface,
diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h
index 8f71c19dc..9a04a035c 100644
--- a/src/wayland/meta-wayland-versions.h
+++ b/src/wayland/meta-wayland-versions.h
@@ -53,7 +53,7 @@
 #define META_ZXDG_OUTPUT_V1_VERSION         3
 #define META_ZWP_XWAYLAND_KEYBOARD_GRAB_V1_VERSION 1
 #define META_GTK_TEXT_INPUT_VERSION         1
-#define META_ZWP_TEXT_INPUT_V3_VERSION      1
+#define META_ZWP_TEXT_INPUT_V3_VERSION      2
 #define META_WP_VIEWPORTER_VERSION          1
 #define META_GTK_PRIMARY_SELECTION_VERSION  1
 #define META_ZWP_PRIMARY_SELECTION_V1_VERSION 1
-- 
2.30.2

