summaryrefslogtreecommitdiffstats
path: root/platform/linuxbsd
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r--platform/linuxbsd/detect.py14
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.cpp9
-rw-r--r--platform/linuxbsd/joypad_linux.cpp6
-rw-r--r--platform/linuxbsd/wayland/SCsub11
-rw-r--r--platform/linuxbsd/wayland/detect_prime_egl.cpp28
-rw-r--r--platform/linuxbsd/wayland/detect_prime_egl.h28
-rw-r--r--platform/linuxbsd/wayland/display_server_wayland.cpp84
-rw-r--r--platform/linuxbsd/wayland/display_server_wayland.h12
-rw-r--r--platform/linuxbsd/wayland/wayland_thread.cpp182
-rw-r--r--platform/linuxbsd/wayland/wayland_thread.h46
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp208
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h9
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.cpp2
13 files changed, 531 insertions, 108 deletions
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 47f3bcadc9..303a88ab26 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -1,11 +1,11 @@
import os
import platform
import sys
-from methods import print_warning, print_error, get_compiler_version, using_gcc
-from platform_methods import detect_arch
-
from typing import TYPE_CHECKING
+from methods import get_compiler_version, print_error, print_warning, using_gcc
+from platform_methods import detect_arch
+
if TYPE_CHECKING:
from SCons.Script.SConscript import SConsEnvironment
@@ -65,10 +65,10 @@ def get_doc_path():
def get_flags():
- return [
- ("arch", detect_arch()),
- ("supported", ["mono"]),
- ]
+ return {
+ "arch": detect_arch(),
+ "supported": ["mono"],
+ }
def configure(env: "SConsEnvironment"):
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp
index e65404a531..671da7fc2a 100644
--- a/platform/linuxbsd/freedesktop_portal_desktop.cpp
+++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp
@@ -591,13 +591,18 @@ void FreeDesktopPortalDesktop::_thread_monitor(void *p_ud) {
dbus_connection_read_write(portal->monitor_connection, 0);
}
- usleep(50000);
+ OS::get_singleton()->delay_usec(50'000);
}
}
void FreeDesktopPortalDesktop::_system_theme_changed_callback() {
if (system_theme_changed.is_valid()) {
- system_theme_changed.call();
+ Variant ret;
+ Callable::CallError ce;
+ system_theme_changed.callp(nullptr, 0, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute system theme changed callback: %s.", Variant::get_callable_error_text(system_theme_changed, nullptr, 0, ce)));
+ }
}
}
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index 6e546c4531..3534c1afee 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -225,7 +225,7 @@ void JoypadLinux::monitor_joypads(udev *p_udev) {
udev_device_unref(dev);
}
}
- usleep(50000);
+ OS::get_singleton()->delay_usec(50'000);
}
udev_monitor_unref(mon);
}
@@ -250,7 +250,7 @@ void JoypadLinux::monitor_joypads() {
}
}
closedir(input_directory);
- usleep(1000000); // 1s
+ OS::get_singleton()->delay_usec(1'000'000);
}
}
@@ -508,7 +508,7 @@ void JoypadLinux::joypad_events_thread_run() {
}
}
if (no_events) {
- usleep(10000); // 10ms
+ OS::get_singleton()->delay_usec(10'000);
}
}
}
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/detect_prime_egl.cpp b/platform/linuxbsd/wayland/detect_prime_egl.cpp
index 4c97a80039..e24c03c869 100644
--- a/platform/linuxbsd/wayland/detect_prime_egl.cpp
+++ b/platform/linuxbsd/wayland/detect_prime_egl.cpp
@@ -38,15 +38,6 @@
#include <stdlib.h>
-#ifdef GLAD_ENABLED
-#include "thirdparty/glad/glad/egl.h"
-#include "thirdparty/glad/glad/gl.h"
-#else
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GL/glcorearb.h>
-#endif // GLAD_ENABLED
-
#include <cstring>
#include <sys/types.h>
@@ -57,7 +48,7 @@
#undef glGetString
// Runs inside a child. Exiting will not quit the engine.
-void DetectPrimeEGL::create_context() {
+void DetectPrimeEGL::create_context(EGLenum p_platform_enum) {
#if defined(GLAD_ENABLED)
if (!gladLoaderLoadEGL(nullptr)) {
print_verbose("Unable to load EGL, GPU detection skipped.");
@@ -65,7 +56,18 @@ void DetectPrimeEGL::create_context() {
}
#endif
- EGLDisplay egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ EGLDisplay egl_display = EGL_NO_DISPLAY;
+
+ if (GLAD_EGL_VERSION_1_5) {
+ egl_display = eglGetPlatformDisplay(p_platform_enum, nullptr, nullptr);
+ } else if (GLAD_EGL_EXT_platform_base) {
+#ifdef EGL_EXT_platform_base
+ egl_display = eglGetPlatformDisplayEXT(p_platform_enum, nullptr, nullptr);
+#endif
+ } else {
+ egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ }
+
EGLConfig egl_config;
EGLContext egl_context = EGL_NO_CONTEXT;
@@ -110,7 +112,7 @@ void DetectPrimeEGL::create_context() {
eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_context);
}
-int DetectPrimeEGL::detect_prime() {
+int DetectPrimeEGL::detect_prime(EGLenum p_platform_enum) {
pid_t p;
int priorities[4] = {};
String vendors[4];
@@ -168,7 +170,7 @@ int DetectPrimeEGL::detect_prime() {
setenv("DRI_PRIME", itos(i).utf8().ptr(), 1);
- create_context();
+ create_context(p_platform_enum);
PFNGLGETSTRINGPROC glGetString = (PFNGLGETSTRINGPROC)eglGetProcAddress("glGetString");
const char *vendor = (const char *)glGetString(GL_VENDOR);
diff --git a/platform/linuxbsd/wayland/detect_prime_egl.h b/platform/linuxbsd/wayland/detect_prime_egl.h
index 26351b0dce..3391e020d8 100644
--- a/platform/linuxbsd/wayland/detect_prime_egl.h
+++ b/platform/linuxbsd/wayland/detect_prime_egl.h
@@ -34,6 +34,30 @@
#ifdef GLES3_ENABLED
#ifdef EGL_ENABLED
+#ifdef GLAD_ENABLED
+#include "thirdparty/glad/glad/egl.h"
+#include "thirdparty/glad/glad/gl.h"
+#else
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GL/glcorearb.h>
+
+#define GLAD_EGL_VERSION_1_5 1
+
+#ifdef EGL_EXT_platform_base
+#define GLAD_EGL_EXT_platform_base 1
+#endif
+
+#define KHRONOS_STATIC 1
+extern "C" EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list);
+#undef KHRONOS_STATIC
+
+#endif // GLAD_ENABLED
+
+#ifndef EGL_EXT_platform_base
+#define GLAD_EGL_EXT_platform_base 0
+#endif
+
class DetectPrimeEGL {
private:
struct Vendor {
@@ -53,10 +77,10 @@ private:
{ nullptr, 0 }
};
- static void create_context();
+ static void create_context(EGLenum p_platform_enum);
public:
- static int detect_prime();
+ static int detect_prime(EGLenum p_platform_enum);
};
#endif // GLES3_ENABLED
diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp
index f7995472d0..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
@@ -1018,8 +1029,7 @@ void DisplayServerWayland::cursor_set_custom_image(const Ref<Resource> &p_cursor
wayland_thread.cursor_shape_clear_custom_image(p_shape);
}
- Rect2 atlas_rect;
- Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot, atlas_rect);
+ Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot);
ERR_FAIL_COND(image.is_null());
CustomCursor &cursor = custom_cursors[p_shape];
@@ -1137,9 +1147,47 @@ void DisplayServerWayland::process_events() {
WindowData wd = main_window;
if (wd.drop_files_callback.is_valid()) {
- wd.drop_files_callback.call(dropfiles_msg->files);
+ Variant v_files = dropfiles_msg->files;
+ const Variant *v_args[1] = { &v_files };
+ Variant ret;
+ Callable::CallError ce;
+ wd.drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(wd.drop_files_callback, v_args, 1, ce)));
+ }
}
}
+
+ 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();
@@ -1209,6 +1257,15 @@ void DisplayServerWayland::set_context(Context p_context) {
wayland_thread.window_set_app_id(MAIN_WINDOW_ID, app_id);
}
+bool DisplayServerWayland::is_window_transparency_available() const {
+#if defined(RD_ENABLED)
+ if (rendering_device && !rendering_device->is_composite_alpha_supported()) {
+ return false;
+ }
+#endif
+ return OS::get_singleton()->is_layered_allowed();
+}
+
Vector<String> DisplayServerWayland::get_rendering_drivers_func() {
Vector<String> drivers;
@@ -1224,8 +1281,8 @@ Vector<String> DisplayServerWayland::get_rendering_drivers_func() {
return drivers;
}
-DisplayServer *DisplayServerWayland::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Error &r_error) {
- DisplayServer *ds = memnew(DisplayServerWayland(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerWayland::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Context p_context, Error &r_error) {
+ DisplayServer *ds = memnew(DisplayServerWayland(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, p_context, r_error));
if (r_error != OK) {
ERR_PRINT("Can't create the Wayland display server.");
memdelete(ds);
@@ -1235,7 +1292,7 @@ DisplayServer *DisplayServerWayland::create_func(const String &p_rendering_drive
return ds;
}
-DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Context p_context, Error &r_error) {
#ifdef GLES3_ENABLED
#ifdef SOWRAP_ENABLED
#ifdef DEBUG_ENABLED
@@ -1247,6 +1304,7 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
#endif // GLES3_ENABLED
r_error = ERR_UNAVAILABLE;
+ context = p_context;
Error thread_err = wayland_thread.init();
@@ -1326,7 +1384,7 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
if (prime_idx == -1) {
print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic.");
- prime_idx = DetectPrimeEGL::detect_prime();
+ prime_idx = DetectPrimeEGL::detect_prime(EGL_PLATFORM_WAYLAND_KHR);
}
if (prime_idx) {
@@ -1339,7 +1397,7 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
if (rendering_driver == "opengl3") {
egl_manager = memnew(EGLManagerWayland);
- if (egl_manager->initialize() != OK || egl_manager->open_display(wayland_thread.get_wl_display()) != OK) {
+ if (egl_manager->initialize(wayland_thread.get_wl_display()) != OK || egl_manager->open_display(wayland_thread.get_wl_display()) != OK) {
memdelete(egl_manager);
egl_manager = nullptr;
@@ -1359,7 +1417,7 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
if (rendering_driver == "opengl3_es") {
egl_manager = memnew(EGLManagerWaylandGLES);
- if (egl_manager->initialize() != OK) {
+ if (egl_manager->initialize(wayland_thread.get_wl_display()) != OK) {
memdelete(egl_manager);
egl_manager = nullptr;
r_error = ERR_CANT_CREATE;
diff --git a/platform/linuxbsd/wayland/display_server_wayland.h b/platform/linuxbsd/wayland/display_server_wayland.h
index 1bad358462..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;
@@ -280,12 +286,14 @@ public:
virtual void set_context(Context p_context) override;
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Error &r_error);
+ virtual bool is_window_transparency_available() const override;
+
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, int p_screen, Context p_context, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_wayland_driver();
- DisplayServerWayland(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ DisplayServerWayland(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Context p_context, Error &r_error);
~DisplayServerWayland();
};
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 d35a5b7139..75d03181e2 100644
--- a/platform/linuxbsd/wayland/wayland_thread.h
+++ b/platform/linuxbsd/wayland/wayland_thread.h
@@ -43,6 +43,9 @@
#else
#include <wayland-client-core.h>
#include <wayland-cursor.h>
+#ifdef GLES3_ENABLED
+#include <wayland-egl.h>
+#endif
#include <xkbcommon/xkbcommon.h>
#endif // SOWRAP_ENABLED
@@ -59,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"
@@ -109,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;
@@ -167,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.
@@ -435,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 {
@@ -615,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);
@@ -776,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
};
@@ -926,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/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 9174b65b1b..a605e664ce 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -139,8 +139,9 @@ bool DisplayServerX11::has_feature(Feature p_feature) const {
#endif
case FEATURE_CLIPBOARD_PRIMARY:
case FEATURE_TEXT_TO_SPEECH:
- case FEATURE_SCREEN_CAPTURE:
return true;
+ case FEATURE_SCREEN_CAPTURE:
+ return !xwayland;
default: {
}
}
@@ -502,7 +503,34 @@ Point2i DisplayServerX11::mouse_get_position() const {
}
BitField<MouseButtonMask> DisplayServerX11::mouse_get_button_state() const {
- return last_button_state;
+ int number_of_screens = XScreenCount(x11_display);
+ for (int i = 0; i < number_of_screens; i++) {
+ Window root, child;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask;
+ if (XQueryPointer(x11_display, XRootWindow(x11_display, i), &root, &child, &root_x, &root_y, &win_x, &win_y, &mask)) {
+ BitField<MouseButtonMask> last_button_state = 0;
+
+ if (mask & Button1Mask) {
+ last_button_state.set_flag(MouseButtonMask::LEFT);
+ }
+ if (mask & Button2Mask) {
+ last_button_state.set_flag(MouseButtonMask::MIDDLE);
+ }
+ if (mask & Button3Mask) {
+ last_button_state.set_flag(MouseButtonMask::RIGHT);
+ }
+ if (mask & Button4Mask) {
+ last_button_state.set_flag(MouseButtonMask::MB_XBUTTON1);
+ }
+ if (mask & Button5Mask) {
+ last_button_state.set_flag(MouseButtonMask::MB_XBUTTON2);
+ }
+
+ return last_button_state;
+ }
+ }
+ return 0;
}
void DisplayServerX11::clipboard_set(const String &p_text) {
@@ -1007,7 +1035,8 @@ int DisplayServerX11::get_screen_count() const {
if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) {
XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
XFree(xsi);
- } else {
+ }
+ if (count == 0) {
count = XScreenCount(x11_display);
}
@@ -1068,25 +1097,29 @@ Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const {
ERR_FAIL_COND_V(p_screen < 0, rect);
// Using Xinerama Extension.
+ bool found = false;
int event_base, error_base;
if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) {
int count;
XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
-
- // Check if screen is valid.
- if (p_screen < count) {
- rect.position.x = xsi[p_screen].x_org;
- rect.position.y = xsi[p_screen].y_org;
- rect.size.width = xsi[p_screen].width;
- rect.size.height = xsi[p_screen].height;
- } else {
- ERR_PRINT("Invalid screen index: " + itos(p_screen) + "(count: " + itos(count) + ").");
- }
-
if (xsi) {
+ if (count > 0) {
+ // Check if screen is valid.
+ if (p_screen < count) {
+ rect.position.x = xsi[p_screen].x_org;
+ rect.position.y = xsi[p_screen].y_org;
+ rect.size.width = xsi[p_screen].width;
+ rect.size.height = xsi[p_screen].height;
+ found = true;
+ } else {
+ ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, count));
+ }
+ }
XFree(xsi);
}
- } else {
+ }
+
+ if (!found) {
int count = XScreenCount(x11_display);
if (p_screen < count) {
Window root = XRootWindow(x11_display, p_screen);
@@ -1097,7 +1130,7 @@ Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const {
rect.size.width = xwa.width;
rect.size.height = xwa.height;
} else {
- ERR_PRINT("Invalid screen index: " + itos(p_screen) + "(count: " + itos(count) + ").");
+ ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, count));
}
}
@@ -1462,9 +1495,20 @@ int DisplayServerX11::screen_get_dpi(int p_screen) const {
return 96;
}
+int get_image_errorhandler(Display *dpy, XErrorEvent *ev) {
+ return 0;
+}
+
Color DisplayServerX11::screen_get_pixel(const Point2i &p_position) const {
Point2i pos = p_position;
+ if (xwayland) {
+ return Color();
+ }
+
+ int (*old_handler)(Display *, XErrorEvent *) = XSetErrorHandler(&get_image_errorhandler);
+
+ Color color;
int number_of_screens = XScreenCount(x11_display);
for (int i = 0; i < number_of_screens; i++) {
Window root = XRootWindow(x11_display, i);
@@ -1477,12 +1521,15 @@ Color DisplayServerX11::screen_get_pixel(const Point2i &p_position) const {
c.pixel = XGetPixel(image, 0, 0);
XFree(image);
XQueryColor(x11_display, XDefaultColormap(x11_display, i), &c);
- return Color(float(c.red) / 65535.0, float(c.green) / 65535.0, float(c.blue) / 65535.0, 1.0);
+ color = Color(float(c.red) / 65535.0, float(c.green) / 65535.0, float(c.blue) / 65535.0, 1.0);
+ break;
}
}
}
- return Color();
+ XSetErrorHandler(old_handler);
+
+ return color;
}
Ref<Image> DisplayServerX11::screen_get_image(int p_screen) const {
@@ -1501,27 +1548,41 @@ Ref<Image> DisplayServerX11::screen_get_image(int p_screen) const {
ERR_FAIL_COND_V(p_screen < 0, Ref<Image>());
+ if (xwayland) {
+ return Ref<Image>();
+ }
+
+ int (*old_handler)(Display *, XErrorEvent *) = XSetErrorHandler(&get_image_errorhandler);
+
XImage *image = nullptr;
+ bool found = false;
int event_base, error_base;
if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) {
int xin_count;
XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &xin_count);
- if (p_screen < xin_count) {
- int x_count = XScreenCount(x11_display);
- for (int i = 0; i < x_count; i++) {
- Window root = XRootWindow(x11_display, i);
- XWindowAttributes root_attrs;
- XGetWindowAttributes(x11_display, root, &root_attrs);
- if ((xsi[p_screen].x_org >= root_attrs.x) && (xsi[p_screen].x_org <= root_attrs.x + root_attrs.width) && (xsi[p_screen].y_org >= root_attrs.y) && (xsi[p_screen].y_org <= root_attrs.y + root_attrs.height)) {
- image = XGetImage(x11_display, root, xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height, AllPlanes, ZPixmap);
- break;
+ if (xsi) {
+ if (xin_count > 0) {
+ if (p_screen < xin_count) {
+ int x_count = XScreenCount(x11_display);
+ for (int i = 0; i < x_count; i++) {
+ Window root = XRootWindow(x11_display, i);
+ XWindowAttributes root_attrs;
+ XGetWindowAttributes(x11_display, root, &root_attrs);
+ if ((xsi[p_screen].x_org >= root_attrs.x) && (xsi[p_screen].x_org <= root_attrs.x + root_attrs.width) && (xsi[p_screen].y_org >= root_attrs.y) && (xsi[p_screen].y_org <= root_attrs.y + root_attrs.height)) {
+ found = true;
+ image = XGetImage(x11_display, root, xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height, AllPlanes, ZPixmap);
+ break;
+ }
+ }
+ } else {
+ ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, xin_count));
}
}
- } else {
- ERR_FAIL_V_MSG(Ref<Image>(), "Invalid screen index: " + itos(p_screen) + "(count: " + itos(xin_count) + ").");
+ XFree(xsi);
}
- } else {
+ }
+ if (!found) {
int x_count = XScreenCount(x11_display);
if (p_screen < x_count) {
Window root = XRootWindow(x11_display, p_screen);
@@ -1531,10 +1592,12 @@ Ref<Image> DisplayServerX11::screen_get_image(int p_screen) const {
image = XGetImage(x11_display, root, root_attrs.x, root_attrs.y, root_attrs.width, root_attrs.height, AllPlanes, ZPixmap);
} else {
- ERR_FAIL_V_MSG(Ref<Image>(), "Invalid screen index: " + itos(p_screen) + "(count: " + itos(x_count) + ").");
+ ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, x_count));
}
}
+ XSetErrorHandler(old_handler);
+
Ref<Image> img;
if (image) {
int width = image->width;
@@ -2256,7 +2319,7 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
break;
}
- usleep(10000);
+ OS::get_singleton()->delay_usec(10'000);
}
// Keep rendering context window size in sync
@@ -2531,7 +2594,7 @@ void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) {
// Give up after 0.5s, it's not going to happen on this WM.
// https://github.com/godotengine/godot/issues/19978
for (int attempt = 0; window_get_mode(p_window) != WINDOW_MODE_MAXIMIZED && attempt < 50; attempt++) {
- usleep(10000);
+ OS::get_singleton()->delay_usec(10'000);
}
}
wd.maximized = p_enabled;
@@ -3068,8 +3131,7 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu
cursors_cache.erase(p_shape);
}
- Rect2 atlas_rect;
- Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot, atlas_rect);
+ Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot);
ERR_FAIL_COND(image.is_null());
Vector2i texture_size = image->get_size();
@@ -3087,13 +3149,8 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu
cursor_image->pixels = (XcursorPixel *)memalloc(size);
for (XcursorPixel index = 0; index < image_size; index++) {
- int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
- int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
-
- if (atlas_rect.has_area()) {
- column_index = MIN(column_index, atlas_rect.size.width - 1);
- row_index = MIN(row_index, atlas_rect.size.height - 1);
- }
+ int row_index = floor(index / texture_size.width);
+ int column_index = index % int(texture_size.width);
*(cursor_image->pixels + index) = image->get_pixel(column_index, row_index).to_argb32();
}
@@ -3338,18 +3395,6 @@ void DisplayServerX11::_get_key_modifier_state(unsigned int p_x11_state, Ref<Inp
state->set_meta_pressed((p_x11_state & Mod4Mask));
}
-BitField<MouseButtonMask> DisplayServerX11::_get_mouse_button_state(MouseButton p_x11_button, int p_x11_type) {
- MouseButtonMask mask = mouse_button_to_mask(p_x11_button);
-
- if (p_x11_type == ButtonPress) {
- last_button_state.set_flag(mask);
- } else {
- last_button_state.clear_flag(mask);
- }
-
- return last_button_state;
-}
-
void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, LocalVector<XEvent> &p_events, uint32_t &p_event_index, bool p_echo) {
WindowData &wd = windows[p_window];
// X11 functions don't know what const is
@@ -4162,8 +4207,11 @@ void DisplayServerX11::popup_open(WindowID p_window) {
}
}
+ // Detect tooltips and other similar popups that shouldn't block input to their parent.
+ bool ignores_input = window_get_flag(WINDOW_FLAG_NO_FOCUS, p_window) && window_get_flag(WINDOW_FLAG_MOUSE_PASSTHROUGH, p_window);
+
WindowData &wd = windows[p_window];
- if (wd.is_popup || has_popup_ancestor) {
+ if (wd.is_popup || (has_popup_ancestor && !ignores_input)) {
// Find current popup parent, or root popup if new window is not transient.
List<WindowID>::Element *C = nullptr;
List<WindowID>::Element *E = popup_list.back();
@@ -4193,7 +4241,10 @@ void DisplayServerX11::popup_close(WindowID p_window) {
WindowID win_id = E->get();
popup_list.erase(E);
- _send_window_event(windows[win_id], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
+ if (win_id != p_window) {
+ // Only request close on related windows, not this window. We are already processing it.
+ _send_window_event(windows[win_id], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
+ }
E = F;
}
}
@@ -4734,12 +4785,20 @@ void DisplayServerX11::process_events() {
} else if (mb->get_button_index() == MouseButton::MIDDLE) {
mb->set_button_index(MouseButton::RIGHT);
}
- mb->set_button_mask(_get_mouse_button_state(mb->get_button_index(), event.xbutton.type));
mb->set_position(Vector2(event.xbutton.x, event.xbutton.y));
mb->set_global_position(mb->get_position());
mb->set_pressed((event.type == ButtonPress));
+ if (mb->is_pressed() && mb->get_button_index() >= MouseButton::WHEEL_UP && mb->get_button_index() <= MouseButton::WHEEL_RIGHT) {
+ MouseButtonMask mask = mouse_button_to_mask(mb->get_button_index());
+ BitField<MouseButtonMask> scroll_mask = mouse_get_button_state();
+ scroll_mask.set_flag(mask);
+ mb->set_button_mask(scroll_mask);
+ } else {
+ mb->set_button_mask(mouse_get_button_state());
+ }
+
const WindowData &wd = windows[window_id];
if (event.type == ButtonPress) {
@@ -4995,7 +5054,14 @@ void DisplayServerX11::process_events() {
}
if (windows[window_id].drop_files_callback.is_valid()) {
- windows[window_id].drop_files_callback.call(files);
+ Variant v_files = files;
+ const Variant *v_args[1] = { &v_files };
+ Variant ret;
+ Callable::CallError ce;
+ windows[window_id].drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(windows[window_id].drop_files_callback, v_args, 1, ce)));
+ }
}
//Reply that all is well.
@@ -5179,6 +5245,23 @@ void DisplayServerX11::set_context(Context p_context) {
}
}
+bool DisplayServerX11::is_window_transparency_available() const {
+ CharString net_wm_cm_name = vformat("_NET_WM_CM_S%d", XDefaultScreen(x11_display)).ascii();
+ Atom net_wm_cm = XInternAtom(x11_display, net_wm_cm_name.get_data(), False);
+ if (net_wm_cm == None) {
+ return false;
+ }
+ if (XGetSelectionOwner(x11_display, net_wm_cm) == None) {
+ return false;
+ }
+#if defined(RD_ENABLED)
+ if (rendering_device && !rendering_device->is_composite_alpha_supported()) {
+ return false;
+ }
+#endif
+ return OS::get_singleton()->is_layered_allowed();
+}
+
void DisplayServerX11::set_native_icon(const String &p_filename) {
WARN_PRINT("Native icon not supported by this display server.");
}
@@ -5320,8 +5403,8 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
return drivers;
}
-DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
- DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error));
+DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) {
+ DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, r_error));
if (r_error != OK) {
if (p_rendering_driver == "vulkan") {
String executable_name = OS::get_singleton()->get_executable_path().get_file();
@@ -5752,10 +5835,13 @@ static ::XIMStyle _get_best_xim_style(const ::XIMStyle &p_style_a, const ::XIMSt
return p_style_a;
}
-DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
+DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) {
KeyMappingX11::initialize();
+ xwayland = OS::get_singleton()->get_environment("XDG_SESSION_TYPE").to_lower() == "wayland";
+
native_menu = memnew(NativeMenu);
+ context = p_context;
#ifdef SOWRAP_ENABLED
#ifdef DEBUG_ENABLED
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index 8a7062857c..341ba5f079 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -263,7 +263,6 @@ class DisplayServerX11 : public DisplayServer {
Point2i last_click_pos = Point2i(-100, -100);
uint64_t last_click_ms = 0;
MouseButton last_click_button_index = MouseButton::NONE;
- BitField<MouseButtonMask> last_button_state;
bool app_focused = false;
uint64_t time_since_no_focus = 0;
@@ -292,7 +291,6 @@ class DisplayServerX11 : public DisplayServer {
Rect2i _screen_get_rect(int p_screen) const;
- BitField<MouseButtonMask> _get_mouse_button_state(MouseButton p_x11_button, int p_x11_type);
void _get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state);
void _flush_mouse_motion();
@@ -332,6 +330,7 @@ class DisplayServerX11 : public DisplayServer {
bool xrandr_ext_ok = true;
bool xinerama_ext_ok = true;
bool xshaped_ext_ok = true;
+ bool xwayland = false;
struct Property {
unsigned char *data;
@@ -530,15 +529,17 @@ public:
virtual void set_context(Context p_context) override;
+ virtual bool is_window_transparency_available() const override;
+
virtual void set_native_icon(const String &p_filename) override;
virtual void set_icon(const Ref<Image> &p_icon) override;
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_x11_driver();
- DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
+ DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error);
~DisplayServerX11();
};
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;