From: "Andre Moreira Magalhaes (andrunko)" <[email protected]>

Some clients such as gtk+3 require the zwp_text_input_v3 protocol for
input-method handling. This patch adds this protocol support to text-backend 
and also
modifies weston-keyboard to support zwp_input_method_v2, which is an update
for the v1 protocol and aligned with the updated text-input protocol.

The patch also adds support for zwp_virtual_keyboard_v1, used to emulate the
behaviour of a physical keyboard.

Note that the updated input-method v2 protocol does not support the input-panel 
interface
as it did on v1. The input panel interface is implemented by desktop-shell to 
properly
display the virtual keyboard interface.
To avoid depending on both input method v2 and v1 (for input-panel only), this 
patch adds
a new weston-input-panel internal protocol (a copy of the old interface from 
input-method v1),
which is then implemented by desktop-shell and used by weston-keyboard when 
displaying
its window.

Signed-off-by: Andre Moreira Magalhaes (andrunko) 
<[email protected]>
---
 Makefile.am                     |   28 +-
 clients/keyboard.c              |  528 ++++++++-------
 clients/meson.build             |   12 +-
 clients/window.c                |    9 +
 clients/window.h                |    3 +
 compositor/meson.build          |   12 +-
 compositor/text-backend.c       | 1104 +++++++++++++++++--------------
 desktop-shell/input-panel.c     |   12 +-
 desktop-shell/meson.build       |    4 +-
 protocol/meson.build            |    4 +
 protocol/weston-input-panel.xml |   63 ++
 tests/meson.build               |    6 +-
 tests/text-test.c               |  151 ++---
 13 files changed, 1056 insertions(+), 880 deletions(-)
 create mode 100644 protocol/weston-input-panel.xml

diff --git a/Makefile.am b/Makefile.am
index b2bb61f6..5faec4c0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -171,8 +171,12 @@ nodist_libweston_@LIBWESTON_MAJOR@_la_SOURCES =            
                \
        protocol/text-cursor-position-server-protocol.h \
        protocol/text-input-unstable-v1-protocol.c                      \
        protocol/text-input-unstable-v1-server-protocol.h               \
+       protocol/text-input-unstable-v3-protocol.c                      \
+       protocol/text-input-unstable-v3-server-protocol.h               \
        protocol/input-method-unstable-v1-protocol.c                    \
        protocol/input-method-unstable-v1-server-protocol.h             \
+       protocol/input-method-unstable-v2-protocol.c                    \
+       protocol/input-method-unstable-v2-server-protocol.h             \
        protocol/presentation-time-protocol.c           \
        protocol/presentation-time-server-protocol.h    \
        protocol/viewporter-protocol.c                  \
@@ -185,6 +189,10 @@ nodist_libweston_@LIBWESTON_MAJOR@_la_SOURCES =            
                \
        protocol/pointer-constraints-unstable-v1-server-protocol.h      \
        protocol/input-timestamps-unstable-v1-protocol.c                \
        protocol/input-timestamps-unstable-v1-server-protocol.h         \
+       protocol/virtual-keyboard-unstable-v1-protocol.c                \
+       protocol/virtual-keyboard-unstable-v1-server-protocol.h         \
+       protocol/weston-input-panel-protocol.c                          \
+       protocol/weston-input-panel-server-protocol.h                   \
        protocol/weston-touch-calibration-protocol.c                    \
        protocol/weston-touch-calibration-server-protocol.h             \
        protocol/linux-explicit-synchronization-unstable-v1-protocol.c  \
@@ -879,8 +887,12 @@ weston_keyboard_SOURCES = clients/keyboard.c
 nodist_weston_keyboard_SOURCES =                               \
        protocol/weston-desktop-shell-client-protocol.h         \
        protocol/weston-desktop-shell-protocol.c                \
-       protocol/input-method-unstable-v1-protocol.c            \
-       protocol/input-method-unstable-v1-client-protocol.h
+       protocol/input-method-unstable-v2-protocol.c            \
+       protocol/input-method-unstable-v2-client-protocol.h     \
+       protocol/virtual-keyboard-unstable-v1-protocol.c        \
+       protocol/virtual-keyboard-unstable-v1-client-protocol.h \
+       protocol/weston-input-panel-protocol.c          \
+       protocol/weston-input-panel-client-protocol.h
 weston_keyboard_LDADD = libtoytoolkit.la
 weston_keyboard_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
 
@@ -957,10 +969,18 @@ BUILT_SOURCES +=                                  \
        protocol/text-cursor-position-protocol.c        \
        protocol/text-input-unstable-v1-protocol.c                      \
        protocol/text-input-unstable-v1-client-protocol.h               \
+       protocol/text-input-unstable-v3-protocol.c                      \
+       protocol/text-input-unstable-v3-client-protocol.h               \
        protocol/input-method-unstable-v1-protocol.c                    \
        protocol/input-method-unstable-v1-client-protocol.h             \
+       protocol/input-method-unstable-v2-protocol.c                    \
+       protocol/input-method-unstable-v2-client-protocol.h             \
+       protocol/virtual-keyboard-unstable-v1-protocol.c        \
+       protocol/virtual-keyboard-unstable-v1-client-protocol.h \
        protocol/weston-desktop-shell-client-protocol.h                 \
        protocol/weston-desktop-shell-protocol.c                        \
+       protocol/weston-input-panel-client-protocol.h                   \
+       protocol/weston-input-panel-protocol.c                          \
        protocol/viewporter-client-protocol.h           \
        protocol/viewporter-protocol.c                  \
        protocol/presentation-time-protocol.c                           \
@@ -1628,9 +1648,7 @@ EXTRA_DIST +=                                             
        \
 BUILT_SOURCES +=                               \
        protocol/weston-test-protocol.c \
        protocol/weston-test-server-protocol.h  \
-       protocol/weston-test-client-protocol.h  \
-       protocol/text-input-unstable-v1-protocol.c              \
-       protocol/text-input-unstable-v1-client-protocol.h
+       protocol/weston-test-client-protocol.h
 
 EXTRA_DIST +=                                  \
        protocol/weston-desktop-shell.xml       \
diff --git a/clients/keyboard.c b/clients/keyboard.c
index c9f6f28e..2ba036fb 100644
--- a/clients/keyboard.c
+++ b/clients/keyboard.c
@@ -1,6 +1,7 @@
 /*
  * Copyright © 2012 Openismus GmbH
  * Copyright © 2012 Intel Corporation
+ * Copyright © 2019 Collabora Ltd.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -34,29 +35,39 @@
 #include <cairo.h>
 
 #include "window.h"
-#include "input-method-unstable-v1-client-protocol.h"
-#include "text-input-unstable-v1-client-protocol.h"
+#include "input-method-unstable-v2-client-protocol.h"
+#include "text-input-unstable-v3-client-protocol.h"
+#include "virtual-keyboard-unstable-v1-client-protocol.h"
+#include "weston-input-panel-client-protocol.h"
 #include "shared/xalloc.h"
 
 struct keyboard;
 
+struct text_input_state {
+       uint32_t content_hint;
+       uint32_t content_purpose;
+       uint32_t change_cause;
+       char *surrounding_text;
+       uint32_t surrounding_cursor;
+       bool active;
+};
+
 struct virtual_keyboard {
-       struct zwp_input_panel_v1 *input_panel;
-       struct zwp_input_method_v1 *input_method;
-       struct zwp_input_method_context_v1 *context;
+       struct weston_input_panel *input_panel;
+       struct zwp_input_method_manager_v2 *input_method_manager;
+       struct zwp_input_method_v2 *input_method;
+       struct zwp_virtual_keyboard_manager_v1 *virtual_keyboard_manager;
+       struct zwp_virtual_keyboard_v1 *virtual_keyboard;
        struct display *display;
        struct output *output;
-       char *preedit_string;
-       uint32_t preedit_style;
-       struct {
-               xkb_mod_mask_t shift_mask;
-       } keysym;
+       struct wl_seat *seat;
+
        uint32_t serial;
-       uint32_t content_hint;
-       uint32_t content_purpose;
+       char *preedit_string;
+       struct text_input_state pending;
+       struct text_input_state current;
+       // TODO - add support to change language (e.g. via config)
        char *preferred_language;
-       char *surrounding_text;
-       uint32_t surrounding_cursor;
        struct keyboard *keyboard;
        bool toplevel;
 };
@@ -73,7 +84,6 @@ enum key_type {
        keytype_arrow_left,
        keytype_arrow_right,
        keytype_arrow_down,
-       keytype_style
 };
 
 struct key {
@@ -94,7 +104,6 @@ struct layout {
        uint32_t rows;
 
        const char *language;
-       uint32_t text_direction;
 };
 
 static const struct key normal_keys[] = {
@@ -140,7 +149,6 @@ static const struct key normal_keys[] = {
        { keytype_arrow_left, "<", "<", "<", 1},
        { keytype_arrow_right, ">", ">", ">", 1},
        { keytype_arrow_down, "\\/", "\\/", "\\/", 1},
-       { keytype_style, "", "", "", 2}
 };
 
 static const struct key numeric_keys[] = {
@@ -162,7 +170,6 @@ static const struct key numeric_keys[] = {
        { keytype_arrow_left, "<", "<", "<", 1},
        { keytype_arrow_right, ">", ">", ">", 1},
        { keytype_arrow_down, "\\/", "\\/", "\\/", 1},
-       { keytype_style, "", "", "", 2}
 };
 
 static const struct key arabic_keys[] = {
@@ -210,7 +217,6 @@ static const struct key arabic_keys[] = {
        { keytype_space, "", "", "", 6},
        { keytype_default, ".", "ذ", "]", 1},
        { keytype_default, "ط", "ﺝ", "[", 1},
-       { keytype_style, "", "", "", 2}
 };
 
 
@@ -219,8 +225,7 @@ static const struct layout normal_layout = {
        sizeof(normal_keys) / sizeof(*normal_keys),
        12,
        4,
-       "en",
-       ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR
+       "en"
 };
 
 static const struct layout numeric_layout = {
@@ -228,8 +233,7 @@ static const struct layout numeric_layout = {
        sizeof(numeric_keys) / sizeof(*numeric_keys),
        12,
        2,
-       "en",
-       ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR
+       "en"
 };
 
 static const struct layout arabic_layout = {
@@ -237,19 +241,7 @@ static const struct layout arabic_layout = {
        sizeof(arabic_keys) / sizeof(*arabic_keys),
        13,
        4,
-       "ar",
-       ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_RTL
-};
-
-static const char *style_labels[] = {
-       "default",
-       "none",
-       "active",
-       "inactive",
-       "highlight",
-       "underline",
-       "selection",
-       "incorrect"
+       "ar"
 };
 
 static const double key_width = 60;
@@ -269,6 +261,9 @@ struct keyboard {
        enum keyboard_state state;
 };
 
+static void keyboard_set_visibility(struct virtual_keyboard *virtual_keyboard,
+                                   bool visible);
+
 static void __attribute__ ((format (printf, 1, 2)))
 dbg(const char *fmt, ...)
 {
@@ -285,9 +280,6 @@ static const char *
 label_from_key(struct keyboard *keyboard,
               const struct key *key)
 {
-       if (key->key_type == keytype_style)
-               return style_labels[keyboard->keyboard->preedit_style];
-
        switch(keyboard->state) {
        case KEYBOARD_STATE_DEFAULT:
                return key->label;
@@ -341,9 +333,13 @@ draw_key(struct keyboard *keyboard,
 static const struct layout *
 get_current_layout(struct virtual_keyboard *keyboard)
 {
-       switch (keyboard->content_purpose) {
-               case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_DIGITS:
-               case ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER:
+       if (!keyboard->current.active) {
+               return &normal_layout;
+       }
+
+       switch (keyboard->current.content_purpose) {
+               case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_DIGITS:
+               case ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NUMBER:
                        return &numeric_layout;
                default:
                        if (keyboard->preferred_language &&
@@ -430,22 +426,21 @@ virtual_keyboard_commit_preedit(struct virtual_keyboard 
*keyboard)
            strlen(keyboard->preedit_string) == 0)
                return;
 
-       zwp_input_method_context_v1_cursor_position(keyboard->context,
-                                                   0, 0);
-       zwp_input_method_context_v1_commit_string(keyboard->context,
-                                                 keyboard->serial,
-                                                 keyboard->preedit_string);
+       zwp_input_method_v2_commit_string(keyboard->input_method,
+                                         keyboard->preedit_string);
+       zwp_input_method_v2_commit(keyboard->input_method,
+                                  keyboard->serial);
 
-       if (keyboard->surrounding_text) {
-               surrounding_text = insert_text(keyboard->surrounding_text,
-                                              keyboard->surrounding_cursor,
+       if (keyboard->current.surrounding_text) {
+               surrounding_text = 
insert_text(keyboard->current.surrounding_text,
+                                              
keyboard->current.surrounding_cursor,
                                               keyboard->preedit_string);
-               free(keyboard->surrounding_text);
-               keyboard->surrounding_text = surrounding_text;
-               keyboard->surrounding_cursor += 
strlen(keyboard->preedit_string);
+               free(keyboard->current.surrounding_text);
+               keyboard->current.surrounding_text = surrounding_text;
+               keyboard->current.surrounding_cursor += 
strlen(keyboard->preedit_string);
        } else {
-               keyboard->surrounding_text = strdup(keyboard->preedit_string);
-               keyboard->surrounding_cursor = strlen(keyboard->preedit_string);
+               keyboard->current.surrounding_text = 
strdup(keyboard->preedit_string);
+               keyboard->current.surrounding_cursor = 
strlen(keyboard->preedit_string);
        }
 
        free(keyboard->preedit_string);
@@ -458,19 +453,11 @@ virtual_keyboard_send_preedit(struct virtual_keyboard 
*keyboard,
 {
        uint32_t index = strlen(keyboard->preedit_string);
 
-       if (keyboard->preedit_style)
-               zwp_input_method_context_v1_preedit_styling(keyboard->context,
-                                                           0,
-                                                           
strlen(keyboard->preedit_string),
-                                                           
keyboard->preedit_style);
        if (cursor > 0)
                index = cursor;
-       zwp_input_method_context_v1_preedit_cursor(keyboard->context,
-                                                  index);
-       zwp_input_method_context_v1_preedit_string(keyboard->context,
-                                                  keyboard->serial,
-                                                  keyboard->preedit_string,
-                                                  keyboard->preedit_string);
+       zwp_input_method_v2_set_preedit_string(keyboard->input_method,
+                                              keyboard->preedit_string, index, 
index);
+       zwp_input_method_v2_commit(keyboard->input_method, keyboard->serial);
 }
 
 static const char *
@@ -487,33 +474,33 @@ static void
 delete_before_cursor(struct virtual_keyboard *keyboard)
 {
        const char *start, *end;
+       const char *surrounding_text = keyboard->current.surrounding_text;
+       uint32_t surrounding_cursor = keyboard->current.surrounding_cursor;
 
-       if (!keyboard->surrounding_text) {
+       if (!surrounding_text) {
                dbg("delete_before_cursor: No surrounding text available\n");
                return;
        }
 
-       start = prev_utf8_char(keyboard->surrounding_text,
-                              keyboard->surrounding_text + 
keyboard->surrounding_cursor);
+       start = prev_utf8_char(surrounding_text,
+                              surrounding_text + surrounding_cursor);
        if (!start) {
                dbg("delete_before_cursor: No previous character to delete\n");
                return;
        }
 
-       end = keyboard->surrounding_text + keyboard->surrounding_cursor;
+       end = surrounding_text + surrounding_cursor;
 
-       zwp_input_method_context_v1_delete_surrounding_text(keyboard->context,
-                                                           (start - 
keyboard->surrounding_text) - keyboard->surrounding_cursor,
-                                                           end - start);
-       zwp_input_method_context_v1_commit_string(keyboard->context,
-                                                 keyboard->serial,
-                                                 "");
+       zwp_input_method_v2_delete_surrounding_text(keyboard->input_method,
+                                                   surrounding_cursor - (start 
- surrounding_text), 0);
+       zwp_input_method_v2_commit(keyboard->input_method, keyboard->serial);
 
        /* Update surrounding text */
