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 @@
       </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
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, &registry_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 @@
       </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.
@@ -355,6 +361,35 @@
       <arg name="cursor_end" type="int"/>
     </event>
 
+    <event name="preedit_string_with_mode">
+      <description summary="pre-edit-with-mode">
+        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.
+      </description>
+      <arg name="text" type="string" allow-null="true"/>
+      <arg name="cursor_begin" type="int"/>
+      <arg name="cursor_end" type="int"/>
+      <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
