commit e0293aec49f89658e1734c0a4fc07cf1f4eb8628
Author: Peng Wu <pwu@redhat.com>
Date:   Wed Mar 25 15:42:44 2020 +0800

    wayland/text-input: Support ibus update_preedit_string_with_mode feature

diff --git a/clutter/clutter/clutter-input-focus-private.h b/clutter/clutter/clutter-input-focus-private.h
index 563e58978..825fa63a0 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 gchar       *preedit,
+                                                     guint              cursor,
+                                                     guint              mode);
 
 #endif /* __CLUTTER_INPUT_FOCUS_PRIVATE_H__ */
diff --git a/clutter/clutter/clutter-input-focus.c b/clutter/clutter/clutter-input-focus.c
index d54494b0f..e4c9ee767 100644
--- a/clutter/clutter/clutter-input-focus.c
+++ b/clutter/clutter/clutter-input-focus.c
@@ -242,3 +242,14 @@ clutter_input_focus_set_preedit_text (ClutterInputFocus *focus,
 
   CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->set_preedit_text (focus, preedit, cursor);
 }
+
+void
+clutter_input_focus_set_preedit_text_with_mode (ClutterInputFocus *focus,
+                                                const gchar       *preedit,
+                                                guint              cursor,
+                                                guint              mode)
+{
+  g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
+
+  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 3f971fec4..1d32e1ea5 100644
--- a/clutter/clutter/clutter-input-focus.h
+++ b/clutter/clutter/clutter-input-focus.h
@@ -49,6 +49,10 @@ struct _ClutterInputFocusClass
   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 344e19297..c5a88814d 100644
--- a/clutter/clutter/clutter-input-method.c
+++ b/clutter/clutter/clutter-input-method.c
@@ -338,6 +338,30 @@ clutter_input_method_set_preedit_text (ClutterInputMethod *im,
     clutter_input_focus_set_preedit_text (priv->focus, preedit, cursor);
 }
 
+/**
+ * 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 text 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)
+{
+  ClutterInputMethodPrivate *priv;
+
+  g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
+
+  priv = clutter_input_method_get_instance_private (im);
+  if (priv->focus)
+    clutter_input_focus_set_preedit_text_with_mode (priv->focus, preedit, cursor, mode);
+}
+
 void
 clutter_input_method_notify_key_event (ClutterInputMethod *im,
                                        const ClutterEvent *event,
diff --git a/clutter/clutter/clutter-input-method.h b/clutter/clutter/clutter-input-method.h
index ba1bc223a..4818f7954 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/src/wayland/meta-wayland-text-input-legacy.c b/src/wayland/meta-wayland-text-input-legacy.c
index d4caa9aad..00821911f 100644
--- a/src/wayland/meta-wayland-text-input-legacy.c
+++ b/src/wayland/meta-wayland-text-input-legacy.c
@@ -38,6 +38,7 @@ typedef enum
   META_WAYLAND_PENDING_STATE_INPUT_RECT       = 1 << 0,
   META_WAYLAND_PENDING_STATE_CONTENT_TYPE     = 1 << 1,
   META_WAYLAND_PENDING_STATE_SURROUNDING_TEXT = 1 << 2,
+  META_WAYLAND_PENDING_STATE_RESET            = 1 << 3,
 } MetaWaylandTextInputPendingState;
 
 typedef struct _MetaWaylandGtkTextInput MetaWaylandGtkTextInput;
@@ -140,6 +141,23 @@ meta_wayland_text_input_focus_set_preedit_text (ClutterInputFocus *focus,
     }
 }
 
+static void
+meta_wayland_text_input_focus_set_preedit_text_with_mode (ClutterInputFocus *focus,
+                                                          const gchar       *text,
+                                                          guint              cursor,
+                                                          guint              mode)
+{
+  MetaWaylandGtkTextInput *text_input;
+  struct wl_resource *resource;
+
+  text_input = META_WAYLAND_GTK_TEXT_INPUT_FOCUS (focus)->text_input;
+
+  wl_resource_for_each (resource, &text_input->focus_resource_list)
+    {
+      gtk_text_input_send_preedit_string_with_mode (resource, text, cursor, mode);
+    }
+}
+
 static void
 meta_wayland_gtk_text_input_focus_class_init (MetaWaylandGtkTextInputFocusClass *klass)
 {
@@ -149,6 +167,7 @@ meta_wayland_gtk_text_input_focus_class_init (MetaWaylandGtkTextInputFocusClass
   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
@@ -492,9 +511,26 @@ 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);
+    }
+
   text_input->pending_state = META_WAYLAND_PENDING_STATE_NONE;
 }
 
+static void
+text_input_reset (struct wl_client   *client,
+                  struct wl_resource *resource)
+{
+  MetaWaylandGtkTextInput *text_input = wl_resource_get_user_data (resource);
+
+  if (!text_input->surface)
+    return;
+
+  text_input->pending_state |= META_WAYLAND_PENDING_STATE_RESET;
+}
+
 static struct gtk_text_input_interface meta_text_input_interface = {
   text_input_destroy,
   text_input_enable,
@@ -503,6 +539,7 @@ static struct gtk_text_input_interface meta_text_input_interface = {
   text_input_set_content_type,
   text_input_set_cursor_rectangle,
   text_input_commit_state,
+  text_input_reset,
 };
 
 MetaWaylandGtkTextInput *
diff --git a/src/wayland/meta-wayland-text-input.c b/src/wayland/meta-wayland-text-input.c
index d63f489bd..4b23e4cea 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;
@@ -218,6 +219,25 @@ meta_wayland_text_input_focus_set_preedit_text (ClutterInputFocus *focus,
   meta_wayland_text_input_focus_defer_done (focus);
 }
 
+static void
+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;
+
+  text_input = META_WAYLAND_TEXT_INPUT_FOCUS (focus)->text_input;
+
+  wl_resource_for_each (resource, &text_input->focus_resource_list)
+    {
+      zwp_text_input_v3_send_preedit_string_with_mode (resource, text, cursor, cursor, mode);
+    }
+
+  meta_wayland_text_input_focus_defer_done (focus);
+}
+
 static void
 meta_wayland_text_input_focus_class_init (MetaWaylandTextInputFocusClass *klass)
 {
@@ -227,6 +247,7 @@ meta_wayland_text_input_focus_class_init (MetaWaylandTextInputFocusClass *klass)
   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
@@ -590,12 +611,29 @@ 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)
     clutter_input_focus_set_input_panel_state (focus, CLUTTER_INPUT_PANEL_STATE_ON);
 }
 
+static void
+text_input_reset (struct wl_client   *client,
+                  struct wl_resource *resource)
+{
+  MetaWaylandTextInput *text_input = wl_resource_get_user_data (resource);
+
+  if (!text_input->surface)
+    return;
+
+  text_input->pending_state |= META_WAYLAND_PENDING_STATE_RESET;
+}
+
 static struct zwp_text_input_v3_interface meta_text_input_interface = {
   text_input_destroy,
   text_input_enable,
@@ -605,6 +643,7 @@ static struct zwp_text_input_v3_interface meta_text_input_interface = {
   text_input_set_content_type,
   text_input_set_cursor_rectangle,
   text_input_commit_state,
+  text_input_reset,
 };
 
 MetaWaylandTextInput *
diff --git a/src/wayland/protocol/gtk-text-input.xml b/src/wayland/protocol/gtk-text-input.xml
index a134a19f6..fdc03e077 100644
--- a/src/wayland/protocol/gtk-text-input.xml
+++ b/src/wayland/protocol/gtk-text-input.xml
@@ -214,6 +214,12 @@
       </description>
     </request>
 
+    <request name="reset">
+      <description summary="reset state">
+       Reset the input method state.
+      </description>
+    </request>
+
     <event name="enter">
       <description summary="enter event">
        Notification that this seat's text-input focus is on a certain surface.
@@ -251,6 +257,17 @@
       <arg name="cursor" type="uint"/>
     </event>
 
+    <event name="preedit_string_with_mode">
+      <description summary="pre-edit-with-mode">
+       Notify when a new composing text (pre-edit) should be set around the
+       current cursor position. Any previously set composing text should
+       be removed.
+      </description>
+      <arg name="text" type="string" allow-null="true"/>
+      <arg name="cursor" type="uint"/>
+      <arg name="mode" type="uint"/>
+    </event>
+
     <event name="commit_string">
       <description summary="text commit">
        Notify when text should be inserted into the editor widget. The text to