-       keyboard->surrounding_cursor = start - keyboard->surrounding_text;
-       keyboard->surrounding_text[keyboard->surrounding_cursor] = '\0';
+       keyboard->current.surrounding_cursor = start - surrounding_text;
+       keyboard->current.surrounding_text[surrounding_cursor] = '\0';
        if (*end)
-               memmove(keyboard->surrounding_text + 
keyboard->surrounding_cursor, end, strlen(end));
+               memmove(keyboard->current.surrounding_text + 
keyboard->current.surrounding_cursor,
+                       end, strlen(end));
 }
 
 static char *
@@ -548,7 +535,6 @@ keyboard_handle_key(struct keyboard *keyboard, uint32_t 
time, const struct key *
                break;
        }
 
-       xkb_mod_mask_t mod_mask = keyboard->state == KEYBOARD_STATE_DEFAULT ? 0 
: keyboard->keyboard->keysym.shift_mask;
        uint32_t key_state = (state == WL_POINTER_BUTTON_STATE_PRESSED) ? 
WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED;
 
        switch (key->key_type) {
@@ -562,6 +548,16 @@ keyboard_handle_key(struct keyboard *keyboard, uint32_t 
time, const struct key *
                        virtual_keyboard_send_preedit(keyboard->keyboard, -1);
                        break;
                case keytype_backspace:
+                       if (!keyboard->keyboard->current.active ||
+                           ((!keyboard->keyboard->preedit_string ||
+                             strlen(keyboard->keyboard->preedit_string) == 0) 
&&
+                            (!keyboard->keyboard->current.surrounding_text ||
+                             
strlen(keyboard->keyboard->current.surrounding_text) == 0))) {
+                               
zwp_virtual_keyboard_v1_key(keyboard->keyboard->virtual_keyboard,
+                                                           time, 
KEY_BACKSPACE, key_state);
+                               break;
+                       }
+
                        if (state != WL_POINTER_BUTTON_STATE_PRESSED)
                                break;
 
@@ -573,13 +569,18 @@ keyboard_handle_key(struct keyboard *keyboard, uint32_t 
time, const struct key *
                        }
                        break;
                case keytype_enter:
-                       virtual_keyboard_commit_preedit(keyboard->keyboard);
-                       
zwp_input_method_context_v1_keysym(keyboard->keyboard->context,
-                                                          
display_get_serial(keyboard->keyboard->display),
-                                                          time,
-                                                          XKB_KEY_Return, 
key_state, mod_mask);
+                       if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
+                           keyboard->keyboard->current.active)
+                               
virtual_keyboard_commit_preedit(keyboard->keyboard);
+                       
zwp_virtual_keyboard_v1_key(keyboard->keyboard->virtual_keyboard,
+                                                   time, KEY_ENTER, key_state);
                        break;
                case keytype_space:
+                       if (!keyboard->keyboard->current.active) {
+                               
zwp_virtual_keyboard_v1_key(keyboard->keyboard->virtual_keyboard,
+                                                           time, KEY_SPACE, 
key_state);
+                               break;
+                       }
                        if (state != WL_POINTER_BUTTON_STATE_PRESSED)
                                break;
                        keyboard->keyboard->preedit_string =
@@ -617,45 +618,39 @@ keyboard_handle_key(struct keyboard *keyboard, uint32_t 
time, const struct key *
                        }
                        break;
                case keytype_tab:
-                       virtual_keyboard_commit_preedit(keyboard->keyboard);
-                       
zwp_input_method_context_v1_keysym(keyboard->keyboard->context,
-                                                          
display_get_serial(keyboard->keyboard->display),
-                                                          time,
-                                                          XKB_KEY_Tab, 
key_state, mod_mask);
+                       if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
+                           keyboard->keyboard->current.active)
+                               
virtual_keyboard_commit_preedit(keyboard->keyboard);
+                       
zwp_virtual_keyboard_v1_key(keyboard->keyboard->virtual_keyboard,
+                                                   time, KEY_TAB, key_state);
                        break;
                case keytype_arrow_up:
-                       virtual_keyboard_commit_preedit(keyboard->keyboard);
-                       
zwp_input_method_context_v1_keysym(keyboard->keyboard->context,
-                                                          
display_get_serial(keyboard->keyboard->display),
-                                                          time,
-                                                          XKB_KEY_Up, 
key_state, mod_mask);
+                       if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
+                           keyboard->keyboard->current.active)
+                               
virtual_keyboard_commit_preedit(keyboard->keyboard);
+                       
zwp_virtual_keyboard_v1_key(keyboard->keyboard->virtual_keyboard,
+                                                   time, KEY_UP, key_state);
                        break;
                case keytype_arrow_left:
-                       virtual_keyboard_commit_preedit(keyboard->keyboard);
-                       
zwp_input_method_context_v1_keysym(keyboard->keyboard->context,
-                                                          
display_get_serial(keyboard->keyboard->display),
-                                                          time,
-                                                          XKB_KEY_Left, 
key_state, mod_mask);
+                       if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
+                           keyboard->keyboard->current.active)
+                               
virtual_keyboard_commit_preedit(keyboard->keyboard);
+                       
zwp_virtual_keyboard_v1_key(keyboard->keyboard->virtual_keyboard,
+                                                   time, KEY_LEFT, key_state);
                        break;
                case keytype_arrow_right:
-                       virtual_keyboard_commit_preedit(keyboard->keyboard);
-                       
zwp_input_method_context_v1_keysym(keyboard->keyboard->context,
-                                                          
display_get_serial(keyboard->keyboard->display),
-                                                          time,
-                                                          XKB_KEY_Right, 
key_state, mod_mask);
+                       if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
+                           keyboard->keyboard->current.active)
+                               
virtual_keyboard_commit_preedit(keyboard->keyboard);
+                       
zwp_virtual_keyboard_v1_key(keyboard->keyboard->virtual_keyboard,
+                                                   time, KEY_RIGHT, key_state);
                        break;
                case keytype_arrow_down:
-                       virtual_keyboard_commit_preedit(keyboard->keyboard);
-                       
zwp_input_method_context_v1_keysym(keyboard->keyboard->context,
-                                                          
display_get_serial(keyboard->keyboard->display),
-                                                          time,
-                                                          XKB_KEY_Down, 
key_state, mod_mask);
-                       break;
-               case keytype_style:
-                       if (state != WL_POINTER_BUTTON_STATE_PRESSED)
-                               break;
-                       keyboard->keyboard->preedit_style = 
(keyboard->keyboard->preedit_style + 1) % 8; /* TODO */
-                       virtual_keyboard_send_preedit(keyboard->keyboard, -1);
+                       if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
+                           keyboard->keyboard->current.active)
+                               
virtual_keyboard_commit_preedit(keyboard->keyboard);
+                       
zwp_virtual_keyboard_v1_key(keyboard->keyboard->virtual_keyboard,
+                                                   time, KEY_DOWN, key_state);
                        break;
        }
 }
@@ -751,248 +746,191 @@ touch_up_handler(struct widget *widget, struct input 
*input,
                WL_POINTER_BUTTON_STATE_RELEASED, data);
 }
 
+static void
+input_method_activate(void *data,
+                     struct zwp_input_method_v2 *input_method)
+{
+       struct virtual_keyboard *virtual_keyboard = data;
+       struct text_input_state defaults = {0};
+
+       if (virtual_keyboard->pending.surrounding_text)
+               free(virtual_keyboard->pending.surrounding_text);
+       virtual_keyboard->pending.surrounding_text = NULL;
+       virtual_keyboard->pending = defaults;
+       if (virtual_keyboard->preedit_string)
+               free(virtual_keyboard->preedit_string);
+       virtual_keyboard->preedit_string = strdup("");
+       virtual_keyboard->pending.active = true;
+}
+
+static void
+input_method_deactivate(void *data,
+                       struct zwp_input_method_v2 *input_method)
+{
+       struct virtual_keyboard *virtual_keyboard = data;
+
+       virtual_keyboard->pending.active = false;
+}
+
 static void
 handle_surrounding_text(void *data,
-                       struct zwp_input_method_context_v1 *context,
+                       struct zwp_input_method_v2 *input_method,
                        const char *text,
                        uint32_t cursor,
                        uint32_t anchor)
 {
        struct virtual_keyboard *keyboard = data;
 
-       free(keyboard->surrounding_text);
-       keyboard->surrounding_text = strdup(text);
+       if (keyboard->pending.surrounding_text)
+               free(keyboard->pending.surrounding_text);
+       keyboard->pending.surrounding_text = strdup(text);
 
-       keyboard->surrounding_cursor = cursor;
+       keyboard->pending.surrounding_cursor = cursor;
 }
 
 static void
-handle_reset(void *data,
-            struct zwp_input_method_context_v1 *context)
+handle_text_change_cause(void *data,
+                        struct zwp_input_method_v2 *zwp_input_method_v2,
+                        uint32_t cause)
 {
        struct virtual_keyboard *keyboard = data;
 
-       dbg("Reset pre-edit buffer\n");
-
-       if (strlen(keyboard->preedit_string)) {
-               free(keyboard->preedit_string);
-               keyboard->preedit_string = strdup("");
-       }
+       keyboard->pending.change_cause = cause;
 }
 
 static void
 handle_content_type(void *data,
-                   struct zwp_input_method_context_v1 *context,
+                   struct zwp_input_method_v2 *input_method,
                    uint32_t hint,
                    uint32_t purpose)
 {
        struct virtual_keyboard *keyboard = data;
 
-       keyboard->content_hint = hint;
-       keyboard->content_purpose = purpose;
-}
-
-static void
-handle_invoke_action(void *data,
-                    struct zwp_input_method_context_v1 *context,
-                    uint32_t button,
-                    uint32_t index)
-{
-       struct virtual_keyboard *keyboard = data;
-
-       if (button != BTN_LEFT)
-               return;
-
-       virtual_keyboard_send_preedit(keyboard, index);
+       keyboard->pending.content_hint = hint;
+       keyboard->pending.content_purpose = purpose;
 }
 
 static void
 handle_commit_state(void *data,
-                   struct zwp_input_method_context_v1 *context,
-                   uint32_t serial)
+                   struct zwp_input_method_v2 *input_method)
 {
-       struct virtual_keyboard *keyboard = data;
-       const struct layout *layout;
-
-       keyboard->serial = serial;
+       struct virtual_keyboard *virtual_keyboard = data;
+       struct text_input_state defaults = {0};
 
-       layout = get_current_layout(keyboard);
+       virtual_keyboard->serial++;
 
-       if (keyboard->surrounding_text)
-               dbg("Surrounding text updated: %s\n", 
keyboard->surrounding_text);
+       if (virtual_keyboard->pending.surrounding_text)
+               free(virtual_keyboard->pending.surrounding_text);
+       virtual_keyboard->pending.surrounding_text = NULL;
+       virtual_keyboard->current = virtual_keyboard->pending;
+       virtual_keyboard->pending = defaults;
+       virtual_keyboard->pending.active = virtual_keyboard->current.active;
 
-       window_schedule_resize(keyboard->keyboard->window,
-                              layout->columns * key_width,
-                              layout->rows * key_height);
-
-       zwp_input_method_context_v1_language(context,
-                                            keyboard->serial,
-                                            layout->language);
-       zwp_input_method_context_v1_text_direction(context,
-                                                  keyboard->serial,
-                                                  layout->text_direction);
-
-       widget_schedule_redraw(keyboard->keyboard->widget);
+       keyboard_set_visibility(virtual_keyboard,
+                               virtual_keyboard->current.active);
 }
 
 static void
-handle_preferred_language(void *data,
-                         struct zwp_input_method_context_v1 *context,
-                         const char *language)
+handle_unavailable(void *data,
+                  struct zwp_input_method_v2 *zwp_input_method_v2)
 {
-       struct virtual_keyboard *keyboard = data;
-
-       if (keyboard->preferred_language)
-               free(keyboard->preferred_language);
+       struct virtual_keyboard *virtual_keyboard = data;
 
-       keyboard->preferred_language = NULL;
-
-       if (language)
-               keyboard->preferred_language = strdup(language);
+       virtual_keyboard->current.active = false;
+       zwp_input_method_v2_destroy(virtual_keyboard->input_method);
+       virtual_keyboard->input_method = NULL;
+       keyboard_set_visibility(virtual_keyboard, false);
 }
 
-static const struct zwp_input_method_context_v1_listener 
input_method_context_listener = {
+static const struct zwp_input_method_v2_listener input_method_listener = {
+       input_method_activate,
+       input_method_deactivate,
        handle_surrounding_text,
-       handle_reset,
+       handle_text_change_cause,
        handle_content_type,
-       handle_invoke_action,
        handle_commit_state,
-       handle_preferred_language
+       handle_unavailable
 };
 
 static void
-input_method_activate(void *data,
-                     struct zwp_input_method_v1 *input_method,
-                     struct zwp_input_method_context_v1 *context)
+make_input_method(struct virtual_keyboard *virtual_keyboard)
 {
-       struct virtual_keyboard *keyboard = data;
-       struct wl_array modifiers_map;
-       const struct layout *layout;
-
-       keyboard->keyboard->state = KEYBOARD_STATE_DEFAULT;
-
-       if (keyboard->context)
-               zwp_input_method_context_v1_destroy(keyboard->context);
-
-       if (keyboard->preedit_string)
-               free(keyboard->preedit_string);
-
-       keyboard->preedit_string = strdup("");
-       keyboard->content_hint = 0;
-       keyboard->content_purpose = 0;
-       free(keyboard->preferred_language);
-       keyboard->preferred_language = NULL;
-       free(keyboard->surrounding_text);
-       keyboard->surrounding_text = NULL;
-
-       keyboard->serial = 0;
-
-       keyboard->context = context;
-       zwp_input_method_context_v1_add_listener(context,
-                                                &input_method_context_listener,
-                                                keyboard);
-
-       wl_array_init(&modifiers_map);
-       keysym_modifiers_add(&modifiers_map, "Shift");
-       keysym_modifiers_add(&modifiers_map, "Control");
-       keysym_modifiers_add(&modifiers_map, "Mod1");
-       zwp_input_method_context_v1_modifiers_map(context, &modifiers_map);
-       keyboard->keysym.shift_mask = keysym_modifiers_get_mask(&modifiers_map, 
"Shift");
-       wl_array_release(&modifiers_map);
-
-       layout = get_current_layout(keyboard);
-
-       window_schedule_resize(keyboard->keyboard->window,
-                              layout->columns * key_width,
-                              layout->rows * key_height);
-
-       zwp_input_method_context_v1_language(context,
-                                            keyboard->serial,
-                                            layout->language);
-       zwp_input_method_context_v1_text_direction(context,
-                                                  keyboard->serial,
-                                                  layout->text_direction);
-
-       widget_schedule_redraw(keyboard->keyboard->widget);
+       virtual_keyboard->input_method =
+               zwp_input_method_manager_v2_get_input_method(
+                       virtual_keyboard->input_method_manager, 
virtual_keyboard->seat);
+       zwp_input_method_v2_add_listener(virtual_keyboard->input_method,
+               &input_method_listener, virtual_keyboard);
 }
 
 static void
-input_method_deactivate(void *data,
-                       struct zwp_input_method_v1 *input_method,
-                       struct zwp_input_method_context_v1 *context)
+make_virtual_keyboard(struct virtual_keyboard *virtual_keyboard)
 {
-       struct virtual_keyboard *keyboard = data;
-
-       if (!keyboard->context)
-               return;
-
-       zwp_input_method_context_v1_destroy(keyboard->context);
-       keyboard->context = NULL;
+       virtual_keyboard->virtual_keyboard =
+               zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(
+                       virtual_keyboard->virtual_keyboard_manager, 
virtual_keyboard->seat);
 }
 
-static const struct zwp_input_method_v1_listener input_method_listener = {
-       input_method_activate,
-       input_method_deactivate
-};
-
 static void
 global_handler(struct display *display, uint32_t name,
               const char *interface, uint32_t version, void *data)
 {
        struct virtual_keyboard *keyboard = data;
 
-       if (!strcmp(interface, "zwp_input_panel_v1")) {
+       if (!strcmp(interface, "weston_input_panel")) {
                keyboard->input_panel =
-                       display_bind(display, name, 
&zwp_input_panel_v1_interface, 1);
-       } else if (!strcmp(interface, "zwp_input_method_v1")) {
-               keyboard->input_method =
                        display_bind(display, name,
-                                    &zwp_input_method_v1_interface, 1);
-               zwp_input_method_v1_add_listener(keyboard->input_method,
-                                                &input_method_listener,
-                                                keyboard);
+                                    &weston_input_panel_interface, 1);
+       } else if (!strcmp(interface, "zwp_input_method_manager_v2")) {
+               keyboard->input_method_manager =
+                       display_bind(display, name,
+                                    &zwp_input_method_manager_v2_interface, 1);
+       } else if (!strcmp(interface, "zwp_virtual_keyboard_manager_v1")) {
+               keyboard->virtual_keyboard_manager =
+                       display_bind(display, name,
+                                    
&zwp_virtual_keyboard_manager_v1_interface, 1);
        }
+
 }
 
 static void
 set_toplevel(struct output *output, struct virtual_keyboard *virtual_keyboard)
 {
-       struct zwp_input_panel_surface_v1 *ips;
+       struct weston_input_panel_surface *ips;
        struct keyboard *keyboard = virtual_keyboard->keyboard;
 
-       ips = 
zwp_input_panel_v1_get_input_panel_surface(virtual_keyboard->input_panel,
+       ips = 
weston_input_panel_get_input_panel_surface(virtual_keyboard->input_panel,
                                                         
window_get_wl_surface(keyboard->window));
 
-       zwp_input_panel_surface_v1_set_toplevel(ips,
+       weston_input_panel_surface_set_toplevel(ips,
                                                output_get_wl_output(output),
-                                               
ZWP_INPUT_PANEL_SURFACE_V1_POSITION_CENTER_BOTTOM);
+                                               
WESTON_INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM);
 
        virtual_keyboard->toplevel = true;
 }
 
 static void
-display_output_handler(struct output *output, void *data) {
+display_output_handler(struct output *output, void *data)
+{
        struct virtual_keyboard *keyboard = data;
 
-       if (!keyboard->toplevel)
+       if (!keyboard->toplevel && keyboard->keyboard->window)
                set_toplevel(output, keyboard);
 }
 
 static void
-keyboard_create(struct virtual_keyboard *virtual_keyboard)
+keyboard_window_create(struct virtual_keyboard *virtual_keyboard)
 {
-       struct keyboard *keyboard;
+       struct keyboard *keyboard = virtual_keyboard->keyboard;
        const struct layout *layout;
 
+       if (keyboard->window)
+               return;
+
        layout = get_current_layout(virtual_keyboard);
 
-       keyboard = xzalloc(sizeof *keyboard);
-       keyboard->keyboard = virtual_keyboard;
        keyboard->window = window_create_custom(virtual_keyboard->display);
        keyboard->widget = window_add_widget(keyboard->window, keyboard);
 
-       virtual_keyboard->keyboard = keyboard;
-
        window_set_title(keyboard->window, "Virtual keyboard");
        window_set_user_data(keyboard->window, keyboard);
 
@@ -1005,6 +943,38 @@ keyboard_create(struct virtual_keyboard *virtual_keyboard)
        window_schedule_resize(keyboard->window,
                               layout->columns * key_width,
                               layout->rows * key_height);
+}
+
+static void
+keyboard_window_destroy(struct virtual_keyboard *virtual_keyboard)
+{
+       if (!virtual_keyboard->keyboard->window)
+               return;
+
+       widget_destroy(virtual_keyboard->keyboard->widget);
+       virtual_keyboard->keyboard->widget = NULL;
+       window_destroy(virtual_keyboard->keyboard->window);
+       virtual_keyboard->keyboard->window = NULL;
+}
+
+static void
+keyboard_set_visibility(struct virtual_keyboard *virtual_keyboard,
+                       bool visible)
+{
+       if (visible)
+               keyboard_window_create(virtual_keyboard);
+       else
+               keyboard_window_destroy(virtual_keyboard);
+}
+
+static void
+keyboard_create(struct virtual_keyboard *virtual_keyboard)
+{
+       struct keyboard *keyboard;
+
+       keyboard = xzalloc(sizeof *keyboard);
+       keyboard->keyboard = virtual_keyboard;
+       virtual_keyboard->keyboard = keyboard;
 
        display_set_output_configure_handler(virtual_keyboard->display,
                                             display_output_handler);
@@ -1026,13 +996,35 @@ main(int argc, char *argv[])
        display_set_user_data(virtual_keyboard.display, &virtual_keyboard);
        display_set_global_handler(virtual_keyboard.display, global_handler);
 
+       virtual_keyboard.seat = display_get_seat(virtual_keyboard.display);
+
+       if (virtual_keyboard.seat == NULL) {
+               fprintf(stderr, "No seat available\n");
+               return -1;
+       }
+
+       if (virtual_keyboard.input_method_manager == NULL) {
+               fprintf(stderr, "No input method manager global\n");
+               return -1;
+       }
+
+       if (virtual_keyboard.virtual_keyboard_manager == NULL) {
+               fprintf(stderr, "No virtual keyboard manager global\n");
+               return -1;
+       }
+
        if (virtual_keyboard.input_panel == NULL) {
                fprintf(stderr, "No input panel global\n");
                return -1;
        }
 
+       make_input_method(&virtual_keyboard);
+       make_virtual_keyboard(&virtual_keyboard);
+
        keyboard_create(&virtual_keyboard);
 
+       keyboard_set_visibility(&virtual_keyboard, true);
+
        display_run(virtual_keyboard.display);
 
        return 0;
diff --git a/clients/meson.build b/clients/meson.build
index 47e9e8ce..c1885c50 100644
--- a/clients/meson.build
+++ b/clients/meson.build
@@ -342,10 +342,14 @@ if get_option('shell-desktop')
        exe_keyboard = executable(
                'weston-keyboard',
                'keyboard.c',
-               text_input_unstable_v1_client_protocol_h,
-               text_input_unstable_v1_protocol_c,
-               input_method_unstable_v1_client_protocol_h,
-               input_method_unstable_v1_protocol_c,
+               input_method_unstable_v2_client_protocol_h,
+               input_method_unstable_v2_protocol_c,
+               text_input_unstable_v3_client_protocol_h,
+               text_input_unstable_v3_protocol_c,
+               virtual_keyboard_unstable_v1_client_protocol_h,
+               virtual_keyboard_unstable_v1_protocol_c,
+               weston_input_panel_client_protocol_h,
+               weston_input_panel_protocol_c,
                include_directories: include_directories('..'),
                dependencies: dep_toytoolkit,
                install_dir: get_option('libexecdir'),
diff --git a/clients/window.c b/clients/window.c
index bb9c708f..8e933f9b 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -6317,6 +6317,15 @@ display_get_compositor(struct display *display)
        return display->compositor;
 }
 
+struct wl_seat *
+display_get_seat(struct display *display)
+{
+       if (wl_list_empty(&display->input_list))
+               return NULL;
+
+       return container_of(display->input_list.next, struct input, link)->seat;
+}
+
 uint32_t
 display_get_serial(struct display *display)
 {
diff --git a/clients/window.h b/clients/window.h
index fde5c2f0..13ceddee 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -77,6 +77,9 @@ display_get_cairo_device(struct display *display);
 struct wl_compositor *
 display_get_compositor(struct display *display);
 
+struct wl_seat *
+display_get_seat(struct display *display);
+
 struct output *
 display_get_output(struct display *display);
 
diff --git a/compositor/meson.build b/compositor/meson.build
index d5d7282f..7dba3373 100644
--- a/compositor/meson.build
+++ b/compositor/meson.build
@@ -3,10 +3,14 @@ srcs_weston = [
        'main.c',
        'text-backend.c',
        'weston-screenshooter.c',
-       text_input_unstable_v1_server_protocol_h,
-       text_input_unstable_v1_protocol_c,
-       input_method_unstable_v1_server_protocol_h,
-       input_method_unstable_v1_protocol_c,
+       input_method_unstable_v2_server_protocol_h,
+       input_method_unstable_v2_protocol_c,
+       text_input_unstable_v3_server_protocol_h,
+       text_input_unstable_v3_protocol_c,
+       virtual_keyboard_unstable_v1_server_protocol_h,
+       virtual_keyboard_unstable_v1_protocol_c,
+       weston_input_panel_server_protocol_h,
+       weston_input_panel_protocol_c,
        weston_screenshooter_server_protocol_h,
        weston_screenshooter_protocol_c,
 ]
diff --git a/compositor/text-backend.c b/compositor/text-backend.c
index 03019584..3dd2f09f 100644
--- a/compositor/text-backend.c
+++ b/compositor/text-backend.c
@@ -1,6 +1,7 @@
 /*
  * Copyright © 2012 Openismus GmbH
  * Copyright © 2012 Intel Corporation
+ * Copyright © 2019 Collabora Ltd.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -33,32 +34,63 @@
 #include <unistd.h>
 #include <time.h>
 
+#include <linux/input.h>
+
 #include "compositor.h"
 #include "weston.h"
-#include "text-input-unstable-v1-server-protocol.h"
-#include "input-method-unstable-v1-server-protocol.h"
+#include "input-method-unstable-v2-server-protocol.h"
+#include "text-input-unstable-v3-server-protocol.h"
+#include "virtual-keyboard-unstable-v1-server-protocol.h"
 #include "shared/helpers.h"
 #include "shared/timespec-util.h"
 
-struct text_input_manager;
 struct input_method;
-struct input_method_context;
+struct input_method_manager;
+struct virtual_keyboard;
+struct virtual_keyboard_manager;
 struct text_backend;
+struct text_input_manager;
+
+struct text_input_state {
+       struct {
+               char *text; // NULL is allowed and equivalent to empty string
+               uint32_t cursor;
+               uint32_t anchor;
+       } surrounding;
+
+       uint32_t text_change_cause;
+
+       struct {
+               uint32_t hint;
+               uint32_t purpose;
+       } content_type;
+
+       pixman_box32_t cursor_rectangle;
+};
 
 struct text_input {
        struct wl_resource *resource;
 
        struct weston_compositor *ec;
 
-       struct wl_list input_methods;
+       struct weston_seat *seat;
 
-       struct weston_surface *surface;
+       struct input_method *input_method;
 
-       pixman_box32_t cursor_rectangle;
+       struct weston_surface *surface;
 
        bool input_panel_visible;
 
        struct text_input_manager *manager;
+
+       uint32_t current_serial;
+
+       bool pending_enabled;
+       bool current_enabled;
+       struct text_input_state pending;
+       struct text_input_state current;
+
+       struct wl_list link;
 };
 
 struct text_input_manager {
@@ -68,34 +100,77 @@ struct text_input_manager {
        struct text_input *current_text_input;
 
        struct weston_compositor *ec;
+
+       struct wl_list text_inputs;
+};
+
+struct input_method_state {
+       struct {
+               char *text;
+               int32_t cursor_begin;
+               int32_t cursor_end;
+       } preedit;
+
+       char *commit_text;
+
+       struct {
+               uint32_t before_length;
+               uint32_t after_length;
+       } delete;
 };
 
 struct input_method {
-       struct wl_resource *input_method_binding;
-       struct wl_global *input_method_global;
-       struct wl_listener destroy_listener;
+       struct wl_resource *resource;
+
+       struct weston_compositor *ec;
 
        struct weston_seat *seat;
        struct text_input *input;
 
-       struct wl_list link;
-
        struct wl_listener keyboard_focus_listener;
 
        bool focus_listener_initialized;
 
-       struct input_method_context *context;
+       struct wl_resource *keyboard;
 
-       struct text_backend *text_backend;
+       struct input_method_manager *manager;
+
+       struct weston_surface *pending_focused_surface;
+
+       struct input_method_state pending;
+       struct input_method_state current;
+
+       struct wl_list link;
+};
+
+struct input_method_manager {
+       struct wl_global *input_method_manager_global;
+       struct wl_listener destroy_listener;
+
+       struct weston_compositor *ec;
+
+       struct wl_list input_methods;
 };
 
-struct input_method_context {
+struct virtual_keyboard {
        struct wl_resource *resource;
 
-       struct text_input *input;
-       struct input_method *input_method;
+       struct weston_compositor *ec;
 
-       struct wl_resource *keyboard;
+       struct weston_seat *seat;
+
+       struct virtual_keyboard_manager *manager;
+
+       struct wl_list link;
+};
+
+struct virtual_keyboard_manager {
+       struct wl_global *virtual_keyboard_manager_global;
+       struct wl_listener destroy_listener;
+
+       struct weston_compositor *ec;
+
+       struct wl_list virtual_keyboards;
 };
 
 struct text_backend {
@@ -110,37 +185,36 @@ struct text_backend {
        } input_method;
 
        struct wl_listener client_listener;
-       struct wl_listener seat_created_listener;
 };
 
 static void
-input_method_context_create(struct text_input *input,
-                           struct input_method *input_method);
-static void
-input_method_context_end_keyboard_grab(struct input_method_context *context);
+input_method_end_keyboard_grab(struct input_method *input_method);
 
 static void
 input_method_init_seat(struct weston_seat *seat);
 
+static void
+text_input_show_input_panel(struct text_input *text_input);
+
 static void
 deactivate_input_method(struct input_method *input_method)
 {
-       struct text_input *text_input = input_method->input;
-       struct weston_compositor *ec = text_input->ec;
-
-       if (input_method->context && input_method->input_method_binding) {
-               input_method_context_end_keyboard_grab(input_method->context);
-               zwp_input_method_v1_send_deactivate(
-                       input_method->input_method_binding,
-                       input_method->context->resource);
-               input_method->context->input = NULL;
+       if (input_method->resource) {
+               input_method_end_keyboard_grab(input_method);
+               zwp_input_method_v2_send_deactivate(input_method->resource);
        }
+       if (input_method->input) {
+               input_method->input->input_method = NULL;
+               input_method->input = NULL;
+       }
+}
 
-       wl_list_remove(&input_method->link);
-       input_method->input = NULL;
-       input_method->context = NULL;
+static void
+deactivate_text_input(struct text_input *text_input)
+{
+       struct weston_compositor *ec = text_input->ec;
 
-       if (wl_list_empty(&text_input->input_methods) &&
+       if (text_input->input_method &&
            text_input->input_panel_visible &&
            text_input->manager->current_text_input == text_input) {
                wl_signal_emit(&ec->hide_input_panel_signal, ec);
@@ -150,18 +224,30 @@ deactivate_input_method(struct input_method *input_method)
        if (text_input->manager->current_text_input == text_input)
                text_input->manager->current_text_input = NULL;
 
-       zwp_text_input_v1_send_leave(text_input->resource);
+       if (text_input->input_method)
+               text_input->input_method->input = NULL;
+       text_input->input_method = NULL;
+
+       if (text_input->surface) {
+               zwp_text_input_v3_send_leave(text_input->resource,
+                                            text_input->surface->resource);
+       }
+       text_input->surface = NULL;
 }
 
 static void
 destroy_text_input(struct wl_resource *resource)
 {
        struct text_input *text_input = wl_resource_get_user_data(resource);
-       struct input_method *input_method, *next;
 
-       wl_list_for_each_safe(input_method, next,
-                             &text_input->input_methods, link)
-               deactivate_input_method(input_method);
+       deactivate_text_input(text_input);
+
+       if (text_input->current.surrounding.text)
+               free(text_input->current.surrounding.text);
+       if (text_input->pending.surrounding.text)
+               free(text_input->pending.surrounding.text);
+
+       wl_list_remove(&text_input->link);
 
        free(text_input);
 }
@@ -170,95 +256,69 @@ static void
 text_input_set_surrounding_text(struct wl_client *client,
                                struct wl_resource *resource,
                                const char *text,
-                               uint32_t cursor,
-                               uint32_t anchor)
+                               int32_t cursor,
+                               int32_t anchor)
 {
        struct text_input *text_input = wl_resource_get_user_data(resource);
-       struct input_method *input_method, *next;
-
-       wl_list_for_each_safe(input_method, next,
-                             &text_input->input_methods, link) {
-               if (!input_method->context)
-                       continue;
-               zwp_input_method_context_v1_send_surrounding_text(
-                       input_method->context->resource, text, cursor, anchor);
-       }
+
+       if (text_input->pending.surrounding.text)
+               free(text_input->pending.surrounding.text);
+       text_input->pending.surrounding.text = strdup(text);
+       text_input->pending.surrounding.cursor = cursor;
+       text_input->pending.surrounding.anchor = anchor;
 }
 
 static void
-text_input_activate(struct wl_client *client,
-                   struct wl_resource *resource,
-                   struct wl_resource *seat,
-                   struct wl_resource *surface)
+activate_text_input(struct text_input *text_input)
 {
-       struct text_input *text_input = wl_resource_get_user_data(resource);
-       struct weston_seat *weston_seat = wl_resource_get_user_data(seat);
+       struct weston_seat *weston_seat = text_input->seat;
        struct input_method *input_method;
-       struct weston_compositor *ec = text_input->ec;
-       struct text_input *current;
 
        if (!weston_seat)
                return;
 
        input_method = weston_seat->input_method;
-       if (input_method->input == text_input)
+       if (!input_method || input_method->input == text_input)
                return;
 
-       if (input_method->input)
-               deactivate_input_method(input_method);
+       if (!input_method->pending_focused_surface)
+               return;
 
        input_method->input = text_input;
-       wl_list_insert(&text_input->input_methods, &input_method->link);
-       input_method_init_seat(weston_seat);
-
-       text_input->surface = wl_resource_get_user_data(surface);
-
-       input_method_context_create(text_input, input_method);
+       text_input->input_method = input_method;
 
-       current = text_input->manager->current_text_input;
+       text_input->surface = input_method->pending_focused_surface;
 
-       if (current && current != text_input) {
-               current->input_panel_visible = false;
-               wl_signal_emit(&ec->hide_input_panel_signal, ec);
-       }
+       zwp_input_method_v2_send_activate(input_method->resource);
 
-       if (text_input->input_panel_visible) {
-               wl_signal_emit(&ec->show_input_panel_signal,
-                              text_input->surface);
-               wl_signal_emit(&ec->update_input_panel_signal,
-                              &text_input->cursor_rectangle);
-       }
        text_input->manager->current_text_input = text_input;
 
-       zwp_text_input_v1_send_enter(text_input->resource,
+       text_input_show_input_panel(text_input);
+
+       zwp_text_input_v3_send_enter(text_input->resource,
                                     text_input->surface->resource);
 }
 
 static void
-text_input_deactivate(struct wl_client *client,
-                     struct wl_resource *resource,
-                     struct wl_resource *seat)
+text_input_enable(struct wl_client *client,
+                 struct wl_resource *resource)
 {
-       struct weston_seat *weston_seat = wl_resource_get_user_data(seat);
+       struct text_input *text_input = wl_resource_get_user_data(resource);
+       struct text_input_state defaults = {0};
 
-       if (weston_seat && weston_seat->input_method->input)
-               deactivate_input_method(weston_seat->input_method);
+       if (text_input->pending.surrounding.text)
+               free(text_input->pending.surrounding.text);
+       text_input->pending = defaults;
+       text_input->pending_enabled = true;
 }
 
 static void
-text_input_reset(struct wl_client *client,
-                struct wl_resource *resource)
+text_input_disable(struct wl_client *client,
+                  struct wl_resource *resource)
 {
        struct text_input *text_input = wl_resource_get_user_data(resource);
-       struct input_method *input_method, *next;
-
-       wl_list_for_each_safe(input_method, next,
-                             &text_input->input_methods, link) {
-               if (!input_method->context)
-                       continue;
-               zwp_input_method_context_v1_send_reset(
-                       input_method->context->resource);
-       }
+
+       text_input->pending_enabled = false;
 }
 
 static void
@@ -270,15 +330,11 @@ text_input_set_cursor_rectangle(struct wl_client *client,
                                int32_t height)
 {
        struct text_input *text_input = wl_resource_get_user_data(resource);
-       struct weston_compositor *ec = text_input->ec;
 
-       text_input->cursor_rectangle.x1 = x;
-       text_input->cursor_rectangle.y1 = y;
-       text_input->cursor_rectangle.x2 = x + width;
-       text_input->cursor_rectangle.y2 = y + height;
-
-       wl_signal_emit(&ec->update_input_panel_signal,
-                      &text_input->cursor_rectangle);
+       text_input->pending.cursor_rectangle.x1 = x;
+       text_input->pending.cursor_rectangle.y1 = y;
+       text_input->pending.cursor_rectangle.x2 = x + width;
+       text_input->pending.cursor_rectangle.y2 = y + height;
 }
 
 static void
@@ -288,141 +344,139 @@ text_input_set_content_type(struct wl_client *client,
                            uint32_t purpose)
 {
        struct text_input *text_input = wl_resource_get_user_data(resource);
-       struct input_method *input_method, *next;
-
-       wl_list_for_each_safe(input_method, next,
-                             &text_input->input_methods, link) {
-               if (!input_method->context)
-                       continue;
-               zwp_input_method_context_v1_send_content_type(
-                       input_method->context->resource, hint, purpose);
-       }
+
+       text_input->pending.content_type.hint = hint;
+       text_input->pending.content_type.purpose = purpose;
 }
 
 static void
-text_input_invoke_action(struct wl_client *client,
-                        struct wl_resource *resource,
-                        uint32_t button,
-                        uint32_t index)
+text_input_commit(struct wl_client *client,
+                 struct wl_resource *resource)
 {
        struct text_input *text_input = wl_resource_get_user_data(resource);
-       struct input_method *input_method, *next;
-
-       wl_list_for_each_safe(input_method, next,
-                             &text_input->input_methods, link) {
-               if (!input_method->context)
-                       continue;
-               zwp_input_method_context_v1_send_invoke_action(
-                       input_method->context->resource, button, index);
+       struct weston_compositor *ec = text_input->ec;
+       struct input_method *input_method;
+       bool old_enabled;
+
+       text_input->current_serial++;
+       text_input->current = text_input->pending;
+       if (text_input->pending.surrounding.text)
+               text_input->current.surrounding.text =
+                       strdup(text_input->pending.surrounding.text);
+
+       old_enabled = text_input->current_enabled;
+       text_input->current_enabled = text_input->pending_enabled;
+
+       input_method = text_input->input_method;
+       if (!old_enabled && text_input->current_enabled)
+               activate_text_input(text_input);
+       else if (old_enabled && !text_input->current_enabled) {
+               deactivate_text_input(text_input);
        }
-}
 
-static void
-text_input_commit_state(struct wl_client *client,
-                       struct wl_resource *resource,
-                       uint32_t serial)
-{
-       struct text_input *text_input = wl_resource_get_user_data(resource);
-       struct input_method *input_method, *next;
-
-       wl_list_for_each_safe(input_method, next,
-                             &text_input->input_methods, link) {
-               if (!input_method->context)
-                       continue;
-               zwp_input_method_context_v1_send_commit_state(
-                       input_method->context->resource, serial);
+       if (input_method) {
+               if (text_input->current.surrounding.text) {
+                       zwp_input_method_v2_send_surrounding_text(
+                                               input_method->resource,
+                                               
text_input->current.surrounding.text,
+                                               
text_input->current.surrounding.cursor,
+                                               
text_input->current.surrounding.anchor);
+               }
+               zwp_input_method_v2_send_text_change_cause(
+                                               input_method->resource,
+                                               
text_input->current.text_change_cause);
+               zwp_input_method_v2_send_content_type(
+                                               input_method->resource,
+                                               
text_input->current.content_type.hint,
+                                               
text_input->current.content_type.purpose);
+               wl_signal_emit(&ec->update_input_panel_signal,
+                              &text_input->current.cursor_rectangle);
+               zwp_input_method_v2_send_done(input_method->resource);
        }
 }
 
 static void
-text_input_show_input_panel(struct wl_client *client,
-                           struct wl_resource *resource)
+text_input_show_input_panel(struct text_input *text_input)
 {
-       struct text_input *text_input = wl_resource_get_user_data(resource);
        struct weston_compositor *ec = text_input->ec;
 
        text_input->input_panel_visible = true;
 
-       if (!wl_list_empty(&text_input->input_methods) &&
+       if (text_input->input_method &&
            text_input == text_input->manager->current_text_input) {
                wl_signal_emit(&ec->show_input_panel_signal,
                               text_input->surface);
                wl_signal_emit(&ec->update_input_panel_signal,
-                              &text_input->cursor_rectangle);
+                              &text_input->current.cursor_rectangle);
        }
 }
 
 static void
-text_input_hide_input_panel(struct wl_client *client,
-                           struct wl_resource *resource)
+text_input_destroy(struct wl_client *client,
+                  struct wl_resource *resource)
 {
-       struct text_input *text_input = wl_resource_get_user_data(resource);
-       struct weston_compositor *ec = text_input->ec;
-
-       text_input->input_panel_visible = false;
-
-       if (!wl_list_empty(&text_input->input_methods) &&
-           text_input == text_input->manager->current_text_input)
-               wl_signal_emit(&ec->hide_input_panel_signal, ec);
+       wl_resource_destroy(resource);
 }
 
 static void
-text_input_set_preferred_language(struct wl_client *client,
-                                 struct wl_resource *resource,
-                                 const char *language)
+text_input_set_text_change_cause(struct wl_client *client,
+                                struct wl_resource *resource,
+                                uint32_t cause)
 {
        struct text_input *text_input = wl_resource_get_user_data(resource);
-       struct input_method *input_method, *next;
-
-       wl_list_for_each_safe(input_method, next,
-                             &text_input->input_methods, link) {
-               if (!input_method->context)
-                       continue;
-               zwp_input_method_context_v1_send_preferred_language(
-                       input_method->context->resource, language);
-       }
+
+       text_input->pending.text_change_cause = cause;
 }
 
-static const struct zwp_text_input_v1_interface text_input_implementation = {
-       text_input_activate,
-       text_input_deactivate,
-       text_input_show_input_panel,
-       text_input_hide_input_panel,
-       text_input_reset,
+static const struct zwp_text_input_v3_interface text_input_implementation = {
+       text_input_destroy,
+       text_input_enable,
+       text_input_disable,
        text_input_set_surrounding_text,
+       text_input_set_text_change_cause,
        text_input_set_content_type,
        text_input_set_cursor_rectangle,
-       text_input_set_preferred_language,
-       text_input_commit_state,
-       text_input_invoke_action
+       text_input_commit,
 };
 
-static void text_input_manager_create_text_input(struct wl_client *client,
-                                                struct wl_resource *resource,
-                                                uint32_t id)
+static void
+text_input_manager_destroy(struct wl_client *client,
+                          struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void text_input_manager_get_text_input(struct wl_client *client,
+                                             struct wl_resource *resource,
+                                             uint32_t id,
+                                             struct wl_resource *seat)
 {
        struct text_input_manager *text_input_manager =
                wl_resource_get_user_data(resource);
        struct text_input *text_input;
+       struct weston_seat *weston_seat = wl_resource_get_user_data(seat);
 
        text_input = zalloc(sizeof *text_input);
        if (text_input == NULL)
                return;
 
        text_input->resource =
-               wl_resource_create(client, &zwp_text_input_v1_interface, 1, id);
+               wl_resource_create(client, &zwp_text_input_v3_interface, 1, id);
        wl_resource_set_implementation(text_input->resource,
                                       &text_input_implementation,
                                       text_input, destroy_text_input);
 
        text_input->ec = text_input_manager->ec;
        text_input->manager = text_input_manager;
+       text_input->seat = weston_seat;
+       text_input->current_serial = 0;
 
-       wl_list_init(&text_input->input_methods);
+       wl_list_insert(&text_input_manager->text_inputs, &text_input->link);
 };
 
-static const struct zwp_text_input_manager_v1_interface manager_implementation 
= {
-       text_input_manager_create_text_input
+static const struct zwp_text_input_manager_v3_interface 
text_input_manager_implementation = {
+       text_input_manager_destroy,
+       text_input_manager_get_text_input
 };
 
 static void
@@ -437,10 +491,10 @@ bind_text_input_manager(struct wl_client *client,
        /* No checking for duplicate binding necessary.  */
        resource =
                wl_resource_create(client,
-                                  &zwp_text_input_manager_v1_interface, 1, id);
+                                  &zwp_text_input_manager_v3_interface, 1, id);
        if (resource)
                wl_resource_set_implementation(resource,
-                                              &manager_implementation,
+                                              
&text_input_manager_implementation,
                                               text_input_manager, NULL);
 }
 
@@ -451,6 +505,12 @@ text_input_manager_notifier_destroy(struct wl_listener 
*listener, void *data)
                container_of(listener,
                             struct text_input_manager,
                             destroy_listener);
+       struct text_input *text_input, *text_input_tmp;
+
+       wl_list_for_each_safe(text_input, text_input_tmp,
+                             &text_input_manager->text_inputs, link) {
+               wl_resource_destroy(text_input->resource);
+       }
 
        wl_list_remove(&text_input_manager->destroy_listener.link);
        wl_global_destroy(text_input_manager->text_input_manager_global);
@@ -471,151 +531,113 @@ text_input_manager_create(struct weston_compositor *ec)
 
        text_input_manager->text_input_manager_global =
                wl_global_create(ec->wl_display,
-                                &zwp_text_input_manager_v1_interface, 1,
+                                &zwp_text_input_manager_v3_interface, 1,
                                 text_input_manager, bind_text_input_manager);
 
        text_input_manager->destroy_listener.notify =
                text_input_manager_notifier_destroy;
        wl_signal_add(&ec->destroy_signal,
                      &text_input_manager->destroy_listener);
-}
-
-static void
-input_method_context_destroy(struct wl_client *client,
-                            struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static void
-input_method_context_commit_string(struct wl_client *client,
-                                  struct wl_resource *resource,
-                                  uint32_t serial,
-                                  const char *text)
-{
-       struct input_method_context *context =
-               wl_resource_get_user_data(resource);
 
-       if (context->input)
-               zwp_text_input_v1_send_commit_string(context->input->resource,
-                                                    serial, text);
+       wl_list_init(&text_input_manager->text_inputs);
 }
 
 static void
-input_method_context_preedit_string(struct wl_client *client,
-                                   struct wl_resource *resource,
-                                   uint32_t serial,
-                                   const char *text,
-                                   const char *commit)
+input_method_destroy(struct wl_client *client,
+                    struct wl_resource *resource)
 {
-       struct input_method_context *context =
-               wl_resource_get_user_data(resource);
-
-       if (context->input)
-               zwp_text_input_v1_send_preedit_string(context->input->resource,
-                                                     serial, text, commit);
-}
-
-static void
-input_method_context_preedit_styling(struct wl_client *client,
-                                    struct wl_resource *resource,
-                                    uint32_t index,
-                                    uint32_t length,
-                                    uint32_t style)
-{
-       struct input_method_context *context =
-               wl_resource_get_user_data(resource);
-
-       if (context->input)
-               zwp_text_input_v1_send_preedit_styling(context->input->resource,
-                                                      index, length, style);
+       wl_resource_destroy(resource);
 }
 
 static void
-input_method_context_preedit_cursor(struct wl_client *client,
-                                   struct wl_resource *resource,
-                                   int32_t cursor)
+input_method_commit_string(struct wl_client *client,
+                          struct wl_resource *resource,
+                          const char *text)
 {
-       struct input_method_context *context =
-               wl_resource_get_user_data(resource);
+       struct input_method *input_method = wl_resource_get_user_data(resource);
 
-       if (context->input)
-               zwp_text_input_v1_send_preedit_cursor(context->input->resource,
-                                                     cursor);
+       if (input_method->pending.commit_text)
+               free(input_method->pending.commit_text);
+       input_method->pending.commit_text = strdup(text);
 }
 
 static void
-input_method_context_delete_surrounding_text(struct wl_client *client,
-                                            struct wl_resource *resource,
-                                            int32_t index,
-                                            uint32_t length)
+input_method_set_preedit_string(struct wl_client *client,
+                               struct wl_resource *resource,
+                               const char *text,
+                               int32_t cursor_begin,
+                               int32_t cursor_end)
 {
-       struct input_method_context *context =
-               wl_resource_get_user_data(resource);
+       struct input_method *input_method = wl_resource_get_user_data(resource);
 
-       if (context->input)
-               zwp_text_input_v1_send_delete_surrounding_text(
-                       context->input->resource, index, length);
+       if (input_method->pending.preedit.text)
+               free(input_method->pending.preedit.text);
+       input_method->pending.preedit.text = strdup(text);
+       input_method->pending.preedit.cursor_begin = cursor_begin;
+       input_method->pending.preedit.cursor_end = cursor_end;
 }
 
 static void
-input_method_context_cursor_position(struct wl_client *client,
+input_method_delete_surrounding_text(struct wl_client *client,
                                     struct wl_resource *resource,
-                                    int32_t index,
-                                    int32_t anchor)
+                                    uint32_t before_length,
+                                    uint32_t after_length)
 {
-       struct input_method_context *context =
-               wl_resource_get_user_data(resource);
+       struct input_method *input_method = wl_resource_get_user_data(resource);
 
-       if (context->input)
-               zwp_text_input_v1_send_cursor_position(context->input->resource,
-                                                      index, anchor);
+       input_method->pending.delete.before_length = before_length;
+       input_method->pending.delete.after_length = after_length;
 }
 
 static void
-input_method_context_modifiers_map(struct wl_client *client,
-                                  struct wl_resource *resource,
-                                  struct wl_array *map)
+input_method_commit(struct wl_client *client,
+                   struct wl_resource *resource,
+                   uint32_t serial)
 {
-       struct input_method_context *context =
-               wl_resource_get_user_data(resource);
+       struct input_method *input_method = wl_resource_get_user_data(resource);
 
-       if (context->input)
-               zwp_text_input_v1_send_modifiers_map(context->input->resource,
-                                                    map);
-}
+       if (!input_method->input) {
+               return;
+       }
 
-static void
-input_method_context_keysym(struct wl_client *client,
-                           struct wl_resource *resource,
-                           uint32_t serial,
-                           uint32_t time,
-                           uint32_t sym,
-                           uint32_t state,
-                           uint32_t modifiers)
-{
-       struct input_method_context *context =
-               wl_resource_get_user_data(resource);
+       input_method->current = input_method->pending;
+       struct input_method_state default_state = {0};
+       input_method->pending = default_state;
 
-       if (context->input)
-               zwp_text_input_v1_send_keysym(context->input->resource,
-                                             serial, time,
-                                             sym, state, modifiers);
+       if (input_method->current.preedit.text) {
+               
zwp_text_input_v3_send_preedit_string(input_method->input->resource,
+                                               
input_method->current.preedit.text,
+                                               
input_method->current.preedit.cursor_begin,
+                                               
input_method->current.preedit.cursor_end);
+       }
+       if (input_method->current.commit_text) {
+               
zwp_text_input_v3_send_commit_string(input_method->input->resource,
+                                               
input_method->current.commit_text);
+       }
+       if (input_method->current.delete.before_length ||
+               input_method->current.delete.after_length) {
+               
zwp_text_input_v3_send_delete_surrounding_text(input_method->input->resource,
+                                               
input_method->current.delete.before_length,
+                                               
input_method->current.delete.after_length);
+       }
+       zwp_text_input_v3_send_done(input_method->input->resource,
+                                               
input_method->input->current_serial);
 }
 
 static void
 unbind_keyboard(struct wl_resource *resource)
 {
-       struct input_method_context *context =
+       struct input_method *input_method =
                wl_resource_get_user_data(resource);
 
-       input_method_context_end_keyboard_grab(context);
-       context->keyboard = NULL;
+       input_method_end_keyboard_grab(input_method);
+       input_method->keyboard = NULL;
 }
 
 static void
 input_method_context_grab_key(struct weston_keyboard_grab *grab,
-                             const struct timespec *time, uint32_t key,
+                             const struct timespec *time,
+                             uint32_t key,
                              uint32_t state_w)
 {
        struct weston_keyboard *keyboard = grab->keyboard;
@@ -665,20 +687,20 @@ static const struct weston_keyboard_grab_interface 
input_method_context_grab = {
 };
 
 static void
-input_method_context_grab_keyboard(struct wl_client *client,
-                                  struct wl_resource *resource,
-                                  uint32_t id)
+input_method_grab_keyboard(struct wl_client *client,
+                          struct wl_resource *resource,
+                          uint32_t id)
 {
-       struct input_method_context *context =
+       struct input_method *input_method =
                wl_resource_get_user_data(resource);
        struct wl_resource *cr;
-       struct weston_seat *seat = context->input_method->seat;
+       struct weston_seat *seat = input_method->seat;
        struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
 
        cr = wl_resource_create(client, &wl_keyboard_interface, 1, id);
-       wl_resource_set_implementation(cr, NULL, context, unbind_keyboard);
+       wl_resource_set_implementation(cr, NULL, input_method, unbind_keyboard);
 
-       context->keyboard = cr;
+       input_method->keyboard = cr;
 
        weston_keyboard_send_keymap(keyboard, cr);
 
@@ -690,16 +712,25 @@ input_method_context_grab_keyboard(struct wl_client 
*client,
 }
 
 static void
-input_method_context_key(struct wl_client *client,
-                        struct wl_resource *resource,
-                        uint32_t serial,
-                        uint32_t time,
-                        uint32_t key,
-                        uint32_t state_w)
+virtual_keyboard_keymap(struct wl_client *client,
+                       struct wl_resource *resource,
+                       uint32_t format,
+                       int32_t fd,
+                       uint32_t size)
 {
-       struct input_method_context *context =
+       weston_log("stub: zwp_virtual_keyboard_v1_interface:keymap\n");
+}
+
+static void
+virtual_keyboard_key(struct wl_client *client,
+                    struct wl_resource *resource,
+                    uint32_t time,
+                    uint32_t key,
+                    uint32_t state_w)
+{
+       struct virtual_keyboard *virtual_keyboard =
                wl_resource_get_user_data(resource);
-       struct weston_seat *seat = context->input_method->seat;
+       struct weston_seat *seat = virtual_keyboard->seat;
        struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
        struct weston_keyboard_grab *default_grab = &keyboard->default_grab;
        struct timespec ts;
@@ -710,20 +741,20 @@ input_method_context_key(struct wl_client *client,
 }
 
 static void
-input_method_context_modifiers(struct wl_client *client,
-                              struct wl_resource *resource,
-                              uint32_t serial,
-                              uint32_t mods_depressed,
-                              uint32_t mods_latched,
-                              uint32_t mods_locked,
-                              uint32_t group)
+virtual_keyboard_modifiers(struct wl_client *client,
+                          struct wl_resource *resource,
+                          uint32_t mods_depressed,
+                          uint32_t mods_latched,
+                          uint32_t mods_locked,
+                          uint32_t group)
 {
-       struct input_method_context *context =
+       struct virtual_keyboard *virtual_keyboard =
                wl_resource_get_user_data(resource);
 
-       struct weston_seat *seat = context->input_method->seat;
+       struct weston_seat *seat = virtual_keyboard->seat;
        struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
        struct weston_keyboard_grab *default_grab = &keyboard->default_grab;
+       int serial = wl_display_next_serial(virtual_keyboard->ec->wl_display);
 
        default_grab->interface->modifiers(default_grab,
                                           serial, mods_depressed,
@@ -732,104 +763,12 @@ input_method_context_modifiers(struct wl_client *client,
 }
 
 static void
-input_method_context_language(struct wl_client *client,
-                             struct wl_resource *resource,
-                             uint32_t serial,
-                             const char *language)
-{
-       struct input_method_context *context =
-               wl_resource_get_user_data(resource);
-
-       if (context->input)
-               zwp_text_input_v1_send_language(context->input->resource,
-                                               serial, language);
-}
-
-static void
-input_method_context_text_direction(struct wl_client *client,
-                                   struct wl_resource *resource,
-                                   uint32_t serial,
-                                   uint32_t direction)
-{
-       struct input_method_context *context =
-               wl_resource_get_user_data(resource);
-
-       if (context->input)
-               zwp_text_input_v1_send_text_direction(context->input->resource,
-                                                     serial, direction);
-}
-
-
-static const struct zwp_input_method_context_v1_interface 
context_implementation = {
-       input_method_context_destroy,
-       input_method_context_commit_string,
-       input_method_context_preedit_string,
-       input_method_context_preedit_styling,
-       input_method_context_preedit_cursor,
-       input_method_context_delete_surrounding_text,
-       input_method_context_cursor_position,
-       input_method_context_modifiers_map,
-       input_method_context_keysym,
-       input_method_context_grab_keyboard,
-       input_method_context_key,
-       input_method_context_modifiers,
-       input_method_context_language,
-       input_method_context_text_direction
-};
-
-static void
-destroy_input_method_context(struct wl_resource *resource)
-{
-       struct input_method_context *context =
-               wl_resource_get_user_data(resource);
-
-       if (context->keyboard)
-               wl_resource_destroy(context->keyboard);
-
-       if (context->input_method && context->input_method->context == context)
-               context->input_method->context = NULL;
-
-       free(context);
-}
-
-static void
-input_method_context_create(struct text_input *input,
-                           struct input_method *input_method)
-{
-       struct input_method_context *context;
-       struct wl_resource *binding;
-
-       if (!input_method->input_method_binding)
-               return;
-
-       context = zalloc(sizeof *context);
-       if (context == NULL)
-               return;
-
-       binding = input_method->input_method_binding;
-       context->resource =
-               wl_resource_create(wl_resource_get_client(binding),
-                                  &zwp_input_method_context_v1_interface,
-                                  1, 0);
-       wl_resource_set_implementation(context->resource,
-                                      &context_implementation,
-                                      context, destroy_input_method_context);
-
-       context->input = input;
-       context->input_method = input_method;
-       input_method->context = context;
-
-
-       zwp_input_method_v1_send_activate(binding, context->resource);
-}
-
-static void
-input_method_context_end_keyboard_grab(struct input_method_context *context)
+input_method_end_keyboard_grab(struct input_method *input_method)
 {
        struct weston_keyboard_grab *grab;
        struct weston_keyboard *keyboard;
 
-       keyboard = weston_seat_get_keyboard(context->input_method->seat);
+       keyboard = weston_seat_get_keyboard(input_method->seat);
        if (!keyboard)
                return;
 
@@ -844,64 +783,6 @@ input_method_context_end_keyboard_grab(struct 
input_method_context *context)
        keyboard->input_method_resource = NULL;
 }
 
-static void
-unbind_input_method(struct wl_resource *resource)
-{
-       struct input_method *input_method = wl_resource_get_user_data(resource);
-
-       input_method->input_method_binding = NULL;
-       input_method->context = NULL;
-}
-
-static void
-bind_input_method(struct wl_client *client,
-                 void *data,
-                 uint32_t version,
-                 uint32_t id)
-{
-       struct input_method *input_method = data;
-       struct text_backend *text_backend = input_method->text_backend;
-       struct wl_resource *resource;
-
-       resource =
-               wl_resource_create(client,
-                                  &zwp_input_method_v1_interface, 1, id);
-
-       if (input_method->input_method_binding != NULL) {
-               wl_resource_post_error(resource,
-                                      WL_DISPLAY_ERROR_INVALID_OBJECT,
-                                      "interface object already bound");
-               return;
-       }
-
-       if (text_backend->input_method.client != client) {
-               wl_resource_post_error(resource,
-                                      WL_DISPLAY_ERROR_INVALID_OBJECT,
-                                      "permission to bind "
-                                      "input_method denied");
-               return;
-       }
-
-       wl_resource_set_implementation(resource, NULL, input_method,
-                                      unbind_input_method);
-       input_method->input_method_binding = resource;
-}
-
-static void
-input_method_notifier_destroy(struct wl_listener *listener, void *data)
-{
-       struct input_method *input_method =
-               container_of(listener, struct input_method, destroy_listener);
-
-       if (input_method->input)
-               deactivate_input_method(input_method);
-
-       wl_global_destroy(input_method->input_method_global);
-       wl_list_remove(&input_method->destroy_listener.link);
-
-       free(input_method);
-}
-
 static void
 handle_keyboard_focus(struct wl_listener *listener, void *data)
 {
@@ -911,11 +792,16 @@ handle_keyboard_focus(struct wl_listener *listener, void 
*data)
                             keyboard_focus_listener);
        struct weston_surface *surface = keyboard->focus;
 
-       if (!input_method->input)
+       if (!input_method->input) {
+               input_method->pending_focused_surface = surface;
                return;
+       }
 
-       if (!surface || input_method->input->surface != surface)
-               deactivate_input_method(input_method);
+       if (!surface || input_method->input->surface != surface) {
+               deactivate_text_input(input_method->input);
+       }
+
+       input_method->pending_focused_surface = surface;
 }
 
 static void
@@ -1001,43 +887,282 @@ launch_input_method(struct text_backend *text_backend)
                                       &text_backend->client_listener);
 }
 
+static void input_method_get_input_popup_surface(struct wl_client *client,
+                                                struct wl_resource *resource,
+                                                uint32_t id,
+                                                struct wl_resource *surface)
+{
+       weston_log("stub: 
zwp_input_method_v2_interface:get_input_popup_surface\n");
+}
+
+static const struct zwp_input_method_v2_interface input_method_implementation 
= {
+       input_method_commit_string,
+       input_method_set_preedit_string,
+       input_method_delete_surrounding_text,
+       input_method_commit,
+       input_method_get_input_popup_surface,
+       input_method_grab_keyboard,
+       input_method_destroy,
+};
+
 static void
-text_backend_seat_created(struct text_backend *text_backend,
-                         struct weston_seat *seat)
+destroy_input_method(struct wl_resource *resource)
 {
+       struct input_method *input_method =
+               wl_resource_get_user_data(resource);
+
+       if (input_method->keyboard)
+               wl_resource_destroy(input_method->keyboard);
+
+       if (input_method->input)
+               deactivate_input_method(input_method);
+
+       if (input_method->pending.commit_text)
+               free(input_method->pending.commit_text);
+       if (input_method->pending.preedit.text)
+               free(input_method->pending.preedit.text);
+       if (input_method->current.commit_text)
+               free(input_method->current.commit_text);
+       if (input_method->current.preedit.text)
+               free(input_method->current.preedit.text);
+
+       wl_list_remove(&input_method->link);
+
+       free(input_method);
+}
+
+static void
+input_method_manager_get_input_method(struct wl_client *client,
+                                     struct wl_resource *resource,
+                                     struct wl_resource *seat,
+                                     uint32_t id)
+{
+       struct input_method_manager *input_method_manager =
+               wl_resource_get_user_data(resource);
+       struct weston_seat *weston_seat = wl_resource_get_user_data(seat);
        struct input_method *input_method;
-       struct weston_compositor *ec = seat->compositor;
 
        input_method = zalloc(sizeof *input_method);
        if (input_method == NULL)
                return;
 
-       input_method->seat = seat;
+       input_method->resource =
+               wl_resource_create(client, &zwp_input_method_v2_interface, 1, 
id);
+       wl_resource_set_implementation(input_method->resource,
+                                      &input_method_implementation,
+                                      input_method, destroy_input_method);
+
+       input_method->seat = weston_seat;
        input_method->input = NULL;
        input_method->focus_listener_initialized = false;
-       input_method->context = NULL;
-       input_method->text_backend = text_backend;
+       input_method->manager = input_method_manager;
+       input_method->pending_focused_surface = NULL;
+
+       weston_seat->input_method = input_method;
+
+       input_method_init_seat(weston_seat);
+
+       wl_list_insert(&input_method_manager->input_methods, 
&input_method->link);
+};
+
+static void
+input_method_manager_destroy(struct wl_client *client,
+                            struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static const struct zwp_input_method_manager_v2_interface 
input_method_manager_implementation = {
+       input_method_manager_get_input_method,
+       input_method_manager_destroy
+};
+
+static void
+bind_input_method_manager(struct wl_client *client,
+                         void *data,
+                         uint32_t version,
+                         uint32_t id)
+{
+       struct input_method_manager *input_method_manager = data;
+       struct wl_resource *resource;
+
+       resource =
+               wl_resource_create(client,
+                                  &zwp_input_method_manager_v2_interface, 1, 
id);
+       if (resource)
+               wl_resource_set_implementation(resource,
+                                              
&input_method_manager_implementation,
+                                              input_method_manager, NULL);
+}
+
+static void
+input_method_manager_notifier_destroy(struct wl_listener *listener, void *data)
+{
+       struct input_method_manager *input_method_manager =
+               container_of(listener,
+                            struct input_method_manager,
+                            destroy_listener);
+       struct input_method *input_method, *input_method_tmp;
+
+       wl_list_for_each_safe(input_method, input_method_tmp,
+                             &input_method_manager->input_methods, link) {
+               wl_resource_destroy(input_method->resource);
+       }
+
+       wl_list_remove(&input_method_manager->destroy_listener.link);
+       wl_global_destroy(input_method_manager->input_method_manager_global);
+
+       free(input_method_manager);
+}
 
-       input_method->input_method_global =
+static void
+input_method_manager_create(struct weston_compositor *ec)
+{
+       struct input_method_manager *input_method_manager;
+
+       input_method_manager = zalloc(sizeof *input_method_manager);
+       if (input_method_manager == NULL)
+               return;
+
+       input_method_manager->ec = ec;
+
+       input_method_manager->input_method_manager_global =
                wl_global_create(ec->wl_display,
-                                &zwp_input_method_v1_interface, 1,
-                                input_method, bind_input_method);
+                                &zwp_input_method_manager_v2_interface, 1,
+                                input_method_manager, 
bind_input_method_manager);
 
-       input_method->destroy_listener.notify = input_method_notifier_destroy;
-       wl_signal_add(&seat->destroy_signal, &input_method->destroy_listener);
+       input_method_manager->destroy_listener.notify =
+               input_method_manager_notifier_destroy;
+       wl_signal_add(&ec->destroy_signal,
+                     &input_method_manager->destroy_listener);
+
+       wl_list_init(&input_method_manager->input_methods);
+}
 
-       seat->input_method = input_method;
+static void
+virtual_keyboard_destroy(struct wl_client *client,
+                        struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
 }
 
+static const struct zwp_virtual_keyboard_v1_interface 
virtual_keyboard_implementation = {
+       virtual_keyboard_keymap,
+       virtual_keyboard_key,
+       virtual_keyboard_modifiers,
+       virtual_keyboard_destroy,
+};
+
 static void
-handle_seat_created(struct wl_listener *listener, void *data)
+destroy_virtual_keyboard(struct wl_resource *resource)
 {
-       struct weston_seat *seat = data;
-       struct text_backend *text_backend =
-               container_of(listener, struct text_backend,
-                            seat_created_listener);
+       struct virtual_keyboard *virtual_keyboard =
+               wl_resource_get_user_data(resource);
 
-       text_backend_seat_created(text_backend, seat);
+       wl_list_remove(&virtual_keyboard->link);
+
+       free(virtual_keyboard);
+}
+
+static void
+virtual_keyboard_manager_create_virtual_keyboard(struct wl_client *client,
+                                                struct wl_resource *resource,
+                                                struct wl_resource *seat,
+                                                uint32_t id)
+{
+       struct virtual_keyboard_manager *virtual_keyboard_manager =
+               wl_resource_get_user_data(resource);
+       struct weston_seat *weston_seat = wl_resource_get_user_data(seat);
+       struct virtual_keyboard *virtual_keyboard;
+
+       virtual_keyboard = zalloc(sizeof *virtual_keyboard);
+       if (virtual_keyboard == NULL)
+               return;
+
+       virtual_keyboard->resource =
+               wl_resource_create(client, &zwp_virtual_keyboard_v1_interface, 
1, id);
+       wl_resource_set_implementation(virtual_keyboard->resource,
+                                      &virtual_keyboard_implementation,
+                                      virtual_keyboard, 
destroy_virtual_keyboard);
+
+       virtual_keyboard->seat = weston_seat;
+       virtual_keyboard->manager = virtual_keyboard_manager;
+
+       wl_list_insert(&virtual_keyboard_manager->virtual_keyboards, 
&virtual_keyboard->link);
+};
+
+static void
+virtual_keyboard_manager_destroy(struct wl_client *client,
+                                struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static const struct zwp_virtual_keyboard_manager_v1_interface 
virtual_keyboard_manager_implementation = {
+       virtual_keyboard_manager_create_virtual_keyboard,
+       virtual_keyboard_manager_destroy,
+};
+
+static void
+bind_virtual_keyboard_manager(struct wl_client *client,
+                             void *data,
+                             uint32_t version,
+                             uint32_t id)
+{
+       struct virtual_keyboard_manager *virtual_keyboard_manager = data;
+       struct wl_resource *resource;
+
+       resource =
+               wl_resource_create(client,
+                                  &zwp_virtual_keyboard_manager_v1_interface, 
1, id);
+       if (resource)
+               wl_resource_set_implementation(resource,
+                                              
&virtual_keyboard_manager_implementation,
+                                              virtual_keyboard_manager, NULL);
+}
+
+static void
+virtual_keyboard_manager_notifier_destroy(struct wl_listener *listener, void 
*data)
+{
+       struct virtual_keyboard_manager *virtual_keyboard_manager =
+               container_of(listener,
+                            struct virtual_keyboard_manager,
+                            destroy_listener);
+       struct virtual_keyboard *virtual_keyboard, *virtual_keyboard_tmp;
+
+       wl_list_for_each_safe(virtual_keyboard, virtual_keyboard_tmp,
+                             &virtual_keyboard_manager->virtual_keyboards, 
link) {
+               wl_resource_destroy(virtual_keyboard->resource);
+       }
+
+       wl_list_remove(&virtual_keyboard_manager->destroy_listener.link);
+       
wl_global_destroy(virtual_keyboard_manager->virtual_keyboard_manager_global);
+
+       free(virtual_keyboard_manager);
+}
+
+static void
+virtual_keyboard_manager_create(struct weston_compositor *ec)
+{
+       struct virtual_keyboard_manager *virtual_keyboard_manager;
+
+       virtual_keyboard_manager = zalloc(sizeof *virtual_keyboard_manager);
+       if (virtual_keyboard_manager == NULL)
+               return;
+
+       virtual_keyboard_manager->ec = ec;
+
+       virtual_keyboard_manager->virtual_keyboard_manager_global =
+               wl_global_create(ec->wl_display,
+                                &zwp_virtual_keyboard_manager_v1_interface, 1,
+                                virtual_keyboard_manager, 
bind_virtual_keyboard_manager);
+
+       virtual_keyboard_manager->destroy_listener.notify =
+               virtual_keyboard_manager_notifier_destroy;
+       wl_signal_add(&ec->destroy_signal,
+                     &virtual_keyboard_manager->destroy_listener);
+
+       wl_list_init(&virtual_keyboard_manager->virtual_keyboards);
 }
 
 static void
@@ -1059,8 +1184,6 @@ text_backend_configuration(struct text_backend 
*text_backend)
 WL_EXPORT void
 text_backend_destroy(struct text_backend *text_backend)
 {
-       wl_list_remove(&text_backend->seat_created_listener.link);
-
        if (text_backend->input_method.client) {
                /* disable respawn */
                wl_list_remove(&text_backend->client_listener.link);
@@ -1075,7 +1198,6 @@ WL_EXPORT struct text_backend *
 text_backend_init(struct weston_compositor *ec)
 {
        struct text_backend *text_backend;
-       struct weston_seat *seat;
 
        text_backend = zalloc(sizeof(*text_backend));
        if (text_backend == NULL)
@@ -1085,13 +1207,9 @@ text_backend_init(struct weston_compositor *ec)
 
        text_backend_configuration(text_backend);
 
-       wl_list_for_each(seat, &ec->seat_list, link)
-               text_backend_seat_created(text_backend, seat);
-       text_backend->seat_created_listener.notify = handle_seat_created;
-       wl_signal_add(&ec->seat_created_signal,
-                     &text_backend->seat_created_listener);
-
+       input_method_manager_create(ec);
        text_input_manager_create(ec);
+       virtual_keyboard_manager_create(ec);
 
        launch_input_method(text_backend);
 
diff --git a/desktop-shell/input-panel.c b/desktop-shell/input-panel.c
index 8292f20a..f7a60809 100644
--- a/desktop-shell/input-panel.c
+++ b/desktop-shell/input-panel.c
@@ -31,7 +31,7 @@
 #include <string.h>
 
 #include "shell.h"
-#include "input-method-unstable-v1-server-protocol.h"
+#include "weston-input-panel-server-protocol.h"
 #include "shared/helpers.h"
 
 struct input_panel_surface {
@@ -294,7 +294,7 @@ input_panel_surface_set_overlay_panel(struct wl_client 
*client,
        input_panel_surface->panel = 1;
 }
 
-static const struct zwp_input_panel_surface_v1_interface 
input_panel_surface_implementation = {
+static const struct weston_input_panel_surface_interface 
input_panel_surface_implementation = {
        input_panel_surface_set_toplevel,
        input_panel_surface_set_overlay_panel
 };
@@ -336,7 +336,7 @@ input_panel_get_input_panel_surface(struct wl_client 
*client,
 
        ipsurf->resource =
                wl_resource_create(client,
-                                  &zwp_input_panel_surface_v1_interface,
+                                  &weston_input_panel_surface_interface,
                                   1,
                                   id);
        wl_resource_set_implementation(ipsurf->resource,
@@ -345,7 +345,7 @@ input_panel_get_input_panel_surface(struct wl_client 
*client,
                                       destroy_input_panel_surface_resource);
 }
 
-static const struct zwp_input_panel_v1_interface input_panel_implementation = {
+static const struct weston_input_panel_interface input_panel_implementation = {
        input_panel_get_input_panel_surface
 };
 
@@ -365,7 +365,7 @@ bind_input_panel(struct wl_client *client,
        struct wl_resource *resource;
 
        resource = wl_resource_create(client,
-                                     &zwp_input_panel_v1_interface, 1, id);
+                                     &weston_input_panel_interface, 1, id);
 
        if (shell->input_panel.binding == NULL) {
                wl_resource_set_implementation(resource,
@@ -404,7 +404,7 @@ input_panel_setup(struct desktop_shell *shell)
        wl_list_init(&shell->input_panel.surfaces);
 
        if (wl_global_create(shell->compositor->wl_display,
-                            &zwp_input_panel_v1_interface, 1,
+                            &weston_input_panel_interface, 1,
                             shell, bind_input_panel) == NULL)
                return -1;
 
diff --git a/desktop-shell/meson.build b/desktop-shell/meson.build
index 07013437..a785648b 100644
--- a/desktop-shell/meson.build
+++ b/desktop-shell/meson.build
@@ -8,8 +8,8 @@ if get_option('shell-desktop')
                '../shared/matrix.c',
                weston_desktop_shell_server_protocol_h,
                weston_desktop_shell_protocol_c,
-               input_method_unstable_v1_server_protocol_h,
-               input_method_unstable_v1_protocol_c,
+               weston_input_panel_server_protocol_h,
+               weston_input_panel_protocol_c,
        ]
        deps_shell_desktop = [
                dep_libshared,
diff --git a/protocol/meson.build b/protocol/meson.build
index 34026ff9..b9c02376 100644
--- a/protocol/meson.build
+++ b/protocol/meson.build
@@ -16,6 +16,7 @@ install_data(
 
 generated_protocols = [
        [ 'input-method', 'v1' ],
+       [ 'input-method', 'v2' ],
        [ 'input-timestamps', 'v1' ],
        [ 'ivi-application', 'internal' ],
        [ 'ivi-hmi-controller', 'internal' ],
@@ -28,9 +29,12 @@ generated_protocols = [
        [ 'tablet', 'v2' ],
        [ 'text-cursor-position', 'internal' ],
        [ 'text-input', 'v1' ],
+       [ 'text-input', 'v3' ],
        [ 'viewporter', 'stable' ],
+       [ 'virtual-keyboard', 'v1' ],
        [ 'weston-debug', 'internal' ],
        [ 'weston-desktop-shell', 'internal' ],
+       [ 'weston-input-panel', 'internal' ],
        [ 'weston-screenshooter', 'internal' ],
        [ 'weston-test', 'internal' ],
        [ 'weston-touch-calibration', 'internal' ],
diff --git a/protocol/weston-input-panel.xml b/protocol/weston-input-panel.xml
new file mode 100644
index 00000000..9a68a441
--- /dev/null
+++ b/protocol/weston-input-panel.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="weston_input_panel">
+
+  <copyright>
+    Copyright © 2012, 2013 Intel Corporation
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="weston_input_panel" version="1">
+    <description summary="interface for implementing keyboards">
+      Only one client can bind this interface at a time.
+    </description>
+
+    <request name="get_input_panel_surface">
+      <arg name="id" type="new_id" interface="weston_input_panel_surface"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="weston_input_panel_surface" version="1">
+    <enum name="position">
+      <entry name="center_bottom" value="0"/>
+    </enum>
+
+    <request name="set_toplevel">
+      <description summary="set the surface type as a keyboard">
+       Set the input_panel_surface type to keyboard.
+
+       A keyboard surface is only shown when a text input is active.
+      </description>
+      <arg name="output" type="object" interface="wl_output"/>
+      <arg name="position" type="uint"/>
+    </request>
+
+    <request name="set_overlay_panel">
+      <description summary="set the surface type as an overlay panel">
+       Set the input_panel_surface to be an overlay panel.
+
+       This is shown near the input cursor above the application window when
+       a text input is active.
+      </description>
+    </request>
+  </interface>
+
+</protocol>
diff --git a/tests/meson.build b/tests/meson.build
index 03692f47..ac65183d 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -156,8 +156,10 @@ tests_weston = [
        [
                'text',
                [
-                       text_input_unstable_v1_client_protocol_h,
-                       text_input_unstable_v1_protocol_c,
+                       text_input_unstable_v3_client_protocol_h,
+                       text_input_unstable_v3_protocol_c,
+                       input_method_unstable_v2_client_protocol_h,
+                       input_method_unstable_v2_protocol_c,
                ]
        ],
        [
diff --git a/tests/text-test.c b/tests/text-test.c
index 685a28dc..079a5d8e 100644
--- a/tests/text-test.c
+++ b/tests/text-test.c
@@ -30,7 +30,8 @@
 #include <stdio.h>
 
 #include "weston-test-client-helper.h"
-#include "text-input-unstable-v1-client-protocol.h"
+#include "text-input-unstable-v3-client-protocol.h"
+#include "input-method-unstable-v2-client-protocol.h"
 
 struct text_input_state {
        int activated;
@@ -39,74 +40,38 @@ struct text_input_state {
 
 static void
 text_input_commit_string(void *data,
-                        struct zwp_text_input_v1 *text_input,
-                        uint32_t serial,
+                        struct zwp_text_input_v3 *text_input,
                         const char *text)
 {
 }
 
 static void
 text_input_preedit_string(void *data,
-                         struct zwp_text_input_v1 *text_input,
-                         uint32_t serial,
+                         struct zwp_text_input_v3 *text_input,
                          const char *text,
-                         const char *commit)
+                         int32_t cursor_begin,
+                         int32_t cursor_end)
 {
 }
 
 static void
 text_input_delete_surrounding_text(void *data,
-                                  struct zwp_text_input_v1 *text_input,
-                                  int32_t index,
-                                  uint32_t length)
+                                  struct zwp_text_input_v3 *text_input,
+                                  uint32_t before_length,
+                                  uint32_t after_length)
 {
 }
 
 static void
-text_input_cursor_position(void *data,
-                          struct zwp_text_input_v1 *text_input,
-                          int32_t index,
-                          int32_t anchor)
-{
-}
-
-static void
-text_input_preedit_styling(void *data,
-                          struct zwp_text_input_v1 *text_input,
-                          uint32_t index,
-                          uint32_t length,
-                          uint32_t style)
-{
-}
-
-static void
-text_input_preedit_cursor(void *data,
-                         struct zwp_text_input_v1 *text_input,
-                         int32_t index)
-{
-}
-
-static void
-text_input_modifiers_map(void *data,
-                        struct zwp_text_input_v1 *text_input,
-                        struct wl_array *map)
-{
-}
-
-static void
-text_input_keysym(void *data,
-                 struct zwp_text_input_v1 *text_input,
-                 uint32_t serial,
-                 uint32_t time,
-                 uint32_t sym,
-                 uint32_t state,
-                 uint32_t modifiers)
+text_input_done(void *data,
+               struct zwp_text_input_v3 *zwp_text_input_v3,
+               uint32_t serial)
 {
 }
 
 static void
 text_input_enter(void *data,
-                struct zwp_text_input_v1 *text_input,
+                struct zwp_text_input_v3 *text_input,
                 struct wl_surface *surface)
 
 {
@@ -119,76 +84,69 @@ text_input_enter(void *data,
 
 static void
 text_input_leave(void *data,
-                struct zwp_text_input_v1 *text_input)
+                struct zwp_text_input_v3 *text_input,
+                struct wl_surface *surface)
 {
        struct text_input_state *state = data;
 
        state->deactivated += 1;
 }
 
-static void
-text_input_input_panel_state(void *data,
-                            struct zwp_text_input_v1 *text_input,
-                            uint32_t state)
-{
-}
-
-static void
-text_input_language(void *data,
-                   struct zwp_text_input_v1 *text_input,
-                   uint32_t serial,
-                   const char *language)
-{
-}
-
-static void
-text_input_text_direction(void *data,
-                         struct zwp_text_input_v1 *text_input,
-                         uint32_t serial,
-                         uint32_t direction)
-{
-}
-
-static const struct zwp_text_input_v1_listener text_input_listener = {
+static const struct zwp_text_input_v3_listener text_input_listener = {
        text_input_enter,
        text_input_leave,
-       text_input_modifiers_map,
-       text_input_input_panel_state,
        text_input_preedit_string,
-       text_input_preedit_styling,
-       text_input_preedit_cursor,
        text_input_commit_string,
-       text_input_cursor_position,
        text_input_delete_surrounding_text,
-       text_input_keysym,
-       text_input_language,
-       text_input_text_direction
+       text_input_done,
 };
 
 TEST(text_test)
 {
        struct client *client;
        struct global *global;
-       struct zwp_text_input_manager_v1 *factory;
-       struct zwp_text_input_v1 *text_input;
+       struct zwp_input_method_manager_v2 *input_method_factory;
+       struct zwp_input_method_v2 *input_method;
+       struct zwp_text_input_manager_v3 *text_input_factory;
+       struct zwp_text_input_v3 *text_input;
        struct text_input_state state;
 
        client = create_client_and_test_surface(100, 100, 100, 100);
        assert(client);
 
-       factory = NULL;
+       input_method_factory = NULL;
+       text_input_factory = NULL;
        wl_list_for_each(global, &client->global_list, link) {
-               if (strcmp(global->interface, "zwp_text_input_manager_v1") == 0)
-                       factory = wl_registry_bind(client->wl_registry,
-                                                  global->name,
-                                                  
&zwp_text_input_manager_v1_interface, 1);
+               if (strcmp(global->interface, "zwp_input_method_manager_v2") == 
0) {
+                       input_method_factory = 
wl_registry_bind(client->wl_registry,
+                                                               global->name,
+                                                               
&zwp_input_method_manager_v2_interface, 1);
+               }
+               else if (strcmp(global->interface, "zwp_text_input_manager_v3") 
== 0) {
+                       text_input_factory = 
wl_registry_bind(client->wl_registry,
+                                                             global->name,
+                                                             
&zwp_text_input_manager_v3_interface, 1);
+               }
        }
 
-       assert(factory);
+       assert(input_method_factory);
+       assert(text_input_factory);
 
        memset(&state, 0, sizeof state);
-       text_input = zwp_text_input_manager_v1_create_text_input(factory);
-       zwp_text_input_v1_add_listener(text_input,
+
+       /* Initialize input method for seat.
+        * text-input will only receive enter/leave events if there is
+        * an input method available.
+        */
+       input_method = 
zwp_input_method_manager_v2_get_input_method(input_method_factory,
+                                                                   
client->input->wl_seat);
+       assert(input_method);
+
+       /* Initialize text input for seat. */
+       text_input = 
zwp_text_input_manager_v3_get_text_input(text_input_factory,
+                                                             
client->input->wl_seat);
+       assert(text_input);
+       zwp_text_input_v3_add_listener(text_input,
                                       &text_input_listener,
                                       &state);
 
@@ -199,19 +157,20 @@ TEST(text_test)
        assert(client->input->keyboard->focus == client->surface);
 
        /* Activate test model and make sure we get enter event. */
-       zwp_text_input_v1_activate(text_input, client->input->wl_seat,
-                                  client->surface->wl_surface);
+       zwp_text_input_v3_enable(text_input);
+       zwp_text_input_v3_commit(text_input);
        client_roundtrip(client);
        assert(state.activated == 1 && state.deactivated == 0);
 
        /* Deactivate test model and make sure we get leave event. */
-       zwp_text_input_v1_deactivate(text_input, client->input->wl_seat);
+       zwp_text_input_v3_disable(text_input);
+       zwp_text_input_v3_commit(text_input);
        client_roundtrip(client);
        assert(state.activated == 1 && state.deactivated == 1);
 
        /* Activate test model again. */
-       zwp_text_input_v1_activate(text_input, client->input->wl_seat,
-                                  client->surface->wl_surface);
+       zwp_text_input_v3_enable(text_input);
+       zwp_text_input_v3_commit(text_input);
        client_roundtrip(client);
        assert(state.activated == 2 && state.deactivated == 1);
 
-- 
2.20.1

_______________________________________________
wayland-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to