diff options
Diffstat (limited to 'platform/linuxbsd')
| -rw-r--r-- | platform/linuxbsd/export/logo.svg | 2 | ||||
| -rw-r--r-- | platform/linuxbsd/export/run_icon.svg | 2 | ||||
| -rw-r--r-- | platform/linuxbsd/tts_linux.cpp | 8 | ||||
| -rw-r--r-- | platform/linuxbsd/wayland/SCsub | 11 | ||||
| -rw-r--r-- | platform/linuxbsd/wayland/display_server_wayland.cpp | 50 | ||||
| -rw-r--r-- | platform/linuxbsd/wayland/display_server_wayland.h | 6 | ||||
| -rw-r--r-- | platform/linuxbsd/wayland/wayland_thread.cpp | 182 | ||||
| -rw-r--r-- | platform/linuxbsd/wayland/wayland_thread.h | 43 | ||||
| -rw-r--r-- | platform/linuxbsd/x11/gl_manager_x11.cpp | 2 |
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; |
