summaryrefslogtreecommitdiffstats
path: root/platform/linuxbsd
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r--platform/linuxbsd/export/logo.svg2
-rw-r--r--platform/linuxbsd/export/run_icon.svg2
-rw-r--r--platform/linuxbsd/tts_linux.cpp8
-rw-r--r--platform/linuxbsd/wayland/SCsub11
-rw-r--r--platform/linuxbsd/wayland/display_server_wayland.cpp50
-rw-r--r--platform/linuxbsd/wayland/display_server_wayland.h6
-rw-r--r--platform/linuxbsd/wayland/wayland_thread.cpp182
-rw-r--r--platform/linuxbsd/wayland/wayland_thread.h43
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.cpp2
9 files changed, 298 insertions, 8 deletions
diff --git a/platform/linuxbsd/export/logo.svg b/platform/linuxbsd/export/logo.svg
index e5f9f03e0c..c0d2ba1f21 100644
--- a/platform/linuxbsd/export/logo.svg
+++ b/platform/linuxbsd/export/logo.svg
@@ -1 +1 @@
-<svg height="32" width="32"><path d="M13 31h6s3 0 6-6c2.864-5.727-6-17-6-17h-6S3.775 18.55 7 25c3 6 6 6 6 6z" fill="#fff"/><path d="M15.876 28.636c-.05.322-.116.637-.204.941-.142.496-.35.993-.659 1.416.32.02.649.023.985.007a9.1 9.1 0 0 0 .985-.007c-.309-.423-.516-.92-.659-1.416a7.666 7.666 0 0 1-.203-.94l-.123.003c-.04 0-.081-.003-.122-.004z" fill="#333"/><path d="M21.693 21.916c-.629.01-.934.633-1.497.7-.694.08-1.128-.722-2.11-.123-.98.6-1.826 7.473.45 8.409 2.274.935 6.506-4.545 6.23-5.662-.275-1.116-1.146-.853-1.582-1.399-.436-.545.003-1.41-.995-1.82a1.246 1.246 0 0 0-.496-.105zm-11.461 0a1.315 1.315 0 0 0-.421.105c-.998.41-.56 1.275-.995 1.82-.436.546-1.31.283-1.586 1.4-.275 1.116 3.956 6.596 6.232 5.66 2.275-.935 1.429-7.808.448-8.408-.981-.6-1.415.204-2.11.122-.584-.068-.888-.739-1.568-.7z" fill="#f4bb37"/><path d="M15.998.99c-2.934 0-4.657 1.79-4.982 4.204-.324 2.414.198 2.856-.614 5.328-.813 2.472-4.456 6.71-4.37 10.62.026 1.217.166 2.27.41 3.192.3-.496.743-.846 1.066-.995.253-.117.375-.173.432-.194.008-.062.04-.205.098-.485.08-.386.387-.99.91-1.386-.005-.12-.01-.239-.013-.363-.06-3.033 3.073-6.318 3.65-8.236.577-1.917.326-2.114.421-2.59.096-.477.463-1.032.992-1.475a.23.23 0 0 1 .15-.06c.482-.005.965 1.75 1.898 1.752.933 0 1.419-2.141 1.956-1.692.529.443.896.998.992 1.474.095.477-.156.674.42 2.591.578 1.918 3.708 5.203 3.648 8.236-.003.123-.008.24-.014.36.526.396.834 1.002.914 1.389.058.28.09.423.098.485.057.021.18.08.432.197.323.15.764.499 1.063.995.244-.922.387-1.976.414-3.195.085-3.91-3.562-8.148-4.374-10.62-.813-2.472-.287-2.914-.611-5.328C20.659 2.78 18.933.99 15.998.99z" fill="#333"/></svg>
+<svg width="32" height="32"><path fill="#fff" d="M13 31h6s3 0 6-6c2.864-5.727-6-17-6-17h-6S3.775 18.55 7 25c3 6 6 6 6 6z"/><path fill="#333" d="M15.876 28.636c-.05.322-.116.637-.204.941-.142.496-.35.993-.659 1.416.32.02.649.023.985.007a9.1 9.1 0 0 0 .985-.007c-.309-.423-.516-.92-.659-1.416a7.666 7.666 0 0 1-.203-.94l-.123.003c-.04 0-.081-.003-.122-.004z"/><path fill="#f4bb37" d="M21.693 21.916c-.629.01-.934.633-1.497.7-.694.08-1.128-.722-2.11-.123-.98.6-1.826 7.473.45 8.409 2.274.935 6.506-4.545 6.23-5.662-.275-1.116-1.146-.853-1.582-1.399-.436-.545.003-1.41-.995-1.82a1.246 1.246 0 0 0-.496-.105zm-11.461 0a1.315 1.315 0 0 0-.421.105c-.998.41-.56 1.275-.995 1.82-.436.546-1.31.283-1.586 1.4-.275 1.116 3.956 6.596 6.232 5.66 2.275-.935 1.429-7.808.448-8.408-.981-.6-1.415.204-2.11.122-.584-.068-.888-.739-1.568-.7z"/><path fill="#333" d="M15.998.99c-2.934 0-4.657 1.79-4.982 4.204-.324 2.414.198 2.856-.614 5.328-.813 2.472-4.456 6.71-4.37 10.62.026 1.217.166 2.27.41 3.192.3-.496.743-.846 1.066-.995.253-.117.375-.173.432-.194.008-.062.04-.205.098-.485.08-.386.387-.99.91-1.386-.005-.12-.01-.239-.013-.363-.06-3.033 3.073-6.318 3.65-8.236.577-1.917.326-2.114.421-2.59.096-.477.463-1.032.992-1.475a.23.23 0 0 1 .15-.06c.482-.005.965 1.75 1.898 1.752.933 0 1.419-2.141 1.956-1.692.529.443.896.998.992 1.474.095.477-.156.674.42 2.591.578 1.918 3.708 5.203 3.648 8.236-.003.123-.008.24-.014.36.526.396.834 1.002.914 1.389.058.28.09.423.098.485.057.021.18.08.432.197.323.15.764.499 1.063.995.244-.922.387-1.976.414-3.195.085-3.91-3.562-8.148-4.374-10.62-.813-2.472-.287-2.914-.611-5.328C20.659 2.78 18.933.99 15.998.99z"/></svg> \ No newline at end of file
diff --git a/platform/linuxbsd/export/run_icon.svg b/platform/linuxbsd/export/run_icon.svg
index ad58bcd5c7..c7a2d6b0be 100644
--- a/platform/linuxbsd/export/run_icon.svg
+++ b/platform/linuxbsd/export/run_icon.svg
@@ -1 +1 @@
-<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="M7.941 13.966a3.62 3.62 0 0 1-.096.444 2.129 2.129 0 0 1-.31.668c.15.01.305.01.464.003.16.008.314.007.465-.003a2.129 2.129 0 0 1-.31-.668 3.62 3.62 0 0 1-.097-.444zM8 .914c-1.386 0-2.2.845-2.353 1.985-.153 1.14.094 1.348-.29 2.515s-2.103 3.168-2.063 5.013c.012.575.078 1.072.194 1.507a1.25 1.25 0 0 1 .503-.47 4.37 4.37 0 0 1 .204-.09c.004-.03.019-.098.046-.23.038-.182.183-.467.43-.654a4.773 4.773 0 0 1-.006-.172c-.029-1.431 1.45-2.982 1.723-3.888.272-.905.154-.998.199-1.223.045-.225.218-.487.468-.696.253-.211.483.798.945.799.462 0 .692-1.01.945-.799.25.21.423.471.468.696.045.225-.073.318.199 1.223.272.906 1.75 2.457 1.722 3.888a4.773 4.773 0 0 0-.007.17 1.2 1.2 0 0 1 .432.656c.027.132.042.2.046.23.027.01.085.037.204.092.153.07.36.236.502.47.115-.435.183-.933.195-1.509.04-1.845-1.681-3.846-2.065-5.013-.383-1.167-.135-1.376-.288-2.515C10.2 1.759 9.385.914 7.999.914z" fill="#333" style="fill:#e0e0e0;fill-opacity:1"/><path d="M10.688 10.793c-.297.005-.441.299-.707.33-.328.038-.533-.34-.996-.058-.463.283-.862 3.528.212 3.97 1.074.442 3.072-2.146 2.942-2.673-.13-.527-.542-.403-.747-.66-.206-.258 0-.666-.47-.86a.588.588 0 0 0-.234-.05zm-5.411 0a.62.62 0 0 0-.199.05c-.47.193-.264.601-.47.859-.205.257-.618.133-.748.66s1.867 3.115 2.942 2.673c1.074-.442.674-3.687.211-3.97-.463-.283-.668.096-.995.058-.277-.032-.42-.349-.741-.33z" fill="#f4bb37" style="fill:#e0e0e0;fill-opacity:1"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16"><path fill="#e0e0e0" d="M7.941 13.966a3.62 3.62 0 0 1-.096.444 2.129 2.129 0 0 1-.31.668c.15.01.305.01.464.003.16.008.314.007.465-.003a2.129 2.129 0 0 1-.31-.668 3.62 3.62 0 0 1-.097-.444zM8 .914c-1.386 0-2.2.845-2.353 1.985-.153 1.14.094 1.348-.29 2.515s-2.103 3.168-2.063 5.013c.012.575.078 1.072.194 1.507a1.25 1.25 0 0 1 .503-.47 4.37 4.37 0 0 1 .204-.09c.004-.03.019-.098.046-.23.038-.182.183-.467.43-.654a4.773 4.773 0 0 1-.006-.172c-.029-1.431 1.45-2.982 1.723-3.888.272-.905.154-.998.199-1.223.045-.225.218-.487.468-.696.253-.211.483.798.945.799.462 0 .692-1.01.945-.799.25.21.423.471.468.696.045.225-.073.318.199 1.223.272.906 1.75 2.457 1.722 3.888a4.773 4.773 0 0 0-.007.17 1.2 1.2 0 0 1 .432.656c.027.132.042.2.046.23.027.01.085.037.204.092.153.07.36.236.502.47.115-.435.183-.933.195-1.509.04-1.845-1.681-3.846-2.065-5.013-.383-1.167-.135-1.376-.288-2.515C10.2 1.759 9.385.914 7.999.914z"/><path fill="#e0e0e0" d="M10.688 10.793c-.297.005-.441.299-.707.33-.328.038-.533-.34-.996-.058-.463.283-.862 3.528.212 3.97 1.074.442 3.072-2.146 2.942-2.673-.13-.527-.542-.403-.747-.66-.206-.258 0-.666-.47-.86a.588.588 0 0 0-.234-.05zm-5.411 0a.62.62 0 0 0-.199.05c-.47.193-.264.601-.47.859-.205.257-.618.133-.748.66s1.867 3.115 2.942 2.673c1.074-.442.674-3.687.211-3.97-.463-.283-.668.096-.995.058-.277-.032-.42-.349-.741-.33z"/></svg> \ No newline at end of file
diff --git a/platform/linuxbsd/tts_linux.cpp b/platform/linuxbsd/tts_linux.cpp
index 46291bb4da..6c1f49f046 100644
--- a/platform/linuxbsd/tts_linux.cpp
+++ b/platform/linuxbsd/tts_linux.cpp
@@ -149,12 +149,18 @@ void TTS_Linux::_speech_event(int p_msg_id, int p_type) {
}
PackedInt32Array breaks = TS->string_get_word_breaks(message.text, language);
+ int prev_end = -1;
for (int i = 0; i < breaks.size(); i += 2) {
const int start = breaks[i];
const int end = breaks[i + 1];
- text += message.text.substr(start, end - start + 1);
+ if (prev_end != -1 && prev_end != start) {
+ text += message.text.substr(prev_end, start - prev_end);
+ }
+ text += message.text.substr(start, end - start);
text += "<mark name=\"" + String::num_int64(end, 10) + "\"/>";
+ prev_end = end;
}
+
spd_set_synthesis_voice(synth, message.voice.utf8().get_data());
spd_set_volume(synth, message.volume * 2 - 100);
spd_set_voice_pitch(synth, (message.pitch - 1) * 100);
diff --git a/platform/linuxbsd/wayland/SCsub b/platform/linuxbsd/wayland/SCsub
index add5bdb504..89b586845c 100644
--- a/platform/linuxbsd/wayland/SCsub
+++ b/platform/linuxbsd/wayland/SCsub
@@ -152,6 +152,16 @@ env.WAYLAND_API_CODE(
)
env.WAYLAND_API_HEADER(
+ target="protocol/text_input.gen.h",
+ source="#thirdparty/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml",
+)
+
+env.WAYLAND_API_CODE(
+ target="protocol/text_input.gen.c",
+ source="#thirdparty/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml",
+)
+
+env.WAYLAND_API_HEADER(
target="protocol/xdg_foreign.gen.h",
source="#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml",
)
@@ -175,6 +185,7 @@ source_files = [
"protocol/primary_selection.gen.c",
"protocol/idle_inhibit.gen.c",
"protocol/tablet.gen.c",
+ "protocol/text_input.gen.c",
"display_server_wayland.cpp",
"wayland_thread.cpp",
"key_mapping_xkb.cpp",
diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp
index c231dc0f90..3fad8c2987 100644
--- a/platform/linuxbsd/wayland/display_server_wayland.cpp
+++ b/platform/linuxbsd/wayland/display_server_wayland.cpp
@@ -208,6 +208,7 @@ bool DisplayServerWayland::has_feature(Feature p_feature) const {
case FEATURE_HIDPI:
case FEATURE_SWAP_BUFFERS:
case FEATURE_KEEP_SCREEN_ON:
+ case FEATURE_IME:
case FEATURE_CLIPBOARD_PRIMARY: {
return true;
} break;
@@ -903,13 +904,23 @@ bool DisplayServerWayland::can_any_window_draw() const {
}
void DisplayServerWayland::window_set_ime_active(const bool p_active, DisplayServer::WindowID p_window_id) {
- // TODO
- DEBUG_LOG_WAYLAND(vformat("wayland stub window_set_ime_active active %s", p_active ? "true" : "false"));
+ MutexLock mutex_lock(wayland_thread.mutex);
+
+ wayland_thread.window_set_ime_active(p_active, MAIN_WINDOW_ID);
}
void DisplayServerWayland::window_set_ime_position(const Point2i &p_pos, DisplayServer::WindowID p_window_id) {
- // TODO
- DEBUG_LOG_WAYLAND(vformat("wayland stub window_set_ime_position pos %s window %d", p_pos, p_window_id));
+ MutexLock mutex_lock(wayland_thread.mutex);
+
+ wayland_thread.window_set_ime_position(p_pos, MAIN_WINDOW_ID);
+}
+
+Point2i DisplayServerWayland::ime_get_selection() const {
+ return ime_selection;
+}
+
+String DisplayServerWayland::ime_get_text() const {
+ return ime_text;
}
// NOTE: While Wayland is supposed to be tear-free, wayland-protocols version
@@ -1146,6 +1157,37 @@ void DisplayServerWayland::process_events() {
}
}
}
+
+ Ref<WaylandThread::IMECommitEventMessage> ime_commit_msg = msg;
+ if (ime_commit_msg.is_valid()) {
+ for (int i = 0; i < ime_commit_msg->text.length(); i++) {
+ const char32_t codepoint = ime_commit_msg->text[i];
+
+ Ref<InputEventKey> ke;
+ ke.instantiate();
+ ke->set_window_id(MAIN_WINDOW_ID);
+ ke->set_pressed(true);
+ ke->set_echo(false);
+ ke->set_keycode(Key::NONE);
+ ke->set_physical_keycode(Key::NONE);
+ ke->set_key_label(Key::NONE);
+ ke->set_unicode(codepoint);
+
+ Input::get_singleton()->parse_input_event(ke);
+ }
+ ime_text = String();
+ ime_selection = Vector2i();
+
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
+ }
+
+ Ref<WaylandThread::IMEUpdateEventMessage> ime_update_msg = msg;
+ if (ime_update_msg.is_valid()) {
+ ime_text = ime_update_msg->text;
+ ime_selection = ime_update_msg->selection;
+
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
+ }
}
wayland_thread.keyboard_echo_keys();
diff --git a/platform/linuxbsd/wayland/display_server_wayland.h b/platform/linuxbsd/wayland/display_server_wayland.h
index c24eb0ee62..f02640a12e 100644
--- a/platform/linuxbsd/wayland/display_server_wayland.h
+++ b/platform/linuxbsd/wayland/display_server_wayland.h
@@ -115,6 +115,9 @@ class DisplayServerWayland : public DisplayServer {
Context context;
+ String ime_text;
+ Vector2i ime_selection;
+
bool suspended = false;
bool emulate_vsync = false;
@@ -259,6 +262,9 @@ public:
virtual void window_set_ime_active(const bool p_active, WindowID p_window_id = MAIN_WINDOW_ID) override;
virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window_id = MAIN_WINDOW_ID) override;
+ virtual Point2i ime_get_selection() const override;
+ virtual String ime_get_text() const override;
+
virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window_id = MAIN_WINDOW_ID) override;
virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_window_id) const override;
diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp
index aabf1abdda..63a8db07df 100644
--- a/platform/linuxbsd/wayland/wayland_thread.cpp
+++ b/platform/linuxbsd/wayland/wayland_thread.cpp
@@ -448,6 +448,12 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
zwp_tablet_seat_v2_add_listener(ss->wp_tablet_seat, &wp_tablet_seat_listener, ss);
}
+ if (!ss->wp_text_input && registry->wp_text_input_manager) {
+ // IME.
+ ss->wp_text_input = zwp_text_input_manager_v3_get_text_input(registry->wp_text_input_manager, wl_seat);
+ zwp_text_input_v3_add_listener(ss->wp_text_input, &wp_text_input_listener, ss);
+ }
+
registry->wl_seats.push_back(wl_seat);
wl_seat_add_listener(wl_seat, &wl_seat_listener, ss);
@@ -547,6 +553,22 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
return;
}
+
+ if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) {
+ registry->wp_text_input_manager = (struct zwp_text_input_manager_v3 *)wl_registry_bind(wl_registry, name, &zwp_text_input_manager_v3_interface, 1);
+ registry->wp_text_input_manager_name = name;
+
+ // This global creates some seat data. Let's do that for the ones already available.
+ for (struct wl_seat *wl_seat : registry->wl_seats) {
+ SeatState *ss = wl_seat_get_seat_state(wl_seat);
+ ERR_FAIL_NULL(ss);
+
+ ss->wp_text_input = zwp_text_input_manager_v3_get_text_input(registry->wp_text_input_manager, wl_seat);
+ zwp_text_input_v3_add_listener(ss->wp_text_input, &wp_text_input_listener, ss);
+ }
+
+ return;
+ }
}
void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) {
@@ -825,6 +847,25 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry
return;
}
+ if (name == registry->wp_text_input_manager_name) {
+ if (registry->wp_text_input_manager) {
+ zwp_text_input_manager_v3_destroy(registry->wp_text_input_manager);
+ registry->wp_text_input_manager = nullptr;
+ }
+
+ registry->wp_text_input_manager_name = 0;
+
+ for (struct wl_seat *wl_seat : registry->wl_seats) {
+ SeatState *ss = wl_seat_get_seat_state(wl_seat);
+ ERR_FAIL_NULL(ss);
+
+ zwp_text_input_v3_destroy(ss->wp_text_input);
+ ss->wp_text_input = nullptr;
+ }
+
+ return;
+ }
+
{
// Iterate through all of the seats to find if any got removed.
List<struct wl_seat *>::Element *E = registry->wl_seats.front();
@@ -2535,6 +2576,118 @@ void WaylandThread::_wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_
old_td = td;
}
+void WaylandThread::_wp_text_input_on_enter(void *data, struct zwp_text_input_v3 *wp_text_input_v3, struct wl_surface *surface) {
+ SeatState *ss = (SeatState *)data;
+ if (!ss) {
+ return;
+ }
+
+ ss->ime_enabled = true;
+}
+
+void WaylandThread::_wp_text_input_on_leave(void *data, struct zwp_text_input_v3 *wp_text_input_v3, struct wl_surface *surface) {
+ SeatState *ss = (SeatState *)data;
+ if (!ss) {
+ return;
+ }
+
+ ss->ime_enabled = false;
+ ss->ime_active = false;
+ ss->ime_text = String();
+ ss->ime_text_commit = String();
+ ss->ime_cursor = Vector2i();
+
+ Ref<IMEUpdateEventMessage> msg;
+ msg.instantiate();
+ msg->text = String();
+ msg->selection = Vector2i();
+ ss->wayland_thread->push_message(msg);
+}
+
+void WaylandThread::_wp_text_input_on_preedit_string(void *data, struct zwp_text_input_v3 *wp_text_input_v3, const char *text, int32_t cursor_begin, int32_t cursor_end) {
+ SeatState *ss = (SeatState *)data;
+ if (!ss) {
+ return;
+ }
+
+ ss->ime_text = String::utf8(text);
+
+ // Convert cursor positions from UTF-8 to UTF-32 offset.
+ int32_t cursor_begin_utf32 = 0;
+ int32_t cursor_end_utf32 = 0;
+ for (int i = 0; i < ss->ime_text.length(); i++) {
+ uint32_t c = ss->ime_text[i];
+ if (c <= 0x7f) { // 7 bits.
+ cursor_begin -= 1;
+ cursor_end -= 1;
+ } else if (c <= 0x7ff) { // 11 bits
+ cursor_begin -= 2;
+ cursor_end -= 2;
+ } else if (c <= 0xffff) { // 16 bits
+ cursor_begin -= 3;
+ cursor_end -= 3;
+ } else if (c <= 0x001fffff) { // 21 bits
+ cursor_begin -= 4;
+ cursor_end -= 4;
+ } else if (c <= 0x03ffffff) { // 26 bits
+ cursor_begin -= 5;
+ cursor_end -= 5;
+ } else if (c <= 0x7fffffff) { // 31 bits
+ cursor_begin -= 6;
+ cursor_end -= 6;
+ } else {
+ cursor_begin -= 1;
+ cursor_end -= 1;
+ }
+ if (cursor_begin == 0) {
+ cursor_begin_utf32 = i + 1;
+ }
+ if (cursor_end == 0) {
+ cursor_end_utf32 = i + 1;
+ }
+ if (cursor_begin <= 0 && cursor_end <= 0) {
+ break;
+ }
+ }
+ ss->ime_cursor = Vector2i(cursor_begin_utf32, cursor_end_utf32 - cursor_begin_utf32);
+}
+
+void WaylandThread::_wp_text_input_on_commit_string(void *data, struct zwp_text_input_v3 *wp_text_input_v3, const char *text) {
+ SeatState *ss = (SeatState *)data;
+ if (!ss) {
+ return;
+ }
+
+ ss->ime_text_commit = String::utf8(text);
+}
+
+void WaylandThread::_wp_text_input_on_delete_surrounding_text(void *data, struct zwp_text_input_v3 *wp_text_input_v3, uint32_t before_length, uint32_t after_length) {
+ // Not implemented.
+}
+
+void WaylandThread::_wp_text_input_on_done(void *data, struct zwp_text_input_v3 *wp_text_input_v3, uint32_t serial) {
+ SeatState *ss = (SeatState *)data;
+ if (!ss) {
+ return;
+ }
+
+ if (!ss->ime_text_commit.is_empty()) {
+ Ref<IMECommitEventMessage> msg;
+ msg.instantiate();
+ msg->text = ss->ime_text_commit;
+ ss->wayland_thread->push_message(msg);
+ } else if (!ss->ime_text.is_empty()) {
+ Ref<IMEUpdateEventMessage> msg;
+ msg.instantiate();
+ msg->text = ss->ime_text;
+ msg->selection = ss->ime_cursor;
+ ss->wayland_thread->push_message(msg);
+ }
+ ss->ime_text = String();
+ ss->ime_text_commit = String();
+ ss->ime_cursor = Vector2i();
+}
+
void WaylandThread::_xdg_activation_token_on_done(void *data, struct xdg_activation_token_v1 *xdg_activation_token, const char *token) {
WindowState *ws = (WindowState *)data;
ERR_FAIL_NULL(ws);
@@ -3729,6 +3882,35 @@ void WaylandThread::cursor_shape_clear_custom_image(DisplayServer::CursorShape p
}
}
+void WaylandThread::window_set_ime_active(const bool p_active, DisplayServer::WindowID p_window_id) {
+ SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
+
+ if (ss && ss->wp_text_input && ss->ime_enabled) {
+ if (p_active) {
+ ss->ime_active = true;
+ zwp_text_input_v3_enable(ss->wp_text_input);
+ zwp_text_input_v3_set_cursor_rectangle(ss->wp_text_input, ss->ime_rect.position.x, ss->ime_rect.position.y, ss->ime_rect.size.x, ss->ime_rect.size.y);
+ } else {
+ ss->ime_active = false;
+ ss->ime_text = String();
+ ss->ime_text_commit = String();
+ ss->ime_cursor = Vector2i();
+ zwp_text_input_v3_disable(ss->wp_text_input);
+ }
+ zwp_text_input_v3_commit(ss->wp_text_input);
+ }
+}
+
+void WaylandThread::window_set_ime_position(const Point2i &p_pos, DisplayServer::WindowID p_window_id) {
+ SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
+
+ if (ss && ss->wp_text_input && ss->ime_enabled) {
+ ss->ime_rect = Rect2i(p_pos, Size2i(1, 10));
+ zwp_text_input_v3_set_cursor_rectangle(ss->wp_text_input, ss->ime_rect.position.x, ss->ime_rect.position.y, ss->ime_rect.size.x, ss->ime_rect.size.y);
+ zwp_text_input_v3_commit(ss->wp_text_input);
+ }
+}
+
int WaylandThread::keyboard_get_layout_count() const {
SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h
index 0756b6b0ea..75d03181e2 100644
--- a/platform/linuxbsd/wayland/wayland_thread.h
+++ b/platform/linuxbsd/wayland/wayland_thread.h
@@ -62,6 +62,7 @@
#undef pointer
#include "wayland/protocol/fractional_scale.gen.h"
#include "wayland/protocol/tablet.gen.h"
+#include "wayland/protocol/text_input.gen.h"
#include "wayland/protocol/viewporter.gen.h"
#include "wayland/protocol/wayland.gen.h"
#include "wayland/protocol/xdg_activation.gen.h"
@@ -112,6 +113,17 @@ public:
Vector<String> files;
};
+ class IMEUpdateEventMessage : public Message {
+ public:
+ String text;
+ Vector2i selection;
+ };
+
+ class IMECommitEventMessage : public Message {
+ public:
+ String text;
+ };
+
struct RegistryState {
WaylandThread *wayland_thread;
@@ -170,6 +182,9 @@ public:
struct zwp_tablet_manager_v2 *wp_tablet_manager = nullptr;
uint32_t wp_tablet_manager_name = 0;
+
+ struct zwp_text_input_manager_v3 *wp_text_input_manager = nullptr;
+ uint32_t wp_text_input_manager_name = 0;
};
// General Wayland-specific states. Shouldn't be accessed directly.
@@ -438,6 +453,15 @@ public:
struct zwp_tablet_seat_v2 *wp_tablet_seat = nullptr;
List<struct zwp_tablet_tool_v2 *> tablet_tools;
+
+ // IME.
+ struct zwp_text_input_v3 *wp_text_input = nullptr;
+ bool ime_enabled = false;
+ bool ime_active = false;
+ String ime_text;
+ String ime_text_commit;
+ Vector2i ime_cursor;
+ Rect2i ime_rect;
};
struct CustomCursor {
@@ -618,6 +642,13 @@ private:
static void _wp_tablet_tool_on_button(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial, uint32_t button, uint32_t state);
static void _wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t time);
+ static void _wp_text_input_on_enter(void *data, struct zwp_text_input_v3 *wp_text_input_v3, struct wl_surface *surface);
+ static void _wp_text_input_on_leave(void *data, struct zwp_text_input_v3 *wp_text_input_v3, struct wl_surface *surface);
+ static void _wp_text_input_on_preedit_string(void *data, struct zwp_text_input_v3 *wp_text_input_v3, const char *text, int32_t cursor_begin, int32_t cursor_end);
+ static void _wp_text_input_on_commit_string(void *data, struct zwp_text_input_v3 *wp_text_input_v3, const char *text);
+ static void _wp_text_input_on_delete_surrounding_text(void *data, struct zwp_text_input_v3 *wp_text_input_v3, uint32_t before_length, uint32_t after_length);
+ static void _wp_text_input_on_done(void *data, struct zwp_text_input_v3 *wp_text_input_v3, uint32_t serial);
+
static void _xdg_toplevel_decoration_on_configure(void *data, struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration, uint32_t mode);
static void _xdg_exported_on_exported(void *data, zxdg_exported_v1 *exported, const char *handle);
@@ -779,6 +810,15 @@ private:
.frame = _wp_tablet_tool_on_frame,
};
+ static constexpr struct zwp_text_input_v3_listener wp_text_input_listener = {
+ .enter = _wp_text_input_on_enter,
+ .leave = _wp_text_input_on_leave,
+ .preedit_string = _wp_text_input_on_preedit_string,
+ .commit_string = _wp_text_input_on_commit_string,
+ .delete_surrounding_text = _wp_text_input_on_delete_surrounding_text,
+ .done = _wp_text_input_on_done,
+ };
+
static constexpr struct zxdg_exported_v1_listener xdg_exported_listener = {
.handle = _xdg_exported_on_exported
};
@@ -929,6 +969,9 @@ public:
void cursor_shape_set_custom_image(DisplayServer::CursorShape p_cursor_shape, Ref<Image> p_image, const Point2i &p_hotspot);
void cursor_shape_clear_custom_image(DisplayServer::CursorShape p_cursor_shape);
+ void window_set_ime_active(const bool p_active, DisplayServer::WindowID p_window_id);
+ void window_set_ime_position(const Point2i &p_pos, DisplayServer::WindowID p_window_id);
+
int keyboard_get_layout_count() const;
int keyboard_get_current_layout_index() const;
void keyboard_set_current_layout_index(int p_index);
diff --git a/platform/linuxbsd/x11/gl_manager_x11.cpp b/platform/linuxbsd/x11/gl_manager_x11.cpp
index febb7ae584..738ebffa02 100644
--- a/platform/linuxbsd/x11/gl_manager_x11.cpp
+++ b/platform/linuxbsd/x11/gl_manager_x11.cpp
@@ -357,7 +357,7 @@ void GLManager_X11::set_use_vsync(bool p_use) {
GLXDrawable drawable = glXGetCurrentDrawable();
glXSwapIntervalEXT(disp.x11_display, drawable, val);
} else {
- WARN_PRINT("Could not set V-Sync mode. V-Sync is not supported.");
+ WARN_PRINT_ONCE("Could not set V-Sync mode, as changing V-Sync mode is not supported by the graphics driver.");
return;
}
use_vsync = p_use;