From 74162b7401844d58ee82541b39c51ec2aa264867 Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Thu, 29 Jul 2021 13:27:31 -0400
Subject: [PATCH] wayland: Add support for text-input-unstable-v3
---
src/video/wayland/SDL_waylandevents.c | 141 +++++-
src/video/wayland/SDL_waylandevents_c.h | 3 +
src/video/wayland/SDL_waylandkeyboard.c | 86 +++-
src/video/wayland/SDL_waylandkeyboard.h | 7 +
src/video/wayland/SDL_waylandvideo.c | 11 +-
src/video/wayland/SDL_waylandvideo.h | 1 +
wayland-protocols/text-input-unstable-v3.xml | 452 +++++++++++++++++++
7 files changed, 690 insertions(+), 11 deletions(-)
create mode 100644 wayland-protocols/text-input-unstable-v3.xml
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 29786d3879..a8e7c80ede 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -41,6 +41,7 @@
#include "relative-pointer-unstable-v1-client-protocol.h"
#include "xdg-shell-client-protocol.h"
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
+#include "text-input-unstable-v3-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@@ -221,7 +222,7 @@ Wayland_PumpEvents(_THIS)
WAYLAND_wl_display_flush(d->display);
#ifdef SDL_USE_IME
- if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
+ if (d->text_input_manager == NULL && SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
SDL_IME_PumpEvents();
}
#endif
@@ -741,7 +742,9 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
SDL_SetKeyboardFocus(window->sdlwindow);
}
#ifdef SDL_USE_IME
- SDL_IME_SetFocus(SDL_TRUE);
+ if (!input->text_input) {
+ SDL_IME_SetFocus(SDL_TRUE);
+ }
#endif
}
@@ -760,8 +763,11 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
/* This will release any keys still pressed */
SDL_SetKeyboardFocus(NULL);
+
#ifdef SDL_USE_IME
- SDL_IME_SetFocus(SDL_FALSE);
+ if (!input->text_input) {
+ SDL_IME_SetFocus(SDL_FALSE);
+ }
#endif
}
@@ -1224,6 +1230,93 @@ static const struct wl_data_device_listener data_device_listener = {
data_device_handle_selection
};
+static void
+text_input_enter(void *data,
+ struct zwp_text_input_v3 *zwp_text_input_v3,
+ struct wl_surface *surface)
+{
+ /* No-op */
+}
+
+static void
+text_input_leave(void *data,
+ struct zwp_text_input_v3 *zwp_text_input_v3,
+ struct wl_surface *surface)
+{
+ /* No-op */
+}
+
+static void
+text_input_preedit_string(void *data,
+ struct zwp_text_input_v3 *zwp_text_input_v3,
+ const char *text,
+ int32_t cursor_begin,
+ int32_t cursor_end)
+{
+ char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
+ if (text) {
+ size_t text_bytes = SDL_strlen(text), i = 0;
+ size_t cursor = 0;
+
+ do {
+ const size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
+ const size_t chars = SDL_utf8strlen(buf);
+
+ SDL_SendEditingText(buf, cursor, chars);
+
+ i += sz;
+ cursor += chars;
+ } while (i < text_bytes);
+ } else {
+ buf[0] = '\0';
+ SDL_SendEditingText(buf, 0, 0);
+ }
+}
+
+static void
+text_input_commit_string(void *data,
+ struct zwp_text_input_v3 *zwp_text_input_v3,
+ const char *text)
+{
+ if (text && *text) {
+ char buf[SDL_TEXTINPUTEVENT_TEXT_SIZE];
+ size_t text_bytes = SDL_strlen(text), i = 0;
+
+ while (i < text_bytes) {
+ size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
+ SDL_SendKeyboardText(buf);
+
+ i += sz;
+ }
+ }
+}
+
+static void
+text_input_delete_surrounding_text(void *data,
+ struct zwp_text_input_v3 *zwp_text_input_v3,
+ uint32_t before_length,
+ uint32_t after_length)
+{
+ /* FIXME: Do we care about this event? */
+}
+
+static void
+text_input_done(void *data,
+ struct zwp_text_input_v3 *zwp_text_input_v3,
+ uint32_t serial)
+{
+ /* No-op */
+}
+
+static const struct zwp_text_input_v3_listener text_input_listener = {
+ text_input_enter,
+ text_input_leave,
+ text_input_preedit_string,
+ text_input_commit_string,
+ text_input_delete_surrounding_text,
+ text_input_done
+};
+
static void
Wayland_create_data_device(SDL_VideoData *d)
{
@@ -1249,6 +1342,30 @@ Wayland_create_data_device(SDL_VideoData *d)
}
}
+static void
+Wayland_create_text_input(SDL_VideoData *d)
+{
+ SDL_WaylandTextInput *text_input = NULL;
+
+ text_input = SDL_calloc(1, sizeof *text_input);
+ if (text_input == NULL) {
+ return;
+ }
+
+ text_input->text_input = zwp_text_input_manager_v3_get_text_input(
+ d->text_input_manager, d->input->seat
+ );
+
+ if (text_input->text_input == NULL) {
+ SDL_free(text_input);
+ } else {
+ zwp_text_input_v3_set_user_data(text_input->text_input, text_input);
+ zwp_text_input_v3_add_listener(text_input->text_input,
+ &text_input_listener, text_input);
+ d->input->text_input = text_input;
+ }
+}
+
void
Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
{
@@ -1259,6 +1376,16 @@ Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
}
}
+void
+Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
+{
+ d->text_input_manager = wl_registry_bind(d->registry, id, &zwp_text_input_manager_v3_interface, 1);
+
+ if (d->input != NULL) {
+ Wayland_create_text_input(d);
+ }
+}
+
void
Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
{
@@ -1277,6 +1404,9 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
if (d->data_device_manager != NULL) {
Wayland_create_data_device(d);
}
+ if (d->text_input_manager != NULL) {
+ Wayland_create_text_input(d);
+ }
wl_seat_add_listener(input->seat, &seat_listener, input);
wl_seat_set_user_data(input->seat, input);
@@ -1305,6 +1435,11 @@ void Wayland_display_destroy_input(SDL_VideoData *d)
SDL_free(input->data_device);
}
+ if (input->text_input != NULL) {
+ zwp_text_input_v3_destroy(input->text_input->text_input);
+ SDL_free(input->text_input);
+ }
+
if (input->keyboard)
wl_keyboard_destroy(input->keyboard);
diff --git a/src/video/wayland/SDL_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h
index f3604ac360..e4b76d830e 100644
--- a/src/video/wayland/SDL_waylandevents_c.h
+++ b/src/video/wayland/SDL_waylandevents_c.h
@@ -27,6 +27,7 @@
#include "SDL_waylandvideo.h"
#include "SDL_waylandwindow.h"
#include "SDL_waylanddatamanager.h"
+#include "SDL_waylandkeyboard.h"
typedef struct {
// repeat_rate in range of [1, 1000]
@@ -47,6 +48,7 @@ struct SDL_WaylandInput {
struct wl_touch *touch;
struct wl_keyboard *keyboard;
SDL_WaylandDataDevice *data_device;
+ SDL_WaylandTextInput *text_input;
struct zwp_relative_pointer_v1 *relative_pointer;
struct zwp_confined_pointer_v1 *confined_pointer;
SDL_Window *confined_pointer_window;
@@ -83,6 +85,7 @@ struct SDL_WaylandInput {
extern void Wayland_PumpEvents(_THIS);
extern void Wayland_add_data_device_manager(SDL_VideoData *d, uint32_t id, uint32_t version);
+extern void Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version);
extern void Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version);
extern void Wayland_display_destroy_input(SDL_VideoData *d);
diff --git a/src/video/wayland/SDL_waylandkeyboard.c b/src/video/wayland/SDL_waylandkeyboard.c
index 88384b3512..747a886dda 100644
--- a/src/video/wayland/SDL_waylandkeyboard.c
+++ b/src/video/wayland/SDL_waylandkeyboard.c
@@ -24,12 +24,17 @@
#include "../SDL_sysvideo.h"
#include "SDL_waylandvideo.h"
+#include "SDL_waylandevents_c.h"
+#include "text-input-unstable-v3-client-protocol.h"
int
Wayland_InitKeyboard(_THIS)
{
#ifdef SDL_USE_IME
- SDL_IME_Init();
+ SDL_VideoData *driverdata = _this->driverdata;
+ if (driverdata->text_input_manager == NULL) {
+ SDL_IME_Init();
+ }
#endif
return 0;
@@ -39,37 +44,106 @@ void
Wayland_QuitKeyboard(_THIS)
{
#ifdef SDL_USE_IME
- SDL_IME_Quit();
+ SDL_VideoData *driverdata = _this->driverdata;
+ if (driverdata->text_input_manager == NULL) {
+ SDL_IME_Quit();
+ }
#endif
}
void
Wayland_StartTextInput(_THIS)
{
- /* No-op */
+ SDL_VideoData *driverdata = _this->driverdata;
+
+ if (driverdata->text_input_manager) {
+ struct SDL_WaylandInput *input = driverdata->input;
+ if (input != NULL && input->text_input) {
+ const SDL_Rect *rect = &input->text_input->cursor_rect;
+
+ /* For some reason this has to be done twice, it appears to be a
+ * bug in mutter? Maybe?
+ * -flibit
+ */
+ zwp_text_input_v3_enable(input->text_input->text_input);
+ zwp_text_input_v3_commit(input->text_input->text_input);
+ zwp_text_input_v3_enable(input->text_input->text_input);
+ zwp_text_input_v3_commit(input->text_input->text_input);
+
+ /* Now that it's enabled, set the input properties */
+ zwp_text_input_v3_set_content_type(input->text_input->text_input,
+ ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE,
+ ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL);
+ if (!SDL_RectEmpty(rect)) {
+ /* This gets reset on enable so we have to cache it */
+ zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h);
+ }
+ zwp_text_input_v3_commit(input->text_input->text_input);
+ }
+ }
}
void
Wayland_StopTextInput(_THIS)
{
+ SDL_VideoData *driverdata = _this->driverdata;
+
+ if (driverdata->text_input_manager) {
+ struct SDL_WaylandInput *input = driverdata->input;
+ if (input != NULL && input->text_input) {
+ zwp_text_input_v3_disable(input->text_input->text_input);
+ zwp_text_input_v3_commit(input->text_input->text_input);
+ }
+ }
+
#ifdef SDL_USE_IME
- SDL_IME_Reset();
+ else {
+ SDL_IME_Reset();
+ }
#endif
}
void
Wayland_SetTextInputRect(_THIS, SDL_Rect *rect)
{
+ SDL_VideoData *driverdata = _this->driverdata;
+
if (!rect) {
SDL_InvalidParamError("rect");
return;
}
-
+
+ if (driverdata->text_input_manager) {
+ struct SDL_WaylandInput *input = driverdata->input;
+ if (input != NULL && input->text_input) {
+ SDL_memcpy(&input->text_input->cursor_rect, rect, sizeof(SDL_Rect));
+ zwp_text_input_v3_set_cursor_rectangle(input->text_input->text_input,
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h);
+ zwp_text_input_v3_commit(input->text_input->text_input);
+ }
+ }
+
#ifdef SDL_USE_IME
- SDL_IME_UpdateTextRect(rect);
+ else {
+ SDL_IME_UpdateTextRect(rect);
+ }
#endif
}
+SDL_bool
+Wayland_HasScreenKeyboardSupport(_THIS)
+{
+ SDL_VideoData *driverdata = _this->driverdata;
+ return (driverdata->text_input_manager != NULL);
+}
+
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/wayland/SDL_waylandkeyboard.h b/src/video/wayland/SDL_waylandkeyboard.h
index cca8ac8d9b..efc53d0fc6 100644
--- a/src/video/wayland/SDL_waylandkeyboard.h
+++ b/src/video/wayland/SDL_waylandkeyboard.h
@@ -23,11 +23,18 @@
#ifndef SDL_waylandkeyboard_h_
#define SDL_waylandkeyboard_h_
+typedef struct SDL_WaylandTextInput
+{
+ struct zwp_text_input_v3 *text_input;
+ SDL_Rect cursor_rect;
+} SDL_WaylandTextInput;
+
extern int Wayland_InitKeyboard(_THIS);
extern void Wayland_QuitKeyboard(_THIS);
extern void Wayland_StartTextInput(_THIS);
extern void Wayland_StopTextInput(_THIS);
extern void Wayland_SetTextInputRect(_THIS, SDL_Rect *rect);
+extern SDL_bool Wayland_HasScreenKeyboardSupport(_THIS);
#endif /* SDL_waylandkeyboard_h_ */
diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index 0a5cf6e089..478fe0b699 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -51,6 +51,7 @@
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
+#include "text-input-unstable-v3-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@@ -253,6 +254,7 @@ Wayland_CreateDevice(int devindex)
device->DestroyWindow = Wayland_DestroyWindow;
device->SetWindowHitTest = Wayland_SetWindowHitTest;
device->FlashWindow = Wayland_FlashWindow;
+ device->HasScreenKeyboardSupport = Wayland_HasScreenKeyboardSupport;
device->SetClipboardText = Wayland_SetClipboardText;
device->GetClipboardText = Wayland_GetClipboardText;
@@ -507,6 +509,8 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
d->idle_inhibit_manager = wl_registry_bind(d->registry, id, &zwp_idle_inhibit_manager_v1_interface, 1);
} else if (SDL_strcmp(interface, "xdg_activation_v1") == 0) {
d->activation_manager = wl_registry_bind(d->registry, id, &xdg_activation_v1_interface, 1);
+ } else if (strcmp(interface, "zwp_text_input_manager_v3") == 0) {
+ Wayland_add_text_input_manager(d, id, version);
} else if (SDL_strcmp(interface, "wl_data_device_manager") == 0) {
Wayland_add_data_device_manager(d, id, version);
} else if (SDL_strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
@@ -642,6 +646,11 @@ Wayland_VideoQuit(_THIS)
if (data->key_inhibitor_manager)
zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(data->key_inhibitor_manager);
+ Wayland_QuitKeyboard(_this);
+
+ if (data->text_input_manager)
+ zwp_text_input_manager_v3_destroy(data->text_input_manager);
+
if (data->xkb_context) {
WAYLAND_xkb_context_unref(data->xkb_context);
data->xkb_context = NULL;
@@ -684,8 +693,6 @@ Wayland_VideoQuit(_THIS)
if (data->registry)
wl_registry_destroy(data->registry);
- Wayland_QuitKeyboard(_this);
-
SDL_free(data->classname);
}
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index f44706f1c4..ef769cee34 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -62,6 +62,7 @@ typedef struct {
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *key_inhibitor_manager;
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
struct xdg_activation_v1 *activation_manager;
+ struct zwp_text_input_manager_v3 *text_input_manager;
EGLDisplay edpy;
EGLContext context;
diff --git a/wayland-protocols/text-input-unstable-v3.xml b/wayland-protocols/text-input-unstable-v3.xml
new file mode 100644
index 0000000000..d5f6322b0a
--- /dev/null
+++ b/wayland-protocols/text-input-unstable-v3.xml
@@ -0,0 +1,452 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<protocol name="text_input_unstable_v3">
+ <copyright>
+ Copyright © 2012, 2013 Intel Corporation
+ Copyright © 2015, 2016 Jan Arne Petersen
+ Copyright © 2017, 2018 Red Hat, Inc.
+ Copyright © 2018 Purism SPC
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, provided that the above copyright notice appear in
+ all copies and that both that copyright notice and this permission
+ notice appear in supporting documentation, and that the name of
+ the copyright holders not be used in advertising or publicity
+ pertaining to distribution of the software without specific,
+ written prior permission. The copyright holders make no
+ representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied
+ warranty.
+
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+ </copyright>
+
+ <description summary="Protocol for composing text">
+ This protocol allows compositors to act as input methods and to send text
+ to applications. A text input object is used to manage state of what are
+ typically text entry fields in the application.
+
+ This document adheres to the RFC 2119 when using words like "must",
+ "should", "may", etc.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible changes
+ may be added together with the corresponding interface version bump.
+ Backward incompatible changes are done by bumping the version number in
+ the protocol and interface names and resetting the interface version.
+ Once the protocol is to be declared stable, the 'z' prefix and the
+ version number in the protocol and interface names are removed and the
+ interface version number is reset.
+ </description>
+
+ <interface name="zwp_text_input_v3" version="1">
+ <description summary="text input">
+ The zwp_text_input_v3 interface represents text input and input methods
+ associated with a seat. It provides enter/leave events to follow the
+ text input focus for a seat.
+
+ Requests are used to enable/disable the text-input object and set
+ state information like surrounding and selected text or the content type.
+ The information about the entered text is sent to the text-input object
+ via the preedit_string and commit_string events.
+
+ Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices
+ must not point to middle bytes inside a code point: they must either
+ point to the first byte of a code point or to the end of the buffer.
+ Lengths must be measured between two valid indices.
+
+ Focus moving throughout surfaces will result in the emission of
+ zwp_text_input_v3.enter and zwp_text_input_v3.leave events. The focused
+ surface must commit zwp_text_input_v3.enable and
+ zwp_text_input_v3.disable requests as the keyboard focus moves across
+ editable and non-editable elements of the UI. Those two requests are not
+ expected to be paired with each other, the compositor must be able to
+ handle consecutive series of the same request.
+
+ State is sent by the state requests (set_surrounding_text,
+ set_content_type and set_cursor_rectangle) and a commit request. After an
+ enter event or disable request all state information is invalidated and
+ needs to be resent by the client.
+ </description>
+
+ <request name="destroy" type="destructor">
+ <description summary="Destroy the wp_text_input">
+ Destroy the wp_text_input object. Also disables all surfaces enabled
+ through this wp_text_input object.
+ </description>
+ </request>
+
+ <request name="enable">
+ <description summary="Request text input to be enabled">
+ Requests text input on the surface previously obtained from the enter
+ event.
+
+ This request must be issued every time the active text input changes
+ to a new one, including within the current surface. Use
+ zwp_text_input_v3.disable when there is no longer any input focus on
+ the current surface.
+
+ Clients must not enable more than one text input on the single seat
+ and should disable the current text input before enabling the new one.
+ At most one instance of text input may be in enabled state per instance,
+ Requests to enable the another text input when some text input is active
+ must be ignored by compositor.
+
+ This request resets all state associated with previous enable, disable,
+ set_surrounding_text, set_text_change_cause, set_content_type, and
+ set_cursor_rectangle requests, as well as the state associated with
+ preedit_string, commit_string, and delete_surrounding_text events.
+
+ The set_surrounding_text, set_content_type and set_cursor_rectangle
+ requests must follow if the text input supports the necessary
+ functionality.
+
+ State set with this request is double-buffered. It will get applied on
+ the next zwp_text_input_v3.commit request, and stay valid until the
+ next committed enable or disable request.
+
+ The changes must be applied by the compositor after issuing a
+ zwp_text_input_v3.commit request.
+ </description>
+ </request>
+
+ <request name="disable">
+ <description summary="Disable text input on a surface">
+ Explicitly disable text input on the current surface (typically when
+ there is no focus on any text entry inside the surface).
+
+ State set with this request is double-buffered. It will get applied on
+ the next zwp_text_input_v3.commit request.
+ </description>
+ </request>
+
+ <request name="set_surrounding_text">
+ <description summary="sets the surrounding text">
+ Sets the surrounding plain text around the input, excluding the preedit
+ text.
+
+ The client should notify the compositor of any changes in any of the
+ values carried with this request, including changes caused by handling
+ incoming text-input events as well as changes caused by other
+ mechanisms like keyboard typing.
+
+ If the client is unaware of the text around the cursor, it should not
+ issue this request, to signify lack of support to the compositor.
+
+ Text is UTF-8 encoded, and should include the cursor position, the
+ complete selection and additional characters before and after them.
+ There is a maximum length of wayland messages, so text can not be
+ longer than 4000 bytes.
+
+ Cursor is the byte offset of the cursor within text buffer.
+
+ Anchor is the byte offset of the selection anchor within text buffer.
+ If there is no selected text, anchor is the same as cursor.
+
+ If any preedit text is present, it is replaced with a cursor for the
+ purpose of this event.
+
+ Values set with this request are double-buffered. They will get applied
+ on the next zwp_text_input_v3.commit request, and stay valid until the
+ next committed enable or disable request.
+
+ The initial state for affected fields is empty, meaning that the text
+ input does not support sending surrounding text. If the empty values
+ get applied, subsequent attempts to change them may have no effect.
+ </description>
+ <arg name="text" type="string"/>
+ <arg name="cursor" type="int"/>
+ <arg name="anchor" type="int"/>
+ </request>
+
+ <enum name="change_cause">
+ <description summary="text change reason">
+ Reason for the change of surrounding text or cursor posision.
+ </description>
+ <entry name="input_method" value="0" summary="input method caused the change"/>
+ <entry name="other" value="1" summary="something else than the input method caused the change"/>
+ </enum>
+
+ <request name="set_text_change_cause">
+ <description summary="indicates the cause of surrounding text change">
+ Tells the compositor why the text surrounding the cursor changed.
+
+ Whenever the client detects an external change in text, cursor, or
+ anchor posision, it must issue this request to the compositor. This
+ request is intended to give the input method a chance to update the
+ preedit text in an appropriate way, e.g. by removing it when the user
+ starts typing with a keyboard.
+
+ cause describes the source of the change.
+
+ The value set with this request is double-buffered. It must be applied
+ and reset to initial at the next zwp_text_input_v3.commit request.
+
+ The initial value of cause is input_method.
+ </description>
+ <arg name="cause" type="uint" enum="change_cause"/>
+ </request>
+
+ <enum name="content_hint" bitfield="true">
+ <description summary="content hint">
+ Content hint is a bitmask to allow to modify the behavior of the text
+ input.
+ </description>
+ <entry name="none" value="0x0" summary="no special behavior"/>
+ <entry name="completion" value="0x1" summary="suggest word completions"/>
+ <entry name="spellcheck" value="0x2" summary="suggest word corrections"/>
+ <entry name="auto_capitalization" value="0x4" summary="switch to uppercase letters at the start of a sentence"/>
+ <entry name="lowercase" value="0x8" summary="prefer lowercase letters"/>
+ <entry name="uppercase" value="0x10" summary="prefer uppercase letters"/>
+ <entry name="titlecase" value="0x20" summary="prefer casing for titles and headings (can be language dependent)"/>
+ <entry name="hidden_text" value="0x40" summary="characters should be hidden"/>
+ <entry name="sensitive_data" value="0x80" summary="typed text should not be stored"/>
+ <entry name="latin" value="0x100" summary="just Latin characters should be entered"/>
+ <entry name="multiline" value="0x200" summary="the text input is multiline"/>
+ </enum>
+
+ <enum name="content_purpose">
+ <description summary="content purpose">
+ The content purpose allows to specify the primary purpose of a text
+ input.
+
+ This allows an input method to show special purpose input panels with
+ extra characters or to disallow some characters.
+ </description>
+ <entry name="normal" value="0" summary="default input, allowing all characters"/>
+ <entry name="alpha" value="1" summary="allow only alphabetic characters"/>
+ <entry name="digits" value="2" summary="allow only digits"/>
+ <entry name="number" value="3" summary="input a number (including decimal separator and sign)"/>
+ <entry name="phone" value="4" summary="input a phone number"/>
+ <entry name="url" value="5" summary="input an URL"/>
+ <entry name="email" value="6" summary="input an email address"/>
+ <entry name="name" value="7" summary="input a name of a person"/>
+ <entry name="password" value="8" summary="input a password (combine with sensitive_data hint)"/>
+ <entry name="pin" value="9" summary="input is a numeric password (combine with sensitive_data hint)"/>
+ <entry name="date" value="10" summary="input a date"/>
+ <entry name="time" value="11" summary="input a time"/>
+ <entry name="datetime" value="12" summary="input a date and time"/>
+ <entry name="terminal" value="13" summary="input for a terminal"/>
+ </enum>
+
+ <request name="set_content_type">
+ <description summary="set content purpose and hint">
+ Sets the content purpose and content hint. While the purpose is the
+ basic purpose of an input field, the hint flags allow to modify some of
+ the behavior.
+
+ Values set with this request are double-buffered. They will get applied
+ on the next zwp_text_input_v3.commit request.
+ Subsequent attempts to update them may have no effect. The values
+ remain valid until the next committed enable or disable request.
+
+ The initial value for hint is none, and the initial value for purpose
+ is normal.
+ </description>
+ <arg name="hint" type="uint" enum="content_hint"/>
+ <arg name="purpose" type="uint" enum="content_purpose"/>
+ </request>
+
+ <request name="set_cursor_rectangle">
+ <description summary="set cursor position">
+ Marks an area around the cursor as a x, y, width, height rectangle in
+ surface local coordinates.
+
+ Allows the compositor to put a window with word suggestions near the
+ cursor, without obstructing the text being input.
+
+ If the client is unaware of the position of edited text, it should not
+ issue this request, to signify lack of support to the compositor.
+
+ Values set with this request are double-buffered. They will get applied
+ on the next zwp_text_input_v3.commit request, and stay valid until the
+ next committed enable or disable request.
+
+ The initial values describing a cursor rectangle are empty. That means
+ the text input does not support describing the cursor area. If the
+ empty values get applied, subsequent attempts to change them may have
+ no effect.
+ </description>
+ <arg name="x" type="int"/>
+ <arg name="y" type="int"/>
+ <arg name="width" type="int"/>
+ <arg name="height" type="int"/>
+ </request>
+
+ <request name="commit">
+ <description summary="commit state">
+ Atomically applies state changes recently sent to the compositor.
+
+ The commit request establishes and updates the state of the client, and
+ must be issued after any changes to apply them.
+
+ Text input state (enabled status, content purpose, content hint,
+ surrounding text and change cause, cursor rectangle) is conceptually
+ double-buffered within the context of a text input, i.e. between a
+ committed enable request and the following committed enable or disable
+ request.
+
+ Protocol requests modify the pending state, as opposed to the current
+ state in use by the input method. A commit request atomically applies
+ all pending state, replacing the current state. After commit, the new
+ pending state is as documented for each related request.
+
+ Requests are applied in the order of arrival.
+
+ Neither current nor pending state are modified unless noted otherwise.
+
+ The compositor must count the number of commit requests coming from
+ each zwp_text_input_v3 object and use the count as the serial in done
+ events.
+ </description>
+ </request>
+
+ <event name="enter">
+ <description summary="enter event">
+ Notification that this seat's text-input focus is on a certain surface.
(Patch may be truncated, please check the link at the top of this post.)