diff options
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r-- | platform/linuxbsd/crash_handler_linuxbsd.cpp | 4 | ||||
-rw-r--r-- | platform/linuxbsd/detect.py | 18 | ||||
-rw-r--r-- | platform/linuxbsd/platform_linuxbsd_builders.py | 1 | ||||
-rw-r--r-- | platform/linuxbsd/wayland/display_server_wayland.cpp | 63 | ||||
-rw-r--r-- | platform/linuxbsd/wayland/display_server_wayland.h | 3 | ||||
-rw-r--r-- | platform/linuxbsd/wayland/wayland_thread.cpp | 253 | ||||
-rw-r--r-- | platform/linuxbsd/wayland/wayland_thread.h | 20 | ||||
-rw-r--r-- | platform/linuxbsd/x11/display_server_x11.cpp | 52 | ||||
-rw-r--r-- | platform/linuxbsd/x11/display_server_x11.h | 1 |
9 files changed, 215 insertions, 200 deletions
diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp index fd4bcf92be..446fe5c7a1 100644 --- a/platform/linuxbsd/crash_handler_linuxbsd.cpp +++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp @@ -36,8 +36,8 @@ #include "core/version.h" #include "main/main.h" -#ifdef DEBUG_ENABLED -#define CRASH_HANDLER_ENABLED 1 +#ifndef DEBUG_ENABLED +#undef CRASH_HANDLER_ENABLED #endif #ifdef CRASH_HANDLER_ENABLED diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 4856076436..27dec73b65 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -50,7 +50,7 @@ def get_opts(): BoolVariable("wayland", "Enable Wayland display", True), BoolVariable("libdecor", "Enable libdecor support", True), BoolVariable("touch", "Enable touch events", True), - BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False), + BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", None), ] @@ -488,14 +488,20 @@ def configure(env: "SConsEnvironment"): if platform.system() == "Linux": env.Append(LIBS=["dl"]) - if not env["execinfo"] and platform.libc_ver()[0] != "glibc": + if platform.libc_ver()[0] != "glibc": # The default crash handler depends on glibc, so if the host uses # a different libc (BSD libc, musl), fall back to libexecinfo. - print("Note: Using `execinfo=yes` for the crash handler as required on platforms where glibc is missing.") - env["execinfo"] = True + if not "execinfo" in env: + print("Note: Using `execinfo=yes` for the crash handler as required on platforms where glibc is missing.") + env["execinfo"] = True - if env["execinfo"]: - env.Append(LIBS=["execinfo"]) + if env["execinfo"]: + env.Append(LIBS=["execinfo"]) + env.Append(CPPDEFINES=["CRASH_HANDLER_ENABLED"]) + else: + print("Note: Using `execinfo=no` disables the crash handler on platforms where glibc is missing.") + else: + env.Append(CPPDEFINES=["CRASH_HANDLER_ENABLED"]) if platform.system() == "FreeBSD": env.Append(LINKFLAGS=["-lkvm"]) diff --git a/platform/linuxbsd/platform_linuxbsd_builders.py b/platform/linuxbsd/platform_linuxbsd_builders.py index 58234f3748..85d55f0ac6 100644 --- a/platform/linuxbsd/platform_linuxbsd_builders.py +++ b/platform/linuxbsd/platform_linuxbsd_builders.py @@ -3,6 +3,7 @@ All such functions are invoked in a subprocess on Windows to prevent build flakiness. """ + import os from platform_methods import subprocess_main diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index c957dea32d..59c17b5816 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -192,19 +192,35 @@ void DisplayServerWayland::_show_window() { bool DisplayServerWayland::has_feature(Feature p_feature) const { switch (p_feature) { +#ifndef DISABLE_DEPRECATED + case FEATURE_GLOBAL_MENU: { + return (native_menu && native_menu->has_feature(NativeMenu::FEATURE_GLOBAL_MENU)); + } break; +#endif case FEATURE_MOUSE: + case FEATURE_MOUSE_WARP: case FEATURE_CLIPBOARD: case FEATURE_CURSOR_SHAPE: + case FEATURE_CUSTOM_CURSOR_SHAPE: case FEATURE_WINDOW_TRANSPARENCY: + case FEATURE_HIDPI: case FEATURE_SWAP_BUFFERS: case FEATURE_KEEP_SCREEN_ON: - case FEATURE_CLIPBOARD_PRIMARY: + case FEATURE_CLIPBOARD_PRIMARY: { + return true; + } break; + #ifdef DBUS_ENABLED - case FEATURE_NATIVE_DIALOG: + case FEATURE_NATIVE_DIALOG: { + return true; + } break; #endif - case FEATURE_HIDPI: { + +#ifdef SPEECHD_ENABLED + case FEATURE_TEXT_TO_SPEECH: { return true; } break; +#endif default: { return false; @@ -990,36 +1006,9 @@ void DisplayServerWayland::cursor_set_custom_image(const Ref<Resource> &p_cursor wayland_thread.cursor_shape_clear_custom_image(p_shape); } - Ref<Texture2D> texture = p_cursor; - ERR_FAIL_COND(!texture.is_valid()); - Size2i texture_size; - - Ref<AtlasTexture> atlas_texture = texture; - - if (atlas_texture.is_valid()) { - texture_size.width = atlas_texture->get_region().size.x; - texture_size.height = atlas_texture->get_region().size.y; - } else { - texture_size.width = texture->get_width(); - texture_size.height = texture->get_height(); - } - - ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0); - - // NOTE: The Wayland protocol says nothing about cursor size limits, yet if - // the texture is larger than 256x256 it won't show at least on sway. - ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256); - ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height); - ERR_FAIL_COND(texture_size.height == 0 || texture_size.width == 0); - - Ref<Image> image = texture->get_image(); - ERR_FAIL_COND(!image.is_valid()); - - if (image->is_compressed()) { - image = image->duplicate(true); - Error err = image->decompress(); - ERR_FAIL_COND_MSG(err != OK, "Couldn't decompress VRAM-compressed custom mouse cursor image. Switch to a lossless compression mode in the Import dock."); - } + Rect2 atlas_rect; + Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot, atlas_rect); + ERR_FAIL_COND(image.is_null()); CustomCursor &cursor = custom_cursors[p_shape]; @@ -1258,6 +1247,8 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win // Input. Input::get_singleton()->set_event_dispatch_function(dispatch_input_events); + native_menu = memnew(NativeMenu); + #ifdef SPEECHD_ENABLED // Init TTS tts = memnew(TTS_Linux); @@ -1382,6 +1373,12 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win DisplayServerWayland::~DisplayServerWayland() { // TODO: Multiwindow support. + + if (native_menu) { + memdelete(native_menu); + native_menu = nullptr; + } + if (main_window.visible) { #ifdef VULKAN_ENABLED if (rendering_device) { diff --git a/platform/linuxbsd/wayland/display_server_wayland.h b/platform/linuxbsd/wayland/display_server_wayland.h index e42967eb7b..b7d7bee005 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.h +++ b/platform/linuxbsd/wayland/display_server_wayland.h @@ -59,8 +59,6 @@ #include "core/config/project_settings.h" #include "core/input/input.h" -#include "scene/resources/atlas_texture.h" -#include "scene/resources/texture.h" #include "servers/display_server.h" #include <limits.h> @@ -134,6 +132,7 @@ class DisplayServerWayland : public DisplayServer { #ifdef SPEECHD_ENABLED TTS_Linux *tts = nullptr; #endif + NativeMenu *native_menu = nullptr; #if DBUS_ENABLED FreeDesktopPortalDesktop *portal_desktop = nullptr; diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp index ebb21722e2..8167642345 100644 --- a/platform/linuxbsd/wayland/wayland_thread.cpp +++ b/platform/linuxbsd/wayland/wayland_thread.cpp @@ -448,14 +448,11 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re zwp_primary_selection_device_v1_add_listener(ss->wp_primary_selection_device, &wp_primary_selection_device_listener, ss); } -#if 0 - // FIXME: Broken. if (!ss->wp_tablet_seat && registry->wp_tablet_manager) { // Tablet. ss->wp_tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(registry->wp_tablet_manager, wl_seat); zwp_tablet_seat_v2_add_listener(ss->wp_tablet_seat, &wp_tablet_seat_listener, ss); } -#endif registry->wl_seats.push_back(wl_seat); @@ -541,13 +538,11 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re return; } -#if 0 - // FIXME: Broken. if (strcmp(interface, zwp_tablet_manager_v2_interface.name) == 0) { registry->wp_tablet_manager = (struct zwp_tablet_manager_v2 *)wl_registry_bind(wl_registry, name, &zwp_tablet_manager_v2_interface, 1); registry->wp_tablet_manager_name = name; - // This global creates some seats data. Let's do that for the ones already available. + // 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); @@ -558,7 +553,6 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re return; } -#endif } void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) { @@ -820,8 +814,6 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry return; } -#if 0 - // FIXME: Broken. if (name == registry->wp_tablet_manager_name) { if (registry->wp_tablet_manager) { zwp_tablet_manager_v2_destroy(registry->wp_tablet_manager); @@ -835,25 +827,27 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry SeatState *ss = wl_seat_get_seat_state(wl_seat); ERR_FAIL_NULL(ss); - List<struct zwp_tablet_tool_v2 *>::Element *it = ss->tablet_tools.front(); - - while (it) { - zwp_tablet_tool_v2_destroy(it->get()); - ss->tablet_tools.erase(it); + for (struct zwp_tablet_tool_v2 *tool : ss->tablet_tools) { + TabletToolState *state = wp_tablet_tool_get_state(tool); + if (state) { + memdelete(state); + } - it = it->next(); + zwp_tablet_tool_v2_destroy(tool); } + + ss->tablet_tools.clear(); } return; } -#endif { // Iterate through all of the seats to find if any got removed. - List<struct wl_seat *>::Element *it = registry->wl_seats.front(); - while (it) { - struct wl_seat *wl_seat = it->get(); + List<struct wl_seat *>::Element *E = registry->wl_seats.front(); + while (E) { + struct wl_seat *wl_seat = E->get(); + List<struct wl_seat *>::Element *N = E->next(); SeatState *ss = wl_seat_get_seat_state(wl_seat); ERR_FAIL_NULL(ss); @@ -867,28 +861,26 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry wl_data_device_destroy(ss->wl_data_device); } -#if 0 - // FIXME: Broken. if (ss->wp_tablet_seat) { zwp_tablet_seat_v2_destroy(ss->wp_tablet_seat); for (struct zwp_tablet_tool_v2 *tool : ss->tablet_tools) { + TabletToolState *state = wp_tablet_tool_get_state(tool); + if (state) { + memdelete(state); + } + zwp_tablet_tool_v2_destroy(tool); } } - // Let's destroy all tools. - for (struct zwp_tablet_tool_v2 *tool : ss->tablet_tools) { - zwp_tablet_tool_v2_destroy(tool); - } - memdelete(ss); - registry->wl_seats.erase(it); -#endif + + registry->wl_seats.erase(E); return; } - it = it->next(); + E = N; } } @@ -2160,82 +2152,80 @@ void WaylandThread::_wp_primary_selection_source_on_cancelled(void *data, struct } void WaylandThread::_wp_tablet_seat_on_tablet_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_v2 *id) { - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet seat %x on tablet %x added", (size_t)zwp_tablet_seat_v2, (size_t)id)); } void WaylandThread::_wp_tablet_seat_on_tool_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_tool_v2 *id) { SeatState *ss = (SeatState *)data; ERR_FAIL_NULL(ss); - ss->tablet_tools.push_back(id); + TabletToolState *state = memnew(TabletToolState); + state->wl_seat = ss->wl_seat; - zwp_tablet_tool_v2_add_listener(id, &wp_tablet_tool_listener, ss); + wl_proxy_tag_godot((struct wl_proxy *)id); + zwp_tablet_tool_v2_add_listener(id, &wp_tablet_tool_listener, state); - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet seat %x on tool %x added", (size_t)zwp_tablet_seat_v2, (size_t)id)); + ss->tablet_tools.push_back(id); } void WaylandThread::_wp_tablet_seat_on_pad_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id) { - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet seat %x on pad %x added", (size_t)zwp_tablet_seat_v2, (size_t)id)); } void WaylandThread::_wp_tablet_tool_on_type(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t tool_type) { - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on type %d", (size_t)zwp_tablet_tool_v2, tool_type)); + TabletToolState *state = wp_tablet_tool_get_state(zwp_tablet_tool_v2); + + if (state && tool_type == ZWP_TABLET_TOOL_V2_TYPE_ERASER) { + state->is_eraser = true; + } } void WaylandThread::_wp_tablet_tool_on_hardware_serial(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t hardware_serial_hi, uint32_t hardware_serial_lo) { - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on hardware serial %x%x", (size_t)zwp_tablet_tool_v2, hardware_serial_hi, hardware_serial_lo)); } void WaylandThread::_wp_tablet_tool_on_hardware_id_wacom(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t hardware_id_hi, uint32_t hardware_id_lo) { - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on hardware id wacom hardware id %x%x", (size_t)zwp_tablet_tool_v2, hardware_id_hi, hardware_id_lo)); } void WaylandThread::_wp_tablet_tool_on_capability(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t capability) { - SeatState *ss = (SeatState *)data; - ERR_FAIL_NULL(ss); - - if (capability == ZWP_TABLET_TOOL_V2_TYPE_ERASER) { - ss->tablet_tool_data_buffer.is_eraser = true; - } - - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on capability %d", (size_t)zwp_tablet_tool_v2, capability)); } void WaylandThread::_wp_tablet_tool_on_done(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on done", (size_t)zwp_tablet_tool_v2)); } void WaylandThread::_wp_tablet_tool_on_removed(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { - SeatState *ss = (SeatState *)data; - ERR_FAIL_NULL(ss); + TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2); + SeatState *ss = wl_seat_get_seat_state(ts->wl_seat); - List<struct zwp_tablet_tool_v2 *>::Element *it = ss->tablet_tools.front(); + if (!ts || !ss) { + return; + } - while (it) { - struct zwp_tablet_tool_v2 *tool = it->get(); + List<struct zwp_tablet_tool_v2 *>::Element *E = ss->tablet_tools.find(zwp_tablet_tool_v2); - if (tool == zwp_tablet_tool_v2) { - zwp_tablet_tool_v2_destroy(tool); - ss->tablet_tools.erase(it); - break; + if (E && E->get()) { + struct zwp_tablet_tool_v2 *tool = E->get(); + TabletToolState *state = wp_tablet_tool_get_state(tool); + if (state) { + memdelete(state); } - } - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on removed", (size_t)zwp_tablet_tool_v2)); + zwp_tablet_tool_v2_destroy(tool); + ss->tablet_tools.erase(E); + } } void WaylandThread::_wp_tablet_tool_on_proximity_in(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface) { - SeatState *ss = (SeatState *)data; - ERR_FAIL_NULL(ss); + TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2); + SeatState *ss = wl_seat_get_seat_state(ts->wl_seat); + + if (!ts || !ss) { + return; + } WaylandThread *wayland_thread = ss->wayland_thread; ERR_FAIL_NULL(wayland_thread); - ss->tablet_tool_data_buffer.in_proximity = true; - - ss->pointer_enter_serial = serial; - ss->pointed_surface = surface; - ss->last_pointed_surface = surface; + ts->data_pending.proximity_serial = serial; + ts->data_pending.proximal_surface = surface; + ts->last_surface = surface; Ref<WindowEventMessage> msg; msg.instantiate(); @@ -2243,21 +2233,20 @@ void WaylandThread::_wp_tablet_tool_on_proximity_in(void *data, struct zwp_table wayland_thread->push_message(msg); DEBUG_LOG_WAYLAND_THREAD("Tablet tool entered window."); - - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on proximity in serial %d tablet %x surface %x", (size_t)zwp_tablet_tool_v2, serial, (size_t)tablet, (size_t)surface)); } void WaylandThread::_wp_tablet_tool_on_proximity_out(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { - SeatState *ss = (SeatState *)data; - ERR_FAIL_NULL(ss); + TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2); + SeatState *ss = wl_seat_get_seat_state(ts->wl_seat); + + if (!ts || !ss) { + return; + } WaylandThread *wayland_thread = ss->wayland_thread; ERR_FAIL_NULL(wayland_thread); - ss->pointed_surface = nullptr; - ss->tablet_tool_data_buffer.in_proximity = false; - - DEBUG_LOG_WAYLAND_THREAD("Tablet tool left window."); + ts->data_pending.proximal_surface = nullptr; Ref<WindowEventMessage> msg; msg.instantiate(); @@ -2265,16 +2254,18 @@ void WaylandThread::_wp_tablet_tool_on_proximity_out(void *data, struct zwp_tabl wayland_thread->push_message(msg); - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on proximity out", (size_t)zwp_tablet_tool_v2)); + DEBUG_LOG_WAYLAND_THREAD("Tablet tool left window."); } void WaylandThread::_wp_tablet_tool_on_down(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial) { - SeatState *ss = (SeatState *)data; - ERR_FAIL_NULL(ss); + TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2); + + if (!ts) { + return; + } - TabletToolData &td = ss->tablet_tool_data_buffer; + TabletToolData &td = ts->data_pending; - td.touching = true; td.pressed_button_mask.set_flag(mouse_button_to_mask(MouseButton::LEFT)); td.last_button_pressed = MouseButton::LEFT; td.double_click_begun = true; @@ -2282,45 +2273,53 @@ void WaylandThread::_wp_tablet_tool_on_down(void *data, struct zwp_tablet_tool_v // The protocol doesn't cover this, but we can use this funky hack to make // double clicking work. td.button_time = OS::get_singleton()->get_ticks_msec(); - - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on down serial %x", (size_t)zwp_tablet_tool_v2, serial)); } void WaylandThread::_wp_tablet_tool_on_up(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) { - SeatState *ss = (SeatState *)data; - ERR_FAIL_NULL(ss); + TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2); - TabletToolData &td = ss->tablet_tool_data_buffer; + if (!ts) { + return; + } + + TabletToolData &td = ts->data_pending; - td.touching = false; td.pressed_button_mask.clear_flag(mouse_button_to_mask(MouseButton::LEFT)); // The protocol doesn't cover this, but we can use this funky hack to make // double clicking work. td.button_time = OS::get_singleton()->get_ticks_msec(); - - DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on up", (size_t)zwp_tablet_tool_v2)); } void WaylandThread::_wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t x, wl_fixed_t y) { - SeatState *ss = (SeatState *)data; - ERR_FAIL_NULL(ss); + TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2); - WindowState *ws = wl_surface_get_window_state(ss->pointed_surface); + if (!ts) { + return; + } + + WindowState *ws = wl_surface_get_window_state(ts->data_pending.proximal_surface); ERR_FAIL_NULL(ws); - double scale_factor = window_state_get_scale_factor(ws); + TabletToolData &td = ts->data_pending; - TabletToolData &td = ss->tablet_tool_data_buffer; + double scale_factor = window_state_get_scale_factor(ws); + td.position.x = wl_fixed_to_int(x); + td.position.y = wl_fixed_to_int(y); td.position = scale_vector2i(td.position, scale_factor); + + td.motion_time = OS::get_singleton()->get_ticks_msec(); } void WaylandThread::_wp_tablet_tool_on_pressure(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t pressure) { - SeatState *ss = (SeatState *)data; - ERR_FAIL_NULL(ss); + TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2); + + if (!ts) { + return; + } - ss->tablet_tool_data_buffer.pressure = pressure; + ts->data_pending.pressure = pressure; } void WaylandThread::_wp_tablet_tool_on_distance(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t distance) { @@ -2328,11 +2327,16 @@ void WaylandThread::_wp_tablet_tool_on_distance(void *data, struct zwp_tablet_to } void WaylandThread::_wp_tablet_tool_on_tilt(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t tilt_x, wl_fixed_t tilt_y) { - SeatState *ss = (SeatState *)data; - ERR_FAIL_NULL(ss); + TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2); + + if (!ts) { + return; + } - ss->tablet_tool_data_buffer.tilt.x = wl_fixed_to_double(tilt_x); - ss->tablet_tool_data_buffer.tilt.y = wl_fixed_to_double(tilt_y); + TabletToolData &td = ts->data_pending; + + td.tilt.x = wl_fixed_to_double(tilt_x); + td.tilt.y = wl_fixed_to_double(tilt_y); } void WaylandThread::_wp_tablet_tool_on_rotation(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees) { @@ -2348,10 +2352,13 @@ void WaylandThread::_wp_tablet_tool_on_wheel(void *data, struct zwp_tablet_tool_ } void WaylandThread::_wp_tablet_tool_on_button(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial, uint32_t button, uint32_t state) { - SeatState *ss = (SeatState *)data; - ERR_FAIL_NULL(ss); + TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2); - TabletToolData &td = ss->tablet_tool_data_buffer; + if (!ts) { + return; + } + + TabletToolData &td = ts->data_pending; MouseButton mouse_button = MouseButton::NONE; @@ -2381,14 +2388,18 @@ void WaylandThread::_wp_tablet_tool_on_button(void *data, struct zwp_tablet_tool } void WaylandThread::_wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t time) { - SeatState *ss = (SeatState *)data; - ERR_FAIL_NULL(ss); + TabletToolState *ts = wp_tablet_tool_get_state(zwp_tablet_tool_v2); + SeatState *ss = wl_seat_get_seat_state(ts->wl_seat); + + if (!ts || !ss) { + return; + } WaylandThread *wayland_thread = ss->wayland_thread; ERR_FAIL_NULL(wayland_thread); - TabletToolData &old_td = ss->tablet_tool_data; - TabletToolData &td = ss->tablet_tool_data_buffer; + TabletToolData &old_td = ts->data; + TabletToolData &td = ts->data_pending; if (old_td.position != td.position || old_td.tilt != td.tilt || old_td.pressure != td.pressure) { Ref<InputEventMouseMotion> mm; @@ -2411,25 +2422,24 @@ void WaylandThread::_wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_ // straight from the compositor, so we have to normalize them here. // According to the tablet proto spec, tilt is expressed in degrees relative - // to the Z axis of the tablet, so it shouldn't go over 90 degrees, I think. - // TODO: Investigate whether the tilt can go over 90 degrees (it shouldn't). + // to the Z axis of the tablet, so it shouldn't go over 90 degrees either way, + // I think. We'll clamp it just in case. + td.tilt = td.tilt.clamp(Vector2(-90, -90), Vector2(90, 90)); + mm->set_tilt(td.tilt / 90); // The tablet proto spec explicitly says that pressure is defined as a value // between 0 to 65535. mm->set_pressure(td.pressure / (float)65535); - // FIXME: Tool handling is broken. - mm->set_pen_inverted(td.is_eraser); + mm->set_pen_inverted(ts->is_eraser); mm->set_relative(td.position - old_td.position); mm->set_relative_screen_position(mm->get_relative()); - // FIXME: Stop doing this to calculate speed. - // FIXME2: It has been done, port this from the pointer logic once this works again. - Input::get_singleton()->set_mouse_position(td.position); - mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity()); - mm->set_screen_velocity(mm->get_velocity()); + Vector2i pos_delta = td.position - old_td.position; + uint32_t time_delta = td.motion_time - td.motion_time; + mm->set_velocity((Vector2)pos_delta / time_delta); Ref<InputEventMessage> inputev_msg; inputev_msg.instantiate(); @@ -2618,6 +2628,15 @@ WaylandThread::SeatState *WaylandThread::wl_seat_get_seat_state(struct wl_seat * return nullptr; } +// Returns the wp_tablet_tool's `TabletToolState`, otherwise `nullptr`. +// NOTE: This will fail if the output isn't tagged as ours. +WaylandThread::TabletToolState *WaylandThread::wp_tablet_tool_get_state(struct zwp_tablet_tool_v2 *p_tool) { + if (p_tool && wl_proxy_is_godot((wl_proxy *)p_tool)) { + return (TabletToolState *)zwp_tablet_tool_v2_get_user_data(p_tool); + } + + return nullptr; +} // Returns the wl_data_offer's `OfferState`, otherwise `nullptr`. // NOTE: This will fail if the output isn't tagged as ours. WaylandThread::OfferState *WaylandThread::wl_data_offer_get_offer_state(struct wl_data_offer *p_offer) { @@ -4070,14 +4089,16 @@ void WaylandThread::destroy() { zwp_confined_pointer_v1_destroy(ss->wp_confined_pointer); } -#if 0 - // FIXME: Broken. if (ss->wp_tablet_seat) { zwp_tablet_seat_v2_destroy(ss->wp_tablet_seat); } -#endif for (struct zwp_tablet_tool_v2 *tool : ss->tablet_tools) { + TabletToolState *state = wp_tablet_tool_get_state(tool); + if (state) { + memdelete(state); + } + zwp_tablet_tool_v2_destroy(tool); } diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h index f3e3c3a2ac..d49f0c9d34 100644 --- a/platform/linuxbsd/wayland/wayland_thread.h +++ b/platform/linuxbsd/wayland/wayland_thread.h @@ -308,7 +308,7 @@ public: struct TabletToolData { Point2i position; - Vector2i tilt; + Vector2 tilt; uint32_t pressure = 0; BitField<MouseButtonMask> pressed_button_mask; @@ -322,10 +322,20 @@ public: // be used as a mouse...), but we'll hack one in with the current ticks. uint64_t button_time = 0; + uint64_t motion_time = 0; + + uint32_t proximity_serial = 0; + struct wl_surface *proximal_surface = nullptr; + }; + + struct TabletToolState { + struct wl_seat *wl_seat = nullptr; + + struct wl_surface *last_surface = nullptr; bool is_eraser = false; - bool in_proximity = false; - bool touching = false; + TabletToolData data_pending; + TabletToolData data; }; struct OfferState { @@ -425,9 +435,6 @@ public: struct zwp_tablet_seat_v2 *wp_tablet_seat = nullptr; List<struct zwp_tablet_tool_v2 *> tablet_tools; - - TabletToolData tablet_tool_data_buffer; - TabletToolData tablet_tool_data; }; struct CustomCursor { @@ -855,6 +862,7 @@ public: static WindowState *wl_surface_get_window_state(struct wl_surface *p_surface); static ScreenState *wl_output_get_screen_state(struct wl_output *p_output); static SeatState *wl_seat_get_seat_state(struct wl_seat *p_seat); + static TabletToolState *wp_tablet_tool_get_state(struct zwp_tablet_tool_v2 *p_tool); static OfferState *wl_data_offer_get_offer_state(struct wl_data_offer *p_offer); static OfferState *wp_primary_selection_offer_get_offer_state(struct zwp_primary_selection_offer_v1 *p_offer); diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 35bfe81827..7e7c791e7f 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -41,7 +41,6 @@ #include "core/string/ustring.h" #include "drivers/png/png_driver_common.h" #include "main/main.h" -#include "scene/resources/atlas_texture.h" #if defined(VULKAN_ENABLED) #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" @@ -110,6 +109,11 @@ static String get_atom_name(Display *p_disp, Atom p_atom) { bool DisplayServerX11::has_feature(Feature p_feature) const { switch (p_feature) { +#ifndef DISABLE_DEPRECATED + case FEATURE_GLOBAL_MENU: { + return (native_menu && native_menu->has_feature(NativeMenu::FEATURE_GLOBAL_MENU)); + } break; +#endif case FEATURE_SUBWINDOWS: #ifdef TOUCH_ENABLED case FEATURE_TOUCHSCREEN: @@ -3064,39 +3068,10 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu cursors_cache.erase(p_shape); } - Ref<Texture2D> texture = p_cursor; - ERR_FAIL_COND(!texture.is_valid()); - Ref<AtlasTexture> atlas_texture = p_cursor; - Size2i texture_size; - Rect2i atlas_rect; - - if (atlas_texture.is_valid()) { - texture = atlas_texture->get_atlas(); - - atlas_rect.size.width = texture->get_width(); - atlas_rect.size.height = texture->get_height(); - atlas_rect.position.x = atlas_texture->get_region().position.x; - atlas_rect.position.y = atlas_texture->get_region().position.y; - - texture_size.width = atlas_texture->get_region().size.x; - texture_size.height = atlas_texture->get_region().size.y; - } else { - texture_size.width = texture->get_width(); - texture_size.height = texture->get_height(); - } - - ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0); - ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256); - ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height); - - Ref<Image> image = texture->get_image(); - - ERR_FAIL_COND(!image.is_valid()); - if (image->is_compressed()) { - image = image->duplicate(true); - Error err = image->decompress(); - ERR_FAIL_COND_MSG(err != OK, "Couldn't decompress VRAM-compressed custom mouse cursor image. Switch to a lossless compression mode in the Import dock."); - } + Rect2 atlas_rect; + Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot, atlas_rect); + ERR_FAIL_COND(image.is_null()); + Vector2i texture_size = image->get_size(); // Create the cursor structure XcursorImage *cursor_image = XcursorImageCreate(texture_size.width, texture_size.height); @@ -3115,7 +3090,7 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu 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_texture.is_valid()) { + 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); } @@ -5795,6 +5770,8 @@ static ::XIMStyle _get_best_xim_style(const ::XIMStyle &p_style_a, const ::XIMSt 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) { KeyMappingX11::initialize(); + native_menu = memnew(NativeMenu); + #ifdef SOWRAP_ENABLED #ifdef DEBUG_ENABLED int dylibloader_verbose = 1; @@ -6387,6 +6364,11 @@ DisplayServerX11::~DisplayServerX11() { events_thread_done.set(); events_thread.wait_to_finish(); + if (native_menu) { + memdelete(native_menu); + native_menu = nullptr; + } + //destroy all windows for (KeyValue<WindowID, WindowData> &E : windows) { #if defined(RD_ENABLED) diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index a5cbe34d26..715a8e48e6 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -156,6 +156,7 @@ class DisplayServerX11 : public DisplayServer { #ifdef SPEECHD_ENABLED TTS_Linux *tts = nullptr; #endif + NativeMenu *native_menu = nullptr; #if defined(DBUS_ENABLED) FreeDesktopPortalDesktop *portal_desktop = nullptr; |