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
