diff --git a/deps/wayland/text-input-unstable-v1.xml b/deps/wayland/text-input-unstable-v1.xml
new file mode 100644
index 00000000..6ee26652
--- /dev/null
+++ b/deps/wayland/text-input-unstable-v1.xml
@@ -0,0 +1,385 @@
+
+
+
+
+ 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.
+
+
+
+
+ An object used for text input. Adds support for text input and input
+ methods to applications. A text_input object is created from a
+ wl_text_input_manager and corresponds typically to a text entry in an
+ application.
+
+ Requests are used to activate/deactivate the text_input object and set
+ state information like surrounding and selected text or the content type.
+ The information about entered text is sent to the text_input object via
+ the pre-edit and commit events. Using this interface removes the need
+ for applications to directly process hardware key events and compose text
+ out of them.
+
+ Text is generally UTF-8 encoded, indices and lengths are in bytes.
+
+ Serials are used to synchronize the state between the text input and
+ an input method. New serials are sent by the text input in the
+ commit_state request and are used by the input method to indicate
+ the known text input state in events like preedit_string, commit_string,
+ and keysym. The text input can then ignore events from the input method
+ which are based on an outdated state (for example after a reset).
+
+ 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.
+
+
+
+
+ Requests the text_input object to be activated (typically when the
+ text entry gets focus).
+
+ The seat argument is a wl_seat which maintains the focus for this
+ activation. The surface argument is a wl_surface assigned to the
+ text_input object and tracked for focus lost. The enter event
+ is emitted on successful activation.
+
+
+
+
+
+
+
+ Requests the text_input object to be deactivated (typically when the
+ text entry lost focus). The seat argument is a wl_seat which was used
+ for activation.
+
+
+
+
+
+
+ Requests input panels (virtual keyboard) to show.
+
+
+
+
+
+ Requests input panels (virtual keyboard) to hide.
+
+
+
+
+
+ Should be called by an editor widget when the input state should be
+ reset, for example after the text was changed outside of the normal
+ input method flow.
+
+
+
+
+
+ Sets the plain surrounding text around the input position. Text is
+ UTF-8 encoded. Cursor is the byte offset within the
+ surrounding text. Anchor is the byte offset of the
+ selection anchor within the surrounding text. If there is no selected
+ text anchor, then it is the same as cursor.
+
+
+
+
+
+
+
+
+ Content hint is a bitmask to allow to modify the behavior of the text
+ input.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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.
+
+ When no content type is explicitly set, a normal content purpose with
+ default hints (auto completion, auto correction, auto capitalization)
+ should be assumed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sets a specific language. This allows for example a virtual keyboard to
+ show a language specific layout. The "language" argument is an RFC-3066
+ format language tag.
+
+ It could be used for example in a word processor to indicate the
+ language of the currently edited document or in an instant message
+ application which tracks languages of contacts.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Notify the text_input object when it received focus. Typically in
+ response to an activate request.
+
+
+
+
+
+
+ Notify the text_input object when it lost focus. Either in response
+ to a deactivate request or when the assigned surface lost focus or was
+ destroyed.
+
+
+
+
+
+ Transfer an array of 0-terminated modifier names. The position in
+ the array is the index of the modifier as used in the modifiers
+ bitmask in the keysym event.
+
+
+
+
+
+
+ Notify when the visibility state of the input panel changed.
+
+
+
+
+
+
+ Notify when a new composing text (pre-edit) should be set around the
+ current cursor position. Any previously set composing text should
+ be removed.
+
+ The commit text can be used to replace the preedit text on reset
+ (for example on unfocus).
+
+ The text input should also handle all preedit_style and preedit_cursor
+ events occurring directly before preedit_string.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sets styling information on composing text. The style is applied for
+ length bytes from index relative to the beginning of the composing
+ text (as byte offset). Multiple styles can
+ be applied to a composing text by sending multiple preedit_styling
+ events.
+
+ This event is handled as part of a following preedit_string event.
+
+
+
+
+
+
+
+
+ Sets the cursor position inside the composing text (as byte
+ offset) relative to the start of the composing text. When index is a
+ negative number no cursor is shown.
+
+ This event is handled as part of a following preedit_string event.
+
+
+
+
+
+
+ Notify when text should be inserted into the editor widget. The text to
+ commit could be either just a single character after a key press or the
+ result of some composing (pre-edit). It could also be an empty text
+ when some text should be removed (see delete_surrounding_text) or when
+ the input cursor should be moved (see cursor_position).
+
+ Any previously set composing text should be removed.
+
+
+
+
+
+
+
+ Notify when the cursor or anchor position should be modified.
+
+ This event should be handled as part of a following commit_string
+ event.
+
+
+
+
+
+
+
+ Notify when the text around the current cursor position should be
+ deleted.
+
+ Index is relative to the current cursor (in bytes).
+ Length is the length of deleted text (in bytes).
+
+ This event should be handled as part of a following commit_string
+ event.
+
+
+
+
+
+
+
+ Notify when a key event was sent. Key events should not be used
+ for normal text input operations, which should be done with
+ commit_string, delete_surrounding_text, etc. The key event follows
+ the wl_keyboard key event convention. Sym is an XKB keysym, state a
+ wl_keyboard key_state. Modifiers are a mask for effective modifiers
+ (where the modifier indices are set by the modifiers_map event)
+
+
+
+
+
+
+
+
+
+
+ Sets the language of the input text. The "language" argument is an
+ RFC-3066 format language tag.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sets the text direction of input text.
+
+ It is mainly needed for showing an input cursor on the correct side of
+ the editor when there is no input done yet and making sure neutral
+ direction text is laid out properly.
+
+
+
+
+
+
+
+
+ A factory for text_input objects. This object is a global singleton.
+
+
+
+
+ Creates a new text_input object.
+
+
+
+
+
+
diff --git a/deps/wayland/text-input-unstable-v3.xml b/deps/wayland/text-input-unstable-v3.xml
new file mode 100644
index 00000000..1fae54d7
--- /dev/null
+++ b/deps/wayland/text-input-unstable-v3.xml
@@ -0,0 +1,457 @@
+
+
+
+
+ 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.
+
+
+
+ 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.
+
+
+
+
+ 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.
+
+
+
+
+ Destroy the wp_text_input object. Also disables all surfaces enabled
+ through this wp_text_input object.
+
+
+
+
+
+ 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.
+
+
+
+
+
+ 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.
+
+
+
+
+
+ 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.
+
+
+
+
+
+
+
+
+ Reason for the change of surrounding text or cursor posision.
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+
+ Content hint is a bitmask to allow to modify the behavior of the text
+ input.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+ Notification that this seat's text-input focus is on a certain surface.
+
+ If client has created multiple text input objects, compositor must send
+ this event to all of them.
+
+ When the seat has the keyboard capability the text-input focus follows
+ the keyboard focus. This event sets the current surface for the
+ text-input object.
+
+
+
+
+
+
+ Notification that this seat's text-input focus is no longer on a
+ certain surface. The client should reset any preedit string previously
+ set.
+
+ The leave notification clears the current surface. It is sent before
+ the enter notification for the new focus. After leave event, compositor
+ must ignore requests from any text input instances until next enter
+ event.
+
+ When the seat has the keyboard capability the text-input focus follows
+ the keyboard focus.
+
+
+
+
+
+
+ Notify when a new composing text (pre-edit) should be set at the
+ current cursor position. Any previously set composing text must be
+ removed. Any previously existing selected text must be removed.
+
+ The argument text contains the pre-edit string buffer.
+
+ The parameters cursor_begin and cursor_end are counted in bytes
+ relative to the beginning of the submitted text buffer. Cursor should
+ be hidden when both are equal to -1.
+
+ They could be represented by the client as a line if both values are
+ the same, or as a text highlight otherwise.
+
+ Values set with this event are double-buffered. They must be applied
+ and reset to initial on the next zwp_text_input_v3.done event.
+
+ The initial value of text is an empty string, and cursor_begin,
+ cursor_end and cursor_hidden are all 0.
+
+
+
+
+
+
+
+
+ Notify when text should be inserted into the editor widget. The text to
+ commit could be either just a single character after a key press or the
+ result of some composing (pre-edit).
+
+ Values set with this event are double-buffered. They must be applied
+ and reset to initial on the next zwp_text_input_v3.done event.
+
+ The initial value of text is an empty string.
+
+
+
+
+
+
+ Notify when the text around the current cursor position should be
+ deleted.
+
+ Before_length and after_length are the number of bytes before and after
+ the current cursor index (excluding the selection) to delete.
+
+ If a preedit text is present, in effect before_length is counted from
+ the beginning of it, and after_length from its end (see done event
+ sequence).
+
+ Values set with this event are double-buffered. They must be applied
+ and reset to initial on the next zwp_text_input_v3.done event.
+
+ The initial values of both before_length and after_length are 0.
+
+
+
+
+
+
+
+ Instruct the application to apply changes to state requested by the
+ preedit_string, commit_string and delete_surrounding_text events. The
+ state relating to these events is double-buffered, and each one
+ modifies the pending state. This event replaces the current state with
+ the pending state.
+
+ The application must proceed by evaluating the changes in the following
+ order:
+
+ 1. Replace existing preedit string with the cursor.
+ 2. Delete requested surrounding text.
+ 3. Insert commit string with the cursor at its end.
+ 4. Calculate surrounding text to send.
+ 5. Insert new preedit text in cursor position.
+ 6. Place cursor inside preedit text.
+
+ The serial number reflects the last state of the zwp_text_input_v3
+ object known to the compositor. The value of the serial argument must
+ be equal to the number of commit requests already issued on that object.
+
+ When the client receives a done event with a serial different than the
+ number of past commit requests, it must proceed with evaluating and
+ applying the changes as normal, except it should not change the current
+ state of the zwp_text_input_v3 object. All pending state requests
+ (set_surrounding_text, set_content_type and set_cursor_rectangle) on
+ the zwp_text_input_v3 object should be sent and committed after
+ receiving a zwp_text_input_v3.done event with a matching serial.
+
+
+
+
+
+
+
+ A factory for text-input objects. This object is a global singleton.
+
+
+
+
+ Destroy the wp_text_input_manager object.
+
+
+
+
+
+ Creates a new text-input object for a given seat.
+
+
+
+
+
+
diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h
index 496bc017..3c4879ac 100644
--- a/include/GLFW/glfw3.h
+++ b/include/GLFW/glfw3.h
@@ -5257,6 +5257,8 @@ GLFWAPI void glfwSetPreeditCursorRectangle(GLFWwindow* window, int x, int y, int
* @remark @x11 Since over-the-spot style is used by default, you don't need
* to use this function.
*
+ * @remark @wayland This function is currently not supported.
+ *
* @par Thread Safety
* This function may only be called from the main thread.
*
@@ -5463,7 +5465,7 @@ GLFWAPI GLFWpreeditfun glfwSetPreeditCallback(GLFWwindow* window, GLFWpreeditfun
* For more information about the callback parameters, see the
* [function pointer type](@ref GLFWimestatusfun).
*
- * @remark @x11 Don't support this function. The callback is not called.
+ * @remark @x11 @wayland Don't support this function. The callback is not called.
*
* @par Thread Safety
* This function may only be called from the main thread.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1057a6f9..373c4b43 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -104,6 +104,8 @@ if (GLFW_BUILD_WAYLAND)
generate_wayland_protocol("fractional-scale-v1.xml")
generate_wayland_protocol("xdg-activation-v1.xml")
generate_wayland_protocol("xdg-decoration-unstable-v1.xml")
+ generate_wayland_protocol("text-input-unstable-v1.xml")
+ generate_wayland_protocol("text-input-unstable-v3.xml")
endif()
if (WIN32 AND GLFW_BUILD_SHARED_LIBRARY)
diff --git a/src/wl_init.c b/src/wl_init.c
index fce71039..5edb36a2 100644
--- a/src/wl_init.c
+++ b/src/wl_init.c
@@ -49,6 +49,8 @@
#include "fractional-scale-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
+#include "text-input-unstable-v1-client-protocol.h"
+#include "text-input-unstable-v3-client-protocol.h"
// NOTE: Versions of wayland-scanner prior to 1.17.91 named every global array of
// wl_interface pointers 'types', making it impossible to combine several unmodified
@@ -91,6 +93,14 @@
#include "idle-inhibit-unstable-v1-client-protocol-code.h"
#undef types
+#define types _glfw_text_input_v1_types
+#include "text-input-unstable-v1-client-protocol-code.h"
+#undef types
+
+#define types _glfw_text_input_v3_types
+#include "text-input-unstable-v3-client-protocol-code.h"
+#undef types
+
static void wmBaseHandlePing(void* userData,
struct xdg_wm_base* wmBase,
uint32_t serial)
@@ -208,6 +218,20 @@ static void registryHandleGlobal(void* userData,
&wp_fractional_scale_manager_v1_interface,
1);
}
+ else if (strcmp(interface, "zwp_text_input_manager_v1") == 0)
+ {
+ _glfw.wl.textInputManagerV1 =
+ wl_registry_bind(registry, name,
+ &zwp_text_input_manager_v1_interface,
+ 1);
+ }
+ else if (strcmp(interface, "zwp_text_input_manager_v3") == 0)
+ {
+ _glfw.wl.textInputManagerV3 =
+ wl_registry_bind(registry, name,
+ &zwp_text_input_manager_v3_interface,
+ 1);
+ }
}
static void registryHandleGlobalRemove(void* userData,
@@ -988,6 +1012,10 @@ void _glfwTerminateWayland(void)
xdg_activation_v1_destroy(_glfw.wl.activationManager);
if (_glfw.wl.fractionalScaleManager)
wp_fractional_scale_manager_v1_destroy(_glfw.wl.fractionalScaleManager);
+ if (_glfw.wl.textInputManagerV1)
+ zwp_text_input_manager_v1_destroy(_glfw.wl.textInputManagerV1);
+ if (_glfw.wl.textInputManagerV3)
+ zwp_text_input_manager_v3_destroy(_glfw.wl.textInputManagerV3);
if (_glfw.wl.registry)
wl_registry_destroy(_glfw.wl.registry);
if (_glfw.wl.display)
diff --git a/src/wl_platform.h b/src/wl_platform.h
index 1023510f..4372ce8f 100644
--- a/src/wl_platform.h
+++ b/src/wl_platform.h
@@ -411,6 +411,13 @@ typedef struct _GLFWwindowWayland
_GLFWfallbackEdgeWayland top, left, right, bottom;
struct wl_surface* focus;
} fallback;
+
+ struct zwp_text_input_v1* textInputV1;
+ struct zwp_text_input_v3* textInputV3;
+ struct {
+ char* preeditText;
+ char* commitTextOnReset;
+ } textInputV1Context;
} _GLFWwindowWayland;
// Wayland-specific global data
@@ -435,6 +442,8 @@ typedef struct _GLFWlibraryWayland
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
struct xdg_activation_v1* activationManager;
struct wp_fractional_scale_manager_v1* fractionalScaleManager;
+ struct zwp_text_input_manager_v1* textInputManagerV1;
+ struct zwp_text_input_manager_v3* textInputManagerV3;
_GLFWofferWayland* offers;
unsigned int offerCount;
diff --git a/src/wl_window.c b/src/wl_window.c
index e3926e50..cf348bfe 100644
--- a/src/wl_window.c
+++ b/src/wl_window.c
@@ -51,6 +51,8 @@
#include "xdg-activation-v1-client-protocol.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "fractional-scale-v1-client-protocol.h"
+#include "text-input-unstable-v1-client-protocol.h"
+#include "text-input-unstable-v3-client-protocol.h"
#define GLFW_BORDER_SIZE 4
#define GLFW_CAPTION_HEIGHT 24
@@ -555,6 +557,22 @@ const struct wp_fractional_scale_v1_listener fractionalScaleListener =
fractionalScaleHandlePreferredScale,
};
+static void activateTextInputV1(_GLFWwindow* window)
+{
+ if (!window->wl.textInputV1)
+ return;
+ zwp_text_input_v1_show_input_panel(window->wl.textInputV1);
+ zwp_text_input_v1_activate(window->wl.textInputV1, _glfw.wl.seat, window->wl.surface);
+}
+
+static void deactivateTextInputV1(_GLFWwindow* window)
+{
+ if (!window->wl.textInputV1)
+ return;
+ zwp_text_input_v1_hide_input_panel(window->wl.textInputV1);
+ zwp_text_input_v1_deactivate(window->wl.textInputV1, _glfw.wl.seat);
+}
+
static void xdgToplevelHandleConfigure(void* userData,
struct xdg_toplevel* toplevel,
int32_t width,
@@ -582,6 +600,7 @@ static void xdgToplevelHandleConfigure(void* userData,
break;
case XDG_TOPLEVEL_STATE_ACTIVATED:
window->wl.pending.activated = GLFW_TRUE;
+ activateTextInputV1(window);
break;
}
}
@@ -1538,6 +1557,11 @@ static void pointerHandleButton(void* userData,
if (!window)
return;
+ // On weston, pressing the title bar will cause leave event and never emit
+ // enter event even though back to content area by pressing mouse button
+ // just after it. So activate it here explicitly.
+ activateTextInputV1(window);
+
if (window->wl.hovered)
{
_glfw.wl.serial = serial;
@@ -2118,6 +2142,379 @@ void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device)
wl_data_device_add_listener(device, &dataDeviceListener, NULL);
}
+// Callbacks for text_input_unstable_v3 protocol.
+//
+// This protocol is widely supported by major desktop environments such as GNOME
+// or KDE.
+//
+static void textInputV3Enter(void* data,
+ struct zwp_text_input_v3* textInputV3,
+ struct wl_surface* surface)
+{
+ zwp_text_input_v3_enable(textInputV3);
+ zwp_text_input_v3_commit(textInputV3);
+}
+
+static void textInputV3Reset(_GLFWwindow* window)
+{
+ _GLFWpreedit* preedit = &window->preedit;
+
+ preedit->textCount = 0;
+ preedit->blockSizesCount = 0;
+ preedit->focusedBlockIndex = 0;
+ preedit->caretIndex = 0;
+
+ _glfwInputPreedit(window);
+}
+
+static void textInputV3Leave(void* data,
+ struct zwp_text_input_v3* textInputV3,
+ struct wl_surface* surface)
+{
+ _GLFWwindow* window = (_GLFWwindow*) data;
+ zwp_text_input_v3_disable(textInputV3);
+ zwp_text_input_v3_commit(textInputV3);
+
+ // Although this should be handled by IM via preedit callback, it seems that
+ // the behavior varies depending on implemention. It's cleared by IM on
+ // Ubuntu 22.04 but not cleared on Ubuntu 20.04.
+ textInputV3Reset(window);
+}
+
+static void textInputV3PreeditString(void* data,
+ struct zwp_text_input_v3* textInputV3,
+ const char* text,
+ int32_t cursorBegin,
+ int32_t cursorEnd)
+{
+ _GLFWwindow* window = (_GLFWwindow*) data;
+ _GLFWpreedit* preedit = &window->preedit;
+ const char* cur = text;
+ unsigned int cursorLength = 0;
+
+ preedit->textCount = 0;
+ preedit->blockSizesCount = 0;
+ preedit->focusedBlockIndex = 0;
+ preedit->caretIndex = 0;
+
+ // Store preedit text
+ while (cur && *cur)
+ {
+ uint32_t codepoint = _glfwDecodeUTF8(&cur);
+
+ ++preedit->textCount;
+
+ if (cur == text + cursorBegin)
+ preedit->caretIndex = preedit->textCount;
+ if (cursorBegin != cursorEnd && cur == text + cursorEnd)
+ cursorLength = preedit->textCount - cursorBegin;
+
+ if (preedit->textBufferCount < preedit->textCount + 1)
+ {
+ int bufSize = preedit->textBufferCount;
+
+ while (bufSize < preedit->textCount + 1)
+ bufSize = (bufSize == 0) ? 1 : bufSize * 2;
+ preedit->text = _glfw_realloc(preedit->text,
+ sizeof(unsigned int) * bufSize);
+ if (!preedit->text)
+ return;
+ preedit->textBufferCount = bufSize;
+ }
+ preedit->text[preedit->textCount - 1] = codepoint;
+ }
+ if (preedit->text)
+ preedit->text[preedit->textCount] = 0;
+
+ // Store preedit blocks
+ if (preedit->textCount)
+ {
+ int* blocks = preedit->blockSizes;
+ int blockCount = preedit->blockSizesCount;
+ int cursorPos = preedit->caretIndex;
+ int textCount = preedit->textCount;
+
+ if (!preedit->blockSizes)
+ {
+ int bufSize = 3;
+
+ preedit->blockSizesBufferCount = bufSize;
+ preedit->blockSizes = _glfw_calloc(sizeof(int), bufSize);
+ if (!preedit->blockSizes)
+ return;
+ blocks = preedit->blockSizes;
+ }
+
+ if (cursorLength && cursorPos)
+ blocks[blockCount++] = cursorPos;
+
+ preedit->focusedBlockIndex = blockCount;
+ blocks[blockCount++] = cursorLength ? cursorLength : textCount;
+
+ if (cursorLength && cursorPos + cursorLength != textCount)
+ blocks[blockCount++] = textCount - cursorPos - cursorLength;
+
+ preedit->blockSizesCount = blockCount;
+ }
+}
+
+static void textInputV3CommitString(void* data,
+ struct zwp_text_input_v3* textInputV3,
+ const char* text)
+{
+ _GLFWwindow* window = (_GLFWwindow*) data;
+ const char* cur = text;
+
+ if (!window->callbacks.character)
+ return;
+
+ while (cur && *cur)
+ {
+ uint32_t codepoint = _glfwDecodeUTF8(&cur);
+ window->callbacks.character((GLFWwindow*) window, codepoint);
+ }
+}
+
+static void textInputV3DeleteSurroundingText(void* data,
+ struct zwp_text_input_v3* textInputV3,
+ uint32_t beforeLength,
+ uint32_t afterLength)
+{
+}
+
+static void textInputV3Done(void* data,
+ struct zwp_text_input_v3* textInputV3,
+ uint32_t serial)
+{
+ _GLFWwindow* window = (_GLFWwindow*) data;
+ _glfwUpdatePreeditCursorRectangleWayland(window);
+ _glfwInputPreedit(window);
+}
+
+static const struct zwp_text_input_v3_listener textInputV3Listener =
+{
+ textInputV3Enter,
+ textInputV3Leave,
+ textInputV3PreeditString,
+ textInputV3CommitString,
+ textInputV3DeleteSurroundingText,
+ textInputV3Done
+};
+
+// Callbacks for text_input_unstable_v1 protocol
+//
+// This protocol isn't so popular but Weston which is the reference Wayland
+// implementation supports only this protocol and doesn't support
+// text_input_unstable_v3.
+//
+static void textInputV1Enter(void* data,
+ struct zwp_text_input_v1* textInputV1,
+ struct wl_surface* surface)
+{
+ _GLFWwindow* window = (_GLFWwindow*) data;
+ activateTextInputV1(window);
+}
+
+static void textInputV1Reset(_GLFWwindow* window)
+{
+ _GLFWpreedit* preedit = &window->preedit;
+
+ preedit->textCount = 0;
+ preedit->blockSizesCount = 0;
+ preedit->focusedBlockIndex = 0;
+ preedit->caretIndex = 0;
+
+ _glfw_free(window->wl.textInputV1Context.preeditText);
+ _glfw_free(window->wl.textInputV1Context.commitTextOnReset);
+ window->wl.textInputV1Context.preeditText = NULL;
+ window->wl.textInputV1Context.commitTextOnReset = NULL;
+
+ _glfwInputPreedit(window);
+}
+
+static void textInputV1Leave(void* data,
+ struct zwp_text_input_v1* textInputV1)
+{
+ _GLFWwindow* window = (_GLFWwindow*) data;
+ char* commitText = window->wl.textInputV1Context.commitTextOnReset;
+
+ textInputV3CommitString(data, NULL, commitText);
+ textInputV1Reset(window);
+ deactivateTextInputV1(window);
+}
+
+static void textInputV1ModifiersMap(void* data,
+ struct zwp_text_input_v1* textInputV1,
+ struct wl_array* map)
+{
+}
+
+static void textInputV1InputPanelState(void* data,
+ struct zwp_text_input_v1* textInputV1,
+ uint32_t state)
+{
+}
+
+static void textInputV1PreeditString(void* data,
+ struct zwp_text_input_v1* textInputV1,
+ uint32_t serial,
+ const char* text,
+ const char* commit)
+{
+ _GLFWwindow* window = (_GLFWwindow*) data;
+
+ _glfw_free(window->wl.textInputV1Context.preeditText);
+ _glfw_free(window->wl.textInputV1Context.commitTextOnReset);
+ window->wl.textInputV1Context.preeditText = strdup(text);
+ window->wl.textInputV1Context.commitTextOnReset = strdup(commit);
+
+ textInputV3PreeditString(data, NULL, text, 0, 0);
+ _glfwInputPreedit(window);
+}
+
+static void textInputV1PreeditStyling(void* data,
+ struct zwp_text_input_v1* textInputV1,
+ uint32_t index,
+ uint32_t length,
+ uint32_t style)
+{
+}
+
+static void textInputV1PreeditCursor(void* data,
+ struct zwp_text_input_v1* textInputV1,
+ int32_t index)
+{
+ _GLFWwindow* window = (_GLFWwindow*) data;
+ _GLFWpreedit* preedit = &window->preedit;
+ const char* text = window->wl.textInputV1Context.preeditText;
+ const char* cur = text;
+
+ preedit->caretIndex = 0;
+ if (index <= 0 || preedit->textCount == 0)
+ return;
+
+ while (cur && *cur)
+ {
+ _glfwDecodeUTF8(&cur);
+ ++preedit->caretIndex;
+ if (cur >= text + index)
+ break;
+ if (preedit->caretIndex > preedit->textCount)
+ break;
+ }
+}
+
+static void textInputV1CommitString(void* data,
+ struct zwp_text_input_v1* textInputV1,
+ uint32_t serial,
+ const char* text)
+{
+ _GLFWwindow* window = (_GLFWwindow*) data;
+
+ textInputV1Reset(window);
+ textInputV3CommitString(data, NULL, text);
+}
+
+static void textInputV1CursorPosition(void* data,
+ struct zwp_text_input_v1* textInputV1,
+ int32_t index,
+ int32_t anchor)
+{
+ // It's for surrounding text feature which isn't supported by GLFW.
+}
+
+static void textInputV1DeleteSurroundingText(void* data,
+ struct zwp_text_input_v1* textInputV1,
+ int32_t index,
+ uint32_t length)
+{
+}
+
+static void textInputV1Keysym(void* data,
+ struct zwp_text_input_v1* textInputV1,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t sym,
+ uint32_t state,
+ uint32_t modifiers)
+{
+ uint32_t scancode;
+
+ // This code supports only weston-keyboard because we aren't aware
+ // of any other input methods that actually support this API.
+ // Supporting all keysyms is overkill for now.
+
+ switch (sym)
+ {
+ case XKB_KEY_Left:
+ scancode = KEY_LEFT;
+ break;
+ case XKB_KEY_Right:
+ scancode = KEY_RIGHT;
+ break;
+ case XKB_KEY_Up:
+ scancode = KEY_UP;
+ break;
+ case XKB_KEY_Down:
+ scancode = KEY_DOWN;
+ break;
+ case XKB_KEY_BackSpace:
+ scancode = KEY_BACKSPACE;
+ break;
+ case XKB_KEY_Tab:
+ scancode = KEY_TAB;
+ break;
+ case XKB_KEY_KP_Enter:
+ scancode = KEY_KPENTER;
+ break;
+ case XKB_KEY_Return:
+ scancode = KEY_ENTER;
+ break;
+ default:
+ return;
+ }
+
+ _glfw.wl.xkb.modifiers = modifiers;
+
+ keyboardHandleKey(data,
+ _glfw.wl.keyboard,
+ serial,
+ time,
+ scancode,
+ state);
+}
+
+static void textInputV1Language(void* data,
+ struct zwp_text_input_v1* textInputV1,
+ uint32_t serial,
+ const char* language)
+{
+}
+
+static void textInputV1TextDirection(void* data,
+ struct zwp_text_input_v1* textInputV1,
+ uint32_t serial,
+ uint32_t direction)
+{
+}
+
+static const struct zwp_text_input_v1_listener textInputV1Listener =
+{
+ textInputV1Enter,
+ textInputV1Leave,
+ textInputV1ModifiersMap,
+ textInputV1InputPanelState,
+ textInputV1PreeditString,
+ textInputV1PreeditStyling,
+ textInputV1PreeditCursor,
+ textInputV1CommitString,
+ textInputV1CursorPosition,
+ textInputV1DeleteSurroundingText,
+ textInputV1Keysym,
+ textInputV1Language,
+ textInputV1TextDirection
+};
+
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
@@ -2172,6 +2569,21 @@ GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window,
return GLFW_FALSE;
}
+ if (_glfw.wl.textInputManagerV3)
+ {
+ window->wl.textInputV3 =
+ zwp_text_input_manager_v3_get_text_input(_glfw.wl.textInputManagerV3, _glfw.wl.seat);
+ zwp_text_input_v3_add_listener(window->wl.textInputV3,
+ &textInputV3Listener, window);
+ }
+ else if (_glfw.wl.textInputManagerV1)
+ {
+ window->wl.textInputV1 =
+ zwp_text_input_manager_v1_create_text_input(_glfw.wl.textInputManagerV1);
+ zwp_text_input_v1_add_listener(window->wl.textInputV1,
+ &textInputV1Listener, window);
+ }
+
return GLFW_TRUE;
}
@@ -2192,6 +2604,15 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window)
if (window->wl.activationToken)
xdg_activation_token_v1_destroy(window->wl.activationToken);
+ if (window->wl.textInputV1) {
+ zwp_text_input_v1_destroy(window->wl.textInputV1);
+ _glfw_free(window->wl.textInputV1Context.preeditText);
+ _glfw_free(window->wl.textInputV1Context.commitTextOnReset);
+ }
+
+ if (window->wl.textInputV3)
+ zwp_text_input_v3_destroy(window->wl.textInputV3);
+
if (window->wl.idleInhibitor)
zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor);
@@ -3197,6 +3618,19 @@ const char* _glfwGetClipboardStringWayland(void)
void _glfwUpdatePreeditCursorRectangleWayland(_GLFWwindow* window)
{
+ _GLFWpreedit* preedit = &window->preedit;
+ int x = preedit->cursorPosX;
+ int y = preedit->cursorPosY;
+ int w = preedit->cursorWidth;
+ int h = preedit->cursorHeight;
+
+ if (window->wl.textInputV3)
+ {
+ zwp_text_input_v3_set_cursor_rectangle(window->wl.textInputV3, x, y, w, h);
+ zwp_text_input_v3_commit(window->wl.textInputV3);
+ }
+ else if (window->wl.textInputV1)
+ zwp_text_input_v1_set_cursor_rectangle(window->wl.textInputV1, x, y, w, h);
}
void _glfwResetPreeditTextWayland(_GLFWwindow* window)