feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -1,4 +1,5 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
Import("env")
@ -10,16 +11,16 @@ if env["use_sowrap"]:
WAYLAND_BUILDERS_SOWRAP = {
"WAYLAND_API_HEADER": Builder(
action=Action(
r"wayland-scanner -c client-header < ${SOURCE} | sed 's:wayland-client-core\.h:../dynwrappers/wayland-client-core-so_wrap\.h:' > ${TARGET}",
'Generating Wayland client header: "${TARGET}"',
action=env.Run(
r"wayland-scanner -c client-header < ${SOURCE} | "
r"sed 's:wayland-client-core\.h:../dynwrappers/wayland-client-core-so_wrap\.h:' > ${TARGET}",
),
single_source=True,
),
"WAYLAND_API_CODE": Builder(
action=Action(
r"wayland-scanner -c private-code < ${SOURCE} | sed 's:wayland-util\.h:../dynwrappers/wayland-client-core-so_wrap\.h:' > ${TARGET}",
'Generating Wayland protocol marshaling code: "${TARGET}"',
action=env.Run(
r"wayland-scanner -c private-code < ${SOURCE} | "
r"sed 's:wayland-util\.h:../dynwrappers/wayland-client-core-so_wrap\.h:' > ${TARGET}",
),
single_source=True,
),
@ -28,155 +29,140 @@ if env["use_sowrap"]:
else:
WAYLAND_BUILDERS = {
"WAYLAND_API_HEADER": Builder(
action=Action(
r"wayland-scanner -c client-header < ${SOURCE} > ${TARGET}",
'Generating Wayland client header: "${TARGET}"',
),
action=env.Run(r"wayland-scanner -c client-header < ${SOURCE} > ${TARGET}"),
single_source=True,
),
"WAYLAND_API_CODE": Builder(
action=Action(
r"wayland-scanner -c private-code < ${SOURCE} > ${TARGET}",
'Generating Wayland protocol marshaling code: "${TARGET}"',
),
action=env.Run(r"wayland-scanner -c private-code < ${SOURCE} > ${TARGET}"),
single_source=True,
),
}
env.Append(BUILDERS=WAYLAND_BUILDERS)
env.WAYLAND_API_HEADER(target="protocol/wayland.gen.h", source="#thirdparty/wayland/protocol/wayland.xml")
env.WAYLAND_API_CODE(target="protocol/wayland.gen.c", source="#thirdparty/wayland/protocol/wayland.xml")
env.WAYLAND_API_HEADER(
target="protocol/viewporter.gen.h", source="#thirdparty/wayland-protocols/stable/viewporter/viewporter.xml"
)
env.WAYLAND_API_CODE(
target="protocol/viewporter.gen.c", source="#thirdparty/wayland-protocols/stable/viewporter/viewporter.xml"
env.NoCache(
env.WAYLAND_API_HEADER("protocol/wayland.gen.h", "#thirdparty/wayland/protocol/wayland.xml"),
env.WAYLAND_API_CODE("protocol/wayland.gen.c", "#thirdparty/wayland/protocol/wayland.xml"),
env.WAYLAND_API_HEADER(
"protocol/viewporter.gen.h", "#thirdparty/wayland-protocols/stable/viewporter/viewporter.xml"
),
env.WAYLAND_API_CODE("protocol/viewporter.gen.c", "#thirdparty/wayland-protocols/stable/viewporter/viewporter.xml"),
env.WAYLAND_API_HEADER(
"protocol/fractional_scale.gen.h",
"#thirdparty/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml",
),
env.WAYLAND_API_CODE(
"protocol/fractional_scale.gen.c",
"#thirdparty/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml",
),
env.WAYLAND_API_HEADER("protocol/xdg_shell.gen.h", "#thirdparty/wayland-protocols/stable/xdg-shell/xdg-shell.xml"),
env.WAYLAND_API_CODE("protocol/xdg_shell.gen.c", "#thirdparty/wayland-protocols/stable/xdg-shell/xdg-shell.xml"),
env.WAYLAND_API_HEADER(
"protocol/xdg_decoration.gen.h",
"#thirdparty/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml",
),
env.WAYLAND_API_CODE(
"protocol/xdg_decoration.gen.c",
"#thirdparty/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml",
),
env.WAYLAND_API_HEADER(
"protocol/xdg_activation.gen.h",
"#thirdparty/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml",
),
env.WAYLAND_API_CODE(
"protocol/xdg_activation.gen.c",
"#thirdparty/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml",
),
env.WAYLAND_API_HEADER(
"protocol/relative_pointer.gen.h",
"#thirdparty/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml",
),
env.WAYLAND_API_CODE(
"protocol/relative_pointer.gen.c",
"#thirdparty/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml",
),
env.WAYLAND_API_HEADER(
"protocol/pointer_constraints.gen.h",
"#thirdparty/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml",
),
env.WAYLAND_API_CODE(
"protocol/pointer_constraints.gen.c",
"#thirdparty/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml",
),
env.WAYLAND_API_HEADER(
"protocol/pointer_gestures.gen.h",
"#thirdparty/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml",
),
env.WAYLAND_API_CODE(
"protocol/pointer_gestures.gen.c",
"#thirdparty/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml",
),
env.WAYLAND_API_HEADER(
"protocol/primary_selection.gen.h",
"#thirdparty/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml",
),
env.WAYLAND_API_CODE(
"protocol/primary_selection.gen.c",
"#thirdparty/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml",
),
env.WAYLAND_API_HEADER(
"protocol/idle_inhibit.gen.h",
"#thirdparty/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml",
),
env.WAYLAND_API_CODE(
"protocol/idle_inhibit.gen.c",
"#thirdparty/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml",
),
env.WAYLAND_API_HEADER(
"protocol/tablet.gen.h",
"#thirdparty/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml",
),
env.WAYLAND_API_CODE(
"protocol/tablet.gen.c",
"#thirdparty/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml",
),
env.WAYLAND_API_HEADER(
"protocol/text_input.gen.h",
"#thirdparty/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml",
),
env.WAYLAND_API_CODE(
"protocol/text_input.gen.c",
"#thirdparty/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml",
),
env.WAYLAND_API_HEADER(
"protocol/xdg_foreign_v1.gen.h",
"#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml",
),
env.WAYLAND_API_CODE(
"protocol/xdg_foreign_v1.gen.c",
"#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml",
),
env.WAYLAND_API_HEADER(
"protocol/xdg_foreign_v2.gen.h",
"#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v2.xml",
),
env.WAYLAND_API_CODE(
"protocol/xdg_foreign_v2.gen.c",
"#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v2.xml",
),
env.WAYLAND_API_HEADER(
"protocol/xdg_system_bell.gen.h",
"#thirdparty/wayland-protocols/staging/xdg-system-bell/xdg-system-bell-v1.xml",
),
env.WAYLAND_API_CODE(
"protocol/xdg_system_bell.gen.c",
"#thirdparty/wayland-protocols/staging/xdg-system-bell/xdg-system-bell-v1.xml",
),
)
env.WAYLAND_API_HEADER(
target="protocol/fractional_scale.gen.h",
source="#thirdparty/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml",
)
env.WAYLAND_API_CODE(
target="protocol/fractional_scale.gen.c",
source="#thirdparty/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml",
)
env.WAYLAND_API_HEADER(
target="protocol/xdg_shell.gen.h", source="#thirdparty/wayland-protocols/stable/xdg-shell/xdg-shell.xml"
)
env.WAYLAND_API_CODE(
target="protocol/xdg_shell.gen.c", source="#thirdparty/wayland-protocols/stable/xdg-shell/xdg-shell.xml"
)
env.WAYLAND_API_HEADER(
target="protocol/xdg_decoration.gen.h",
source="#thirdparty/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml",
)
env.WAYLAND_API_CODE(
target="protocol/xdg_decoration.gen.c",
source="#thirdparty/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml",
)
env.WAYLAND_API_HEADER(
target="protocol/xdg_activation.gen.h",
source="#thirdparty/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml",
)
env.WAYLAND_API_CODE(
target="protocol/xdg_activation.gen.c",
source="#thirdparty/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml",
)
env.WAYLAND_API_HEADER(
target="protocol/relative_pointer.gen.h",
source="#thirdparty/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml",
)
env.WAYLAND_API_CODE(
target="protocol/relative_pointer.gen.c",
source="#thirdparty/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml",
)
env.WAYLAND_API_HEADER(
target="protocol/pointer_constraints.gen.h",
source="#thirdparty/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml",
)
env.WAYLAND_API_CODE(
target="protocol/pointer_constraints.gen.c",
source="#thirdparty/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml",
)
env.WAYLAND_API_HEADER(
target="protocol/pointer_gestures.gen.h",
source="#thirdparty/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml",
)
env.WAYLAND_API_CODE(
target="protocol/pointer_gestures.gen.c",
source="#thirdparty/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml",
)
env.WAYLAND_API_HEADER(
target="protocol/primary_selection.gen.h",
source="#thirdparty/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml",
)
env.WAYLAND_API_CODE(
target="protocol/primary_selection.gen.c",
source="#thirdparty/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml",
)
env.WAYLAND_API_HEADER(
target="protocol/idle_inhibit.gen.h",
source="#thirdparty/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml",
)
env.WAYLAND_API_CODE(
target="protocol/idle_inhibit.gen.c",
source="#thirdparty/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml",
)
env.WAYLAND_API_HEADER(
target="protocol/tablet.gen.h",
source="#thirdparty/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml",
)
env.WAYLAND_API_CODE(
target="protocol/tablet.gen.c",
source="#thirdparty/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml",
)
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",
)
env.WAYLAND_API_CODE(
target="protocol/xdg_foreign.gen.c",
source="#thirdparty/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml",
)
source_files = [
"protocol/wayland.gen.c",
"protocol/viewporter.gen.c",
"protocol/fractional_scale.gen.c",
"protocol/xdg_shell.gen.c",
"protocol/xdg_foreign.gen.c",
"protocol/xdg_system_bell.gen.c",
"protocol/xdg_foreign_v1.gen.c",
"protocol/xdg_foreign_v2.gen.c",
"protocol/xdg_decoration.gen.c",
"protocol/xdg_activation.gen.c",
"protocol/relative_pointer.gen.c",

View file

@ -209,6 +209,7 @@ bool DisplayServerWayland::has_feature(Feature p_feature) const {
case FEATURE_SWAP_BUFFERS:
case FEATURE_KEEP_SCREEN_ON:
case FEATURE_IME:
case FEATURE_WINDOW_DRAG:
case FEATURE_CLIPBOARD_PRIMARY: {
return true;
} break;
@ -216,8 +217,10 @@ bool DisplayServerWayland::has_feature(Feature p_feature) const {
//case FEATURE_NATIVE_DIALOG:
//case FEATURE_NATIVE_DIALOG_INPUT:
#ifdef DBUS_ENABLED
case FEATURE_NATIVE_DIALOG_FILE: {
return true;
case FEATURE_NATIVE_DIALOG_FILE:
case FEATURE_NATIVE_DIALOG_FILE_EXTRA:
case FEATURE_NATIVE_DIALOG_FILE_MIME: {
return (portal_desktop && portal_desktop->is_supported() && portal_desktop->is_file_chooser_supported());
} break;
#endif
@ -279,10 +282,13 @@ void DisplayServerWayland::tts_stop() {
#ifdef DBUS_ENABLED
bool DisplayServerWayland::is_dark_mode_supported() const {
return portal_desktop->is_supported();
return portal_desktop && portal_desktop->is_supported() && portal_desktop->is_settings_supported();
}
bool DisplayServerWayland::is_dark_mode() const {
if (!is_dark_mode_supported()) {
return false;
}
switch (portal_desktop->get_appearance_color_scheme()) {
case 1:
// Prefers dark theme.
@ -318,28 +324,28 @@ Error DisplayServerWayland::file_dialog_with_options_show(const String &p_title,
#endif
void DisplayServerWayland::mouse_set_mode(MouseMode p_mode) {
if (p_mode == mouse_mode) {
void DisplayServerWayland::beep() const {
wayland_thread.beep();
}
void DisplayServerWayland::_mouse_update_mode() {
MouseMode wanted_mouse_mode = mouse_mode_override_enabled
? mouse_mode_override
: mouse_mode_base;
if (wanted_mouse_mode == mouse_mode) {
return;
}
MutexLock mutex_lock(wayland_thread.mutex);
bool show_cursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
bool show_cursor = (wanted_mouse_mode == MOUSE_MODE_VISIBLE || wanted_mouse_mode == MOUSE_MODE_CONFINED);
if (show_cursor) {
if (custom_cursors.has(cursor_shape)) {
wayland_thread.cursor_set_custom_shape(cursor_shape);
} else {
wayland_thread.cursor_set_shape(cursor_shape);
}
} else {
wayland_thread.cursor_hide();
}
wayland_thread.cursor_set_visible(show_cursor);
WaylandThread::PointerConstraint constraint = WaylandThread::PointerConstraint::NONE;
switch (p_mode) {
switch (wanted_mouse_mode) {
case DisplayServer::MOUSE_MODE_CAPTURED: {
constraint = WaylandThread::PointerConstraint::LOCKED;
} break;
@ -355,13 +361,47 @@ void DisplayServerWayland::mouse_set_mode(MouseMode p_mode) {
wayland_thread.pointer_set_constraint(constraint);
mouse_mode = p_mode;
mouse_mode = wanted_mouse_mode;
}
void DisplayServerWayland::mouse_set_mode(MouseMode p_mode) {
ERR_FAIL_INDEX(p_mode, MouseMode::MOUSE_MODE_MAX);
if (p_mode == mouse_mode_base) {
return;
}
mouse_mode_base = p_mode;
_mouse_update_mode();
}
DisplayServerWayland::MouseMode DisplayServerWayland::mouse_get_mode() const {
return mouse_mode;
}
void DisplayServerWayland::mouse_set_mode_override(MouseMode p_mode) {
ERR_FAIL_INDEX(p_mode, MouseMode::MOUSE_MODE_MAX);
if (p_mode == mouse_mode_override) {
return;
}
mouse_mode_override = p_mode;
_mouse_update_mode();
}
DisplayServerWayland::MouseMode DisplayServerWayland::mouse_get_mode_override() const {
return mouse_mode_override;
}
void DisplayServerWayland::mouse_set_mode_override_enabled(bool p_override_enabled) {
if (p_override_enabled == mouse_mode_override_enabled) {
return;
}
mouse_mode_override_enabled = p_override_enabled;
_mouse_update_mode();
}
bool DisplayServerWayland::mouse_is_mode_override_enabled() const {
return mouse_mode_override_enabled;
}
// NOTE: This is hacked together (and not guaranteed to work in the first place)
// as for some reason the there's no proper way to ask the compositor to warp
// the pointer, although, at the time of writing, there's a proposal for a
@ -480,7 +520,7 @@ String DisplayServerWayland::clipboard_get_primary() const {
for (String mime : text_mimes) {
if (wayland_thread.primary_has_mime(mime)) {
print_verbose(vformat("Selecting media type \"%s\" from offered types.", mime));
wayland_thread.primary_get_mime(mime);
data = wayland_thread.primary_get_mime(mime);
break;
}
}
@ -635,6 +675,18 @@ int64_t DisplayServerWayland::window_get_native_handle(HandleType p_handle_type,
}
return 0;
} break;
case EGL_DISPLAY: {
if (egl_manager) {
return (int64_t)egl_manager->get_display(p_window);
}
return 0;
}
case EGL_CONFIG: {
if (egl_manager) {
return (int64_t)egl_manager->get_config(p_window);
}
return 0;
}
#endif // GLES3_ENABLED
default: {
@ -896,11 +948,11 @@ bool DisplayServerWayland::window_is_focused(WindowID p_window_id) const {
}
bool DisplayServerWayland::window_can_draw(DisplayServer::WindowID p_window_id) const {
return !suspended;
return suspend_state == SuspendState::NONE;
}
bool DisplayServerWayland::can_any_window_draw() const {
return !suspended;
return suspend_state == SuspendState::NONE;
}
void DisplayServerWayland::window_set_ime_active(const bool p_active, DisplayServer::WindowID p_window_id) {
@ -977,6 +1029,19 @@ DisplayServer::VSyncMode DisplayServerWayland::window_get_vsync_mode(DisplayServ
return DisplayServer::VSYNC_ENABLED;
}
void DisplayServerWayland::window_start_drag(WindowID p_window) {
MutexLock mutex_lock(wayland_thread.mutex);
wayland_thread.window_start_drag(p_window);
}
void DisplayServerWayland::window_start_resize(WindowResizeEdge p_edge, WindowID p_window) {
MutexLock mutex_lock(wayland_thread.mutex);
ERR_FAIL_INDEX(int(p_edge), WINDOW_EDGE_MAX);
wayland_thread.window_start_resize(p_edge, p_window);
}
void DisplayServerWayland::cursor_set_shape(CursorShape p_shape) {
ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
@ -993,11 +1058,7 @@ void DisplayServerWayland::cursor_set_shape(CursorShape p_shape) {
return;
}
if (custom_cursors.has(p_shape)) {
wayland_thread.cursor_set_custom_shape(p_shape);
} else {
wayland_thread.cursor_set_shape(p_shape);
}
wayland_thread.cursor_set_shape(p_shape);
}
DisplayServerWayland::CursorShape DisplayServerWayland::cursor_get_shape() const {
@ -1009,18 +1070,13 @@ DisplayServerWayland::CursorShape DisplayServerWayland::cursor_get_shape() const
void DisplayServerWayland::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
MutexLock mutex_lock(wayland_thread.mutex);
bool visible = (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED);
if (p_cursor.is_valid()) {
HashMap<CursorShape, CustomCursor>::Iterator cursor_c = custom_cursors.find(p_shape);
if (cursor_c) {
if (cursor_c->value.rid == p_cursor->get_rid() && cursor_c->value.hotspot == p_hotspot) {
if (cursor_c->value.resource == p_cursor && cursor_c->value.hotspot == p_hotspot) {
// We have a cached cursor. Nice.
if (visible) {
wayland_thread.cursor_set_custom_shape(p_shape);
}
wayland_thread.cursor_set_shape(p_shape);
return;
}
@ -1034,25 +1090,23 @@ void DisplayServerWayland::cursor_set_custom_image(const Ref<Resource> &p_cursor
CustomCursor &cursor = custom_cursors[p_shape];
cursor.rid = p_cursor->get_rid();
cursor.resource = p_cursor;
cursor.hotspot = p_hotspot;
wayland_thread.cursor_shape_set_custom_image(p_shape, image, p_hotspot);
if (visible) {
wayland_thread.cursor_set_custom_shape(p_shape);
}
wayland_thread.cursor_set_shape(p_shape);
} else {
// Clear cache and reset to default system cursor.
if (cursor_shape == p_shape && visible) {
wayland_thread.cursor_shape_clear_custom_image(p_shape);
if (cursor_shape == p_shape) {
wayland_thread.cursor_set_shape(p_shape);
}
if (custom_cursors.has(p_shape)) {
custom_cursors.erase(p_shape);
}
wayland_thread.cursor_shape_clear_custom_image(p_shape);
}
}
@ -1120,16 +1174,21 @@ void DisplayServerWayland::try_suspend() {
if (emulate_vsync) {
bool frame = wayland_thread.wait_frame_suspend_ms(1000);
if (!frame) {
suspended = true;
}
} else {
if (wayland_thread.is_suspended()) {
suspended = true;
suspend_state = SuspendState::TIMEOUT;
}
}
if (suspended) {
DEBUG_LOG_WAYLAND("Window suspended.");
// If we suspended by capability, we'll know with this check. We must do this
// after `wait_frame_suspend_ms` as it progressively dispatches the event queue
// during the "timeout".
if (wayland_thread.is_suspended()) {
suspend_state = SuspendState::CAPABILITY;
}
if (suspend_state == SuspendState::TIMEOUT) {
DEBUG_LOG_WAYLAND("Suspending. Reason: timeout.");
} else if (suspend_state == SuspendState::CAPABILITY) {
DEBUG_LOG_WAYLAND("Suspending. Reason: capability.");
}
}
@ -1156,6 +1215,7 @@ void DisplayServerWayland::process_events() {
if (OS::get_singleton()->get_main_loop()) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
}
Input::get_singleton()->release_pressed_events();
}
}
@ -1205,16 +1265,18 @@ void DisplayServerWayland::process_events() {
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;
if (ime_text != ime_update_msg->text || ime_selection != ime_update_msg->selection) {
ime_text = ime_update_msg->text;
ime_selection = ime_update_msg->selection;
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
}
}
}
wayland_thread.keyboard_echo_keys();
if (!suspended) {
if (suspend_state == SuspendState::NONE) {
// Due to the way legacy suspension works, we have to treat low processor
// usage mode very differently than the regular one.
if (OS::get_singleton()->is_in_low_processor_usage_mode()) {
@ -1238,9 +1300,27 @@ void DisplayServerWayland::process_events() {
} else {
try_suspend();
}
} else if (!wayland_thread.is_suspended() || wayland_thread.get_reset_frame()) {
// At last, a sign of life! We're no longer suspended.
suspended = false;
} else {
if (suspend_state == SuspendState::CAPABILITY) {
// If we suspended by capability we can assume that it will be reset when
// the compositor wants us to repaint.
if (!wayland_thread.is_suspended()) {
suspend_state = SuspendState::NONE;
DEBUG_LOG_WAYLAND("Unsuspending from capability.");
}
} else if (suspend_state == SuspendState::TIMEOUT) {
// Certain compositors might not report the "suspended" wm_capability flag.
// Because of this we'll wake up at the next frame event, indicating the
// desire for the compositor to let us repaint.
if (wayland_thread.get_reset_frame()) {
suspend_state = SuspendState::NONE;
DEBUG_LOG_WAYLAND("Unsuspending from timeout.");
}
}
// Since we're not rendering, nothing is committing the windows'
// surfaces. We have to do it ourselves.
wayland_thread.commit_surfaces();
}
#ifdef DBUS_ENABLED
@ -1305,8 +1385,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, 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));
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, int64_t p_parent_window, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerWayland(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, p_context, p_parent_window, r_error));
if (r_error != OK) {
ERR_PRINT("Can't create the Wayland display server.");
memdelete(ds);
@ -1316,7 +1396,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, Context p_context, 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, int64_t p_parent_window, Error &r_error) {
#ifdef GLES3_ENABLED
#ifdef SOWRAP_ENABLED
#ifdef DEBUG_ENABLED
@ -1349,23 +1429,50 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
rendering_driver = p_rendering_driver;
bool driver_found = false;
String executable_name = OS::get_singleton()->get_executable_path().get_file();
#ifdef RD_ENABLED
#ifdef VULKAN_ENABLED
if (rendering_driver == "vulkan") {
rendering_context = memnew(RenderingContextDriverVulkanWayland);
}
#endif
#endif // VULKAN_ENABLED
if (rendering_context) {
if (rendering_context->initialize() != OK) {
ERR_PRINT(vformat("Could not initialize %s", rendering_driver));
memdelete(rendering_context);
rendering_context = nullptr;
r_error = ERR_CANT_CREATE;
return;
#if defined(GLES3_ENABLED)
bool fallback_to_opengl3 = GLOBAL_GET("rendering/rendering_device/fallback_to_opengl3");
if (fallback_to_opengl3 && rendering_driver != "opengl3") {
WARN_PRINT("Your video card drivers seem not to support the required Vulkan version, switching to OpenGL 3.");
rendering_driver = "opengl3";
OS::get_singleton()->set_current_rendering_method("gl_compatibility");
OS::get_singleton()->set_current_rendering_driver_name(rendering_driver);
} else
#endif // GLES3_ENABLED
{
r_error = ERR_CANT_CREATE;
if (p_rendering_driver == "vulkan") {
OS::get_singleton()->alert(
vformat("Your video card drivers seem not to support the required Vulkan version.\n\n"
"If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n"
"You can enable the OpenGL 3 driver by starting the engine from the\n"
"command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n"
"If you recently updated your video card drivers, try rebooting.",
executable_name),
"Unable to initialize Vulkan video driver");
}
ERR_FAIL_MSG(vformat("Could not initialize %s", rendering_driver));
}
}
driver_found = true;
}
#endif
#endif // RD_ENABLED
#ifdef GLES3_ENABLED
if (rendering_driver == "opengl3" || rendering_driver == "opengl3_es") {
@ -1429,30 +1536,58 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
if (fallback) {
WARN_PRINT("Your video card drivers seem not to support the required OpenGL version, switching to OpenGLES.");
rendering_driver = "opengl3_es";
OS::get_singleton()->set_current_rendering_driver_name(rendering_driver);
} else {
r_error = ERR_UNAVAILABLE;
OS::get_singleton()->alert(
vformat("Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n"
"If possible, consider updating your video card drivers or using the Vulkan driver.\n\n"
"You can enable the Vulkan driver by starting the engine from the\n"
"command line with the command:\n\n \"%s\" --rendering-driver vulkan\n\n"
"If you recently updated your video card drivers, try rebooting.",
executable_name),
"Unable to initialize OpenGL video driver");
ERR_FAIL_MSG("Could not initialize OpenGL.");
}
} else {
RasterizerGLES3::make_current(true);
driver_found = true;
}
}
if (rendering_driver == "opengl3_es") {
egl_manager = memnew(EGLManagerWaylandGLES);
if (egl_manager->initialize(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;
r_error = ERR_CANT_CREATE;
ERR_FAIL_MSG("Could not initialize GLES3.");
OS::get_singleton()->alert(
vformat("Your video card drivers seem not to support the required OpenGL ES 3.0 version.\n\n"
"If possible, consider updating your video card drivers or using the Vulkan driver.\n\n"
"You can enable the Vulkan driver by starting the engine from the\n"
"command line with the command:\n\n \"%s\" --rendering-driver vulkan\n\n"
"If you recently updated your video card drivers, try rebooting.",
executable_name),
"Unable to initialize OpenGL ES video driver");
ERR_FAIL_MSG("Could not initialize OpenGL ES.");
}
RasterizerGLES3::make_current(false);
driver_found = true;
}
}
#endif // GLES3_ENABLED
if (!driver_found) {
r_error = ERR_UNAVAILABLE;
ERR_FAIL_MSG("Video driver not found.");
}
cursor_set_shape(CURSOR_BUSY);
WindowData &wd = main_window;
@ -1481,12 +1616,12 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
RendererCompositorRD::make_current();
}
#endif
#endif // RD_ENABLED
#ifdef DBUS_ENABLED
portal_desktop = memnew(FreeDesktopPortalDesktop);
screensaver = memnew(FreeDesktopScreenSaver);
#endif
#endif // DBUS_ENABLED
screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));

View file

@ -101,12 +101,22 @@ class DisplayServerWayland : public DisplayServer {
};
struct CustomCursor {
RID rid;
Ref<Resource> resource;
Point2i hotspot;
};
enum class SuspendState {
NONE, // Unsuspended.
TIMEOUT, // Legacy fallback.
CAPABILITY, // New "suspended" wm_capability flag.
};
CursorShape cursor_shape = CURSOR_ARROW;
DisplayServer::MouseMode mouse_mode = DisplayServer::MOUSE_MODE_VISIBLE;
DisplayServer::MouseMode mouse_mode_base = MOUSE_MODE_VISIBLE;
DisplayServer::MouseMode mouse_mode_override = MOUSE_MODE_VISIBLE;
bool mouse_mode_override_enabled = false;
void _mouse_update_mode();
HashMap<CursorShape, CustomCursor> custom_cursors;
@ -118,7 +128,7 @@ class DisplayServerWayland : public DisplayServer {
String ime_text;
Vector2i ime_selection;
bool suspended = false;
SuspendState suspend_state = SuspendState::NONE;
bool emulate_vsync = false;
String rendering_driver;
@ -181,8 +191,14 @@ public:
virtual Error file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) override;
#endif
virtual void beep() const override;
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
virtual void mouse_set_mode_override(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode_override() const override;
virtual void mouse_set_mode_override_enabled(bool p_override_enabled) override;
virtual bool mouse_is_mode_override_enabled() const override;
virtual void warp_mouse(const Point2i &p_to) override;
virtual Point2i mouse_get_position() const override;
@ -270,6 +286,9 @@ public:
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;
virtual void window_start_drag(WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_start_resize(WindowResizeEdge p_edge, WindowID p_window) override;
virtual void cursor_set_shape(CursorShape p_shape) override;
virtual CursorShape cursor_get_shape() const override;
virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) override;
@ -290,12 +309,12 @@ public:
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 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, int64_t p_parent_window, 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, Context p_context, 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, int64_t p_parent_window, Error &r_error);
~DisplayServerWayland();
};

View file

@ -1,7 +1,7 @@
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
// generated by ./generate-wrapper.py 0.3 on 2022-12-12 10:55:19
// flags: ./generate-wrapper.py --include /usr/include/libdecor-0/libdecor.h --sys-include <libdecor-0/libdecor.h> --soname libdecor-0.so.0 --init-name libdecor --output-header libdecor-so_wrap.h --output-implementation libdecor-so_wrap.c --omit-prefix wl_
// flags: ./generate-wrapper.py --include /usr/include/libdecor-0/libdecor.h --sys-include <libdecor.h> --soname libdecor-0.so.0 --init-name libdecor --output-header libdecor-so_wrap.h --output-implementation libdecor-so_wrap.c --omit-prefix wl_
//
// EDIT: This has been handpatched to properly report the pointer type of the window_state argument of libdecor_configuration_get_window_state.
#include <stdint.h>
@ -45,7 +45,7 @@
#define libdecor_state_free libdecor_state_free_dylibloader_orig_libdecor
#define libdecor_configuration_get_content_size libdecor_configuration_get_content_size_dylibloader_orig_libdecor
#define libdecor_configuration_get_window_state libdecor_configuration_get_window_state_dylibloader_orig_libdecor
#include <libdecor-0/libdecor.h>
#include <libdecor.h>
#undef libdecor_unref
#undef libdecor_new
#undef libdecor_get_fd

View file

@ -3,7 +3,7 @@
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
// generated by ./generate-wrapper.py 0.3 on 2022-12-12 10:55:19
// flags: ./generate-wrapper.py --include /usr/include/libdecor-0/libdecor.h --sys-include <libdecor-0/libdecor.h> --soname libdecor-0.so.0 --init-name libdecor --output-header libdecor-so_wrap.h --output-implementation libdecor-so_wrap.c --omit-prefix wl_
// flags: ./generate-wrapper.py --include /usr/include/libdecor-0/libdecor.h --sys-include <libdecor.h> --soname libdecor-0.so.0 --init-name libdecor --output-header libdecor-so_wrap.h --output-implementation libdecor-so_wrap.c --omit-prefix wl_
//
// EDIT: This has been handpatched to properly report the pointer type of the window_state argument of libdecor_configuration_get_window_state.
#include <stdint.h>
@ -47,7 +47,7 @@
#define libdecor_state_free libdecor_state_free_dylibloader_orig_libdecor
#define libdecor_configuration_get_content_size libdecor_configuration_get_content_size_dylibloader_orig_libdecor
#define libdecor_configuration_get_window_state libdecor_configuration_get_window_state_dylibloader_orig_libdecor
#include <libdecor-0/libdecor.h>
#include <libdecor.h>
#undef libdecor_unref
#undef libdecor_new
#undef libdecor_get_fd

View file

@ -51,7 +51,7 @@ class KeyMappingXKB {
static inline HashMap<Key, unsigned int, HashMapHasherKeys> scancode_map_inv;
static inline HashMap<unsigned int, KeyLocation, HashMapHasherKeys> location_map;
KeyMappingXKB(){};
KeyMappingXKB() {}
public:
static void initialize();

View file

@ -32,11 +32,7 @@
#include "rendering_context_driver_vulkan_wayland.h"
#ifdef USE_VOLK
#include <volk.h>
#else
#include <vulkan/vulkan.h>
#endif
#include "drivers/vulkan/godot_vulkan.h"
const char *RenderingContextDriverVulkanWayland::_get_platform_surface_extension() const {
return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
@ -51,7 +47,7 @@ RenderingContextDriver::SurfaceID RenderingContextDriverVulkanWayland::surface_c
create_info.surface = wpd->surface;
VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
VkResult err = vkCreateWaylandSurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface);
VkResult err = vkCreateWaylandSurfaceKHR(instance_get(), &create_info, get_allocation_callbacks(VK_OBJECT_TYPE_SURFACE_KHR), &vk_surface);
ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
Surface *surface = memnew(Surface);

View file

@ -32,8 +32,12 @@
#ifdef WAYLAND_ENABLED
// FIXME: Does this cause issues with *BSDs?
#ifdef __FreeBSD__
#include <dev/evdev/input-event-codes.h>
#else
// Assume Linux.
#include <linux/input-event-codes.h>
#endif
// For the actual polling thread.
#include <poll.h>
@ -169,12 +173,13 @@ Vector<uint8_t> WaylandThread::_wp_primary_selection_offer_read(struct wl_displa
int fds[2];
if (pipe(fds) == 0) {
// This function expects to return a string, so we can only ask for a MIME of
// "text/plain"
zwp_primary_selection_offer_v1_receive(p_offer, p_mime, fds[1]);
// Wait for the compositor to know about the pipe.
wl_display_roundtrip(p_display);
// NOTE: It's important to just flush and not roundtrip here as we would risk
// running some cleanup event, like for example `wl_data_device::leave`. We're
// going to wait for the message anyways as the read will probably block if
// the compositor doesn't read from the other end of the pipe.
wl_display_flush(p_display);
// Close the write end of the pipe, which we don't need and would otherwise
// just stall our next `read`s.
@ -186,15 +191,34 @@ Vector<uint8_t> WaylandThread::_wp_primary_selection_offer_read(struct wl_displa
return Vector<uint8_t>();
}
// Sets up an `InputEventKey` and returns whether it has any meaningful value.
bool WaylandThread::_seat_state_configure_key_event(SeatState &p_ss, Ref<InputEventKey> p_event, xkb_keycode_t p_keycode, bool p_pressed) {
// TODO: Handle keys that release multiple symbols?
Key keycode = KeyMappingXKB::get_keycode(xkb_state_key_get_one_sym(p_ss.xkb_state, p_keycode));
Ref<InputEventKey> WaylandThread::_seat_state_get_key_event(SeatState *p_ss, xkb_keycode_t p_keycode, bool p_pressed) {
Ref<InputEventKey> event;
ERR_FAIL_NULL_V(p_ss, event);
Key shifted_key = KeyMappingXKB::get_keycode(xkb_state_key_get_one_sym(p_ss->xkb_state, p_keycode));
Key plain_key = Key::NONE;
// NOTE: xkbcommon's API really encourages to apply the modifier state but we
// only want a "plain" symbol so that we can convert it into a godot keycode.
const xkb_keysym_t *syms = nullptr;
int num_sys = xkb_keymap_key_get_syms_by_level(p_ss->xkb_keymap, p_keycode, p_ss->current_layout_index, 0, &syms);
if (num_sys > 0 && syms) {
plain_key = KeyMappingXKB::get_keycode(syms[0]);
}
Key physical_keycode = KeyMappingXKB::get_scancode(p_keycode);
KeyLocation key_location = KeyMappingXKB::get_location(p_keycode);
uint32_t unicode = xkb_state_key_get_utf32(p_ss->xkb_state, p_keycode);
if (physical_keycode == Key::NONE) {
return false;
Key keycode = Key::NONE;
if ((shifted_key & Key::SPECIAL) != Key::NONE || (plain_key & Key::SPECIAL) != Key::NONE) {
keycode = shifted_key;
}
if (keycode == Key::NONE) {
keycode = plain_key;
}
if (keycode == Key::NONE) {
@ -205,40 +229,71 @@ bool WaylandThread::_seat_state_configure_key_event(SeatState &p_ss, Ref<InputEv
keycode -= 'a' - 'A';
}
p_event->set_window_id(DisplayServer::MAIN_WINDOW_ID);
if (physical_keycode == Key::NONE && keycode == Key::NONE && unicode == 0) {
return event;
}
event.instantiate();
event->set_window_id(DisplayServer::MAIN_WINDOW_ID);
// Set all pressed modifiers.
p_event->set_shift_pressed(p_ss.shift_pressed);
p_event->set_ctrl_pressed(p_ss.ctrl_pressed);
p_event->set_alt_pressed(p_ss.alt_pressed);
p_event->set_meta_pressed(p_ss.meta_pressed);
event->set_shift_pressed(p_ss->shift_pressed);
event->set_ctrl_pressed(p_ss->ctrl_pressed);
event->set_alt_pressed(p_ss->alt_pressed);
event->set_meta_pressed(p_ss->meta_pressed);
p_event->set_pressed(p_pressed);
p_event->set_keycode(keycode);
p_event->set_physical_keycode(physical_keycode);
p_event->set_location(key_location);
uint32_t unicode = xkb_state_key_get_utf32(p_ss.xkb_state, p_keycode);
event->set_pressed(p_pressed);
event->set_keycode(keycode);
event->set_physical_keycode(physical_keycode);
event->set_location(key_location);
if (unicode != 0) {
p_event->set_key_label(fix_key_label(unicode, keycode));
event->set_key_label(fix_key_label(unicode, keycode));
} else {
p_event->set_key_label(keycode);
event->set_key_label(keycode);
}
if (p_pressed) {
p_event->set_unicode(fix_unicode(unicode));
event->set_unicode(fix_unicode(unicode));
}
// Taken from DisplayServerX11.
if (p_event->get_keycode() == Key::BACKTAB) {
if (event->get_keycode() == Key::BACKTAB) {
// Make it consistent across platforms.
p_event->set_keycode(Key::TAB);
p_event->set_physical_keycode(Key::TAB);
p_event->set_shift_pressed(true);
event->set_keycode(Key::TAB);
event->set_physical_keycode(Key::TAB);
event->set_shift_pressed(true);
}
return true;
return event;
}
// NOTE: Due to the nature of the way keys are encoded, there's an ambiguity
// regarding "special" keys. In other words: there's no reliable way of
// switching between a special key and a character key if not marking a
// different Godot keycode, even if we're actually using the same XKB raw
// keycode. This means that, during this switch, the old key will get "stuck",
// as it will never receive a release event. This method returns the necessary
// event to fix this if needed.
Ref<InputEventKey> WaylandThread::_seat_state_get_unstuck_key_event(SeatState *p_ss, xkb_keycode_t p_keycode, bool p_pressed, Key p_key) {
Ref<InputEventKey> event;
if (p_pressed) {
Key *old_key = p_ss->pressed_keycodes.getptr(p_keycode);
if (old_key != nullptr && *old_key != p_key) {
print_verbose(vformat("%s and %s have same keycode. Generating release event for %s", keycode_get_string(*old_key), keycode_get_string(p_key), keycode_get_string(*old_key)));
event = _seat_state_get_key_event(p_ss, p_keycode, false);
if (event.is_valid()) {
event->set_keycode(*old_key);
}
}
p_ss->pressed_keycodes[p_keycode] = p_key;
} else {
p_ss->pressed_keycodes.erase(p_keycode);
}
return event;
}
void WaylandThread::_set_current_seat(struct wl_seat *p_seat) {
@ -264,8 +319,6 @@ bool WaylandThread::_load_cursor_theme(int p_cursor_size) {
if (wl_cursor_theme) {
wl_cursor_theme_destroy(wl_cursor_theme);
wl_cursor_theme = nullptr;
current_wl_cursor = nullptr;
}
if (cursor_theme_name.is_empty()) {
@ -356,7 +409,12 @@ void WaylandThread::_update_scale(int p_scale) {
int cursor_size = unscaled_cursor_size * p_scale;
if (_load_cursor_theme(cursor_size)) {
cursor_set_shape(last_cursor_shape);
for (struct wl_seat *wl_seat : registry.wl_seats) {
SeatState *ss = wl_seat_get_seat_state(wl_seat);
ERR_FAIL_NULL(ss);
seat_state_update_cursor(ss);
}
}
}
@ -370,9 +428,16 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
return;
}
// NOTE: Deprecated.
if (strcmp(interface, zxdg_exporter_v1_interface.name) == 0) {
registry->xdg_exporter = (struct zxdg_exporter_v1 *)wl_registry_bind(wl_registry, name, &zxdg_exporter_v1_interface, 1);
registry->xdg_exporter_name = name;
registry->xdg_exporter_v1 = (struct zxdg_exporter_v1 *)wl_registry_bind(wl_registry, name, &zxdg_exporter_v1_interface, 1);
registry->xdg_exporter_v1_name = name;
return;
}
if (strcmp(interface, zxdg_exporter_v2_interface.name) == 0) {
registry->xdg_exporter_v2 = (struct zxdg_exporter_v2 *)wl_registry_bind(wl_registry, name, &zxdg_exporter_v2_interface, 1);
registry->xdg_exporter_v2_name = name;
return;
}
@ -493,6 +558,12 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
return;
}
if (strcmp(interface, xdg_system_bell_v1_interface.name) == 0) {
registry->xdg_system_bell = (struct xdg_system_bell_v1 *)wl_registry_bind(wl_registry, name, &xdg_system_bell_v1_interface, 1);
registry->xdg_system_bell_name = name;
return;
}
if (strcmp(interface, xdg_activation_v1_interface.name) == 0) {
registry->xdg_activation = (struct xdg_activation_v1 *)wl_registry_bind(wl_registry, name, &xdg_activation_v1_interface, 1);
registry->xdg_activation_name = name;
@ -586,13 +657,25 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry
return;
}
if (name == registry->xdg_exporter_name) {
if (registry->xdg_exporter) {
zxdg_exporter_v1_destroy(registry->xdg_exporter);
registry->xdg_exporter = nullptr;
// NOTE: Deprecated.
if (name == registry->xdg_exporter_v1_name) {
if (registry->xdg_exporter_v1) {
zxdg_exporter_v1_destroy(registry->xdg_exporter_v1);
registry->xdg_exporter_v1 = nullptr;
}
registry->xdg_exporter_name = 0;
registry->xdg_exporter_v1_name = 0;
return;
}
if (name == registry->xdg_exporter_v2_name) {
if (registry->xdg_exporter_v2) {
zxdg_exporter_v2_destroy(registry->xdg_exporter_v2);
registry->xdg_exporter_v2 = nullptr;
}
registry->xdg_exporter_v2_name = 0;
return;
}
@ -688,6 +771,17 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry
return;
}
if (name == registry->xdg_system_bell_name) {
if (registry->xdg_system_bell) {
xdg_system_bell_v1_destroy(registry->xdg_system_bell);
registry->xdg_system_bell = nullptr;
}
registry->xdg_system_bell_name = 0;
return;
}
if (name == registry->xdg_activation_name) {
if (registry->xdg_activation) {
xdg_activation_v1_destroy(registry->xdg_activation);
@ -1162,7 +1256,15 @@ void WaylandThread::_xdg_toplevel_on_wm_capabilities(void *data, struct xdg_topl
}
}
void WaylandThread::_xdg_exported_on_exported(void *data, zxdg_exported_v1 *exported, const char *handle) {
// NOTE: Deprecated.
void WaylandThread::_xdg_exported_v1_on_handle(void *data, zxdg_exported_v1 *exported, const char *handle) {
WindowState *ws = (WindowState *)data;
ERR_FAIL_NULL(ws);
ws->exported_handle = vformat("wayland:%s", String::utf8(handle));
}
void WaylandThread::_xdg_exported_v2_on_handle(void *data, zxdg_exported_v2 *exported, const char *handle) {
WindowState *ws = (WindowState *)data;
ERR_FAIL_NULL(ws);
@ -1394,6 +1496,8 @@ void WaylandThread::_wl_pointer_on_leave(void *data, struct wl_pointer *wl_point
ss->pointed_surface = nullptr;
ss->pointer_data_buffer.pressed_button_mask.clear();
Ref<WindowEventMessage> msg;
msg.instantiate();
msg->event = DisplayServer::WINDOW_EVENT_MOUSE_EXIT;
@ -1416,10 +1520,10 @@ void WaylandThread::_wl_pointer_on_motion(void *data, struct wl_pointer *wl_poin
PointerData &pd = ss->pointer_data_buffer;
// TODO: Scale only when sending the Wayland message.
pd.position.x = wl_fixed_to_int(surface_x);
pd.position.y = wl_fixed_to_int(surface_y);
pd.position.x = wl_fixed_to_double(surface_x);
pd.position.y = wl_fixed_to_double(surface_y);
pd.position = scale_vector2i(pd.position, window_state_get_scale_factor(ws));
pd.position *= window_state_get_scale_factor(ws);
pd.motion_time = time;
}
@ -1532,7 +1636,7 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point
mm->set_position(pd.position);
mm->set_global_position(pd.position);
Vector2i pos_delta = pd.position - old_pd.position;
Vector2 pos_delta = pd.position - old_pd.position;
if (old_pd.relative_motion_time != pd.relative_motion_time) {
uint32_t time_delta = pd.relative_motion_time - old_pd.relative_motion_time;
@ -1649,7 +1753,7 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point
// We have to set the last position pressed here as we can't take for
// granted what the individual events might have seen due to them not having
// a garaunteed order.
// a guaranteed order.
if (mb->is_pressed()) {
pd.last_pressed_position = pd.position;
}
@ -1741,7 +1845,7 @@ void WaylandThread::_wl_pointer_on_axis_discrete(void *data, struct wl_pointer *
pd.discrete_scroll_vector_120.y = discrete * 120;
}
if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
pd.discrete_scroll_vector_120.x = discrete * 120;
}
}
@ -1762,7 +1866,7 @@ void WaylandThread::_wl_pointer_on_axis_value120(void *data, struct wl_pointer *
pd.discrete_scroll_vector_120.y += value120;
}
if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
pd.discrete_scroll_vector_120.x += value120;
}
}
@ -1848,13 +1952,19 @@ void WaylandThread::_wl_keyboard_on_key(void *data, struct wl_keyboard *wl_keybo
ss->repeating_keycode = XKB_KEYCODE_INVALID;
}
Ref<InputEventKey> k;
k.instantiate();
if (!_seat_state_configure_key_event(*ss, k, xkb_keycode, pressed)) {
Ref<InputEventKey> k = _seat_state_get_key_event(ss, xkb_keycode, pressed);
if (k.is_null()) {
return;
}
Ref<InputEventKey> uk = _seat_state_get_unstuck_key_event(ss, xkb_keycode, pressed, k->get_keycode());
if (uk.is_valid()) {
Ref<InputEventMessage> u_msg;
u_msg.instantiate();
u_msg->event = uk;
wayland_thread->push_message(u_msg);
}
Ref<InputEventMessage> msg;
msg.instantiate();
msg->event = k;
@ -2388,9 +2498,9 @@ void WaylandThread::_wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool
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.position.x = wl_fixed_to_double(x);
td.position.y = wl_fixed_to_double(y);
td.position *= scale_factor;
td.motion_time = OS::get_singleton()->get_ticks_msec();
}
@ -2520,7 +2630,7 @@ void WaylandThread::_wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_
mm->set_relative(td.position - old_td.position);
mm->set_relative_screen_position(mm->get_relative());
Vector2i pos_delta = td.position - old_td.position;
Vector2 pos_delta = td.position - old_td.position;
uint32_t time_delta = td.motion_time - old_td.motion_time;
mm->set_velocity((Vector2)pos_delta / time_delta);
@ -2681,7 +2791,7 @@ void WaylandThread::_wp_text_input_on_done(void *data, struct zwp_text_input_v3
msg.instantiate();
msg->text = ss->ime_text_commit;
ss->wayland_thread->push_message(msg);
} else if (!ss->ime_text.is_empty()) {
} else {
Ref<IMEUpdateEventMessage> msg;
msg.instantiate();
msg->text = ss->ime_text;
@ -3071,19 +3181,25 @@ void WaylandThread::seat_state_confine_pointer(SeatState *p_ss) {
void WaylandThread::seat_state_update_cursor(SeatState *p_ss) {
ERR_FAIL_NULL(p_ss);
WaylandThread *thread = p_ss->wayland_thread;
ERR_FAIL_NULL(p_ss->wayland_thread);
if (p_ss->wl_pointer && p_ss->cursor_surface) {
// NOTE: Those values are valid by default and will hide the cursor when
// unchanged, which happens when both the current custom cursor and the
// current wl_cursor are `nullptr`.
struct wl_buffer *cursor_buffer = nullptr;
uint32_t hotspot_x = 0;
uint32_t hotspot_y = 0;
int scale = 1;
if (!p_ss->wl_pointer || !p_ss->cursor_surface) {
return;
}
CustomCursor *custom_cursor = p_ss->wayland_thread->current_custom_cursor;
struct wl_cursor *wl_cursor = p_ss->wayland_thread->current_wl_cursor;
// NOTE: Those values are valid by default and will hide the cursor when
// unchanged.
struct wl_buffer *cursor_buffer = nullptr;
uint32_t hotspot_x = 0;
uint32_t hotspot_y = 0;
int scale = 1;
if (thread->cursor_visible) {
DisplayServer::CursorShape shape = thread->cursor_shape;
struct CustomCursor *custom_cursor = thread->custom_cursors.getptr(shape);
if (custom_cursor) {
cursor_buffer = custom_cursor->wl_buffer;
@ -3093,7 +3209,13 @@ void WaylandThread::seat_state_update_cursor(SeatState *p_ss) {
// We can't really reasonably scale custom cursors, so we'll let the
// compositor do it for us (badly).
scale = 1;
} else if (wl_cursor) {
} else {
struct wl_cursor *wl_cursor = thread->wl_cursors[shape];
if (!wl_cursor) {
return;
}
int frame_idx = 0;
if (wl_cursor->image_count > 1) {
@ -3109,24 +3231,24 @@ void WaylandThread::seat_state_update_cursor(SeatState *p_ss) {
struct wl_cursor_image *wl_cursor_image = wl_cursor->images[frame_idx];
scale = p_ss->wayland_thread->cursor_scale;
scale = thread->cursor_scale;
cursor_buffer = wl_cursor_image_get_buffer(wl_cursor_image);
// As the surface's buffer is scaled (thus the surface is smaller) and the
// hotspot must be expressed in surface-local coordinates, we need to scale
// them down accordingly.
// it down accordingly.
hotspot_x = wl_cursor_image->hotspot_x / scale;
hotspot_y = wl_cursor_image->hotspot_y / scale;
}
wl_pointer_set_cursor(p_ss->wl_pointer, p_ss->pointer_enter_serial, p_ss->cursor_surface, hotspot_x, hotspot_y);
wl_surface_set_buffer_scale(p_ss->cursor_surface, scale);
wl_surface_attach(p_ss->cursor_surface, cursor_buffer, 0, 0);
wl_surface_damage_buffer(p_ss->cursor_surface, 0, 0, INT_MAX, INT_MAX);
wl_surface_commit(p_ss->cursor_surface);
}
wl_pointer_set_cursor(p_ss->wl_pointer, p_ss->pointer_enter_serial, p_ss->cursor_surface, hotspot_x, hotspot_y);
wl_surface_set_buffer_scale(p_ss->cursor_surface, scale);
wl_surface_attach(p_ss->cursor_surface, cursor_buffer, 0, 0);
wl_surface_damage_buffer(p_ss->cursor_surface, 0, 0, INT_MAX, INT_MAX);
wl_surface_commit(p_ss->cursor_surface);
}
void WaylandThread::seat_state_echo_keys(SeatState *p_ss) {
@ -3152,15 +3274,18 @@ void WaylandThread::seat_state_echo_keys(SeatState *p_ss) {
int keys_amount = (ticks_delta / p_ss->repeat_key_delay_msec);
for (int i = 0; i < keys_amount; i++) {
Ref<InputEventKey> k;
k.instantiate();
if (!_seat_state_configure_key_event(*p_ss, k, p_ss->repeating_keycode, true)) {
Ref<InputEventKey> k = _seat_state_get_key_event(p_ss, p_ss->repeating_keycode, true);
if (k.is_null()) {
continue;
}
k->set_echo(true);
Ref<InputEventKey> uk = _seat_state_get_unstuck_key_event(p_ss, p_ss->repeating_keycode, true, k->get_keycode());
if (uk.is_valid()) {
Input::get_singleton()->parse_input_event(uk);
}
Input::get_singleton()->parse_input_event(k);
}
@ -3246,9 +3371,12 @@ void WaylandThread::window_create(DisplayServer::WindowID p_window_id, int p_wid
ws.frame_callback = wl_surface_frame(ws.wl_surface);
wl_callback_add_listener(ws.frame_callback, &frame_wl_callback_listener, &ws);
if (registry.xdg_exporter) {
ws.xdg_exported = zxdg_exporter_v1_export(registry.xdg_exporter, ws.wl_surface);
zxdg_exported_v1_add_listener(ws.xdg_exported, &xdg_exported_listener, &ws);
if (registry.xdg_exporter_v2) {
ws.xdg_exported_v2 = zxdg_exporter_v2_export_toplevel(registry.xdg_exporter_v2, ws.wl_surface);
zxdg_exported_v2_add_listener(ws.xdg_exported_v2, &xdg_exported_v2_listener, &ws);
} else if (registry.xdg_exporter_v1) {
ws.xdg_exported_v1 = zxdg_exporter_v1_export(registry.xdg_exporter_v1, ws.wl_surface);
zxdg_exported_v1_add_listener(ws.xdg_exported_v1, &xdg_exported_v1_listener, &ws);
}
wl_surface_commit(ws.wl_surface);
@ -3264,6 +3392,102 @@ struct wl_surface *WaylandThread::window_get_wl_surface(DisplayServer::WindowID
return ws.wl_surface;
}
void WaylandThread::beep() const {
if (registry.xdg_system_bell) {
xdg_system_bell_v1_ring(registry.xdg_system_bell, nullptr);
}
}
void WaylandThread::window_start_drag(DisplayServer::WindowID p_window_id) {
// TODO: Use window IDs for multiwindow support.
WindowState &ws = main_window;
SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
if (ss && ws.xdg_toplevel) {
xdg_toplevel_move(ws.xdg_toplevel, ss->wl_seat, ss->pointer_data.button_serial);
}
#ifdef LIBDECOR_ENABLED
if (ws.libdecor_frame) {
libdecor_frame_move(ws.libdecor_frame, ss->wl_seat, ss->pointer_data.button_serial);
}
#endif
}
void WaylandThread::window_start_resize(DisplayServer::WindowResizeEdge p_edge, DisplayServer::WindowID p_window) {
// TODO: Use window IDs for multiwindow support.
WindowState &ws = main_window;
SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
if (ss && ws.xdg_toplevel) {
xdg_toplevel_resize_edge edge = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
switch (p_edge) {
case DisplayServer::WINDOW_EDGE_TOP_LEFT: {
edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
} break;
case DisplayServer::WINDOW_EDGE_TOP: {
edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
} break;
case DisplayServer::WINDOW_EDGE_TOP_RIGHT: {
edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
} break;
case DisplayServer::WINDOW_EDGE_LEFT: {
edge = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
} break;
case DisplayServer::WINDOW_EDGE_RIGHT: {
edge = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
} break;
case DisplayServer::WINDOW_EDGE_BOTTOM_LEFT: {
edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
} break;
case DisplayServer::WINDOW_EDGE_BOTTOM: {
edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
} break;
case DisplayServer::WINDOW_EDGE_BOTTOM_RIGHT: {
edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
} break;
default:
break;
}
xdg_toplevel_resize(ws.xdg_toplevel, ss->wl_seat, ss->pointer_data.button_serial, edge);
}
#ifdef LIBDECOR_ENABLED
if (ws.libdecor_frame) {
libdecor_resize_edge edge = LIBDECOR_RESIZE_EDGE_NONE;
switch (p_edge) {
case DisplayServer::WINDOW_EDGE_TOP_LEFT: {
edge = LIBDECOR_RESIZE_EDGE_TOP_LEFT;
} break;
case DisplayServer::WINDOW_EDGE_TOP: {
edge = LIBDECOR_RESIZE_EDGE_TOP;
} break;
case DisplayServer::WINDOW_EDGE_TOP_RIGHT: {
edge = LIBDECOR_RESIZE_EDGE_TOP_RIGHT;
} break;
case DisplayServer::WINDOW_EDGE_LEFT: {
edge = LIBDECOR_RESIZE_EDGE_LEFT;
} break;
case DisplayServer::WINDOW_EDGE_RIGHT: {
edge = LIBDECOR_RESIZE_EDGE_RIGHT;
} break;
case DisplayServer::WINDOW_EDGE_BOTTOM_LEFT: {
edge = LIBDECOR_RESIZE_EDGE_BOTTOM_LEFT;
} break;
case DisplayServer::WINDOW_EDGE_BOTTOM: {
edge = LIBDECOR_RESIZE_EDGE_BOTTOM;
} break;
case DisplayServer::WINDOW_EDGE_BOTTOM_RIGHT: {
edge = LIBDECOR_RESIZE_EDGE_BOTTOM_RIGHT;
} break;
default:
break;
}
libdecor_frame_resize(ws.libdecor_frame, ss->wl_seat, ss->pointer_data.button_serial, edge);
}
#endif
}
void WaylandThread::window_set_max_size(DisplayServer::WindowID p_window_id, const Size2i &p_size) {
// TODO: Use window IDs for multiwindow support.
WindowState &ws = main_window;
@ -3328,7 +3552,8 @@ bool WaylandThread::window_can_set_mode(DisplayServer::WindowID p_window_id, Dis
return ws.can_maximize;
};
case DisplayServer::WINDOW_MODE_FULLSCREEN: {
case DisplayServer::WINDOW_MODE_FULLSCREEN:
case DisplayServer::WINDOW_MODE_EXCLUSIVE_FULLSCREEN: {
#ifdef LIBDECOR_ENABLED
if (ws.libdecor_frame) {
return libdecor_frame_has_capability(ws.libdecor_frame, LIBDECOR_ACTION_FULLSCREEN);
@ -3337,13 +3562,6 @@ bool WaylandThread::window_can_set_mode(DisplayServer::WindowID p_window_id, Dis
return ws.can_fullscreen;
};
case DisplayServer::WINDOW_MODE_EXCLUSIVE_FULLSCREEN: {
// I'm not really sure but from what I can find Wayland doesn't really have
// the concept of exclusive fullscreen.
// TODO: Discuss whether to fallback to regular fullscreen or not.
return false;
};
}
return false;
@ -3458,7 +3676,8 @@ void WaylandThread::window_try_set_mode(DisplayServer::WindowID p_window_id, Dis
#endif // LIBDECOR_ENABLED
} break;
case DisplayServer::WINDOW_MODE_FULLSCREEN: {
case DisplayServer::WINDOW_MODE_FULLSCREEN:
case DisplayServer::WINDOW_MODE_EXCLUSIVE_FULLSCREEN: {
if (ws.xdg_toplevel) {
xdg_toplevel_set_fullscreen(ws.xdg_toplevel, nullptr);
}
@ -3767,25 +3986,19 @@ Error WaylandThread::init() {
return OK;
}
void WaylandThread::cursor_hide() {
current_wl_cursor = nullptr;
current_custom_cursor = nullptr;
void WaylandThread::cursor_set_visible(bool p_visible) {
cursor_visible = p_visible;
SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
ERR_FAIL_NULL(ss);
seat_state_update_cursor(ss);
for (struct wl_seat *wl_seat : registry.wl_seats) {
SeatState *ss = wl_seat_get_seat_state(wl_seat);
ERR_FAIL_NULL(ss);
seat_state_update_cursor(ss);
}
}
void WaylandThread::cursor_set_shape(DisplayServer::CursorShape p_cursor_shape) {
if (!wl_cursors[p_cursor_shape]) {
return;
}
// The point of this method is make the current cursor a "plain" shape and, as
// the custom cursor overrides what gets set, we have to clear it too.
current_custom_cursor = nullptr;
current_wl_cursor = wl_cursors[p_cursor_shape];
cursor_shape = p_cursor_shape;
for (struct wl_seat *wl_seat : registry.wl_seats) {
SeatState *ss = wl_seat_get_seat_state(wl_seat);
@ -3793,27 +4006,10 @@ void WaylandThread::cursor_set_shape(DisplayServer::CursorShape p_cursor_shape)
seat_state_update_cursor(ss);
}
last_cursor_shape = p_cursor_shape;
}
void WaylandThread::cursor_set_custom_shape(DisplayServer::CursorShape p_cursor_shape) {
ERR_FAIL_COND(!custom_cursors.has(p_cursor_shape));
current_custom_cursor = &custom_cursors[p_cursor_shape];
for (struct wl_seat *wl_seat : registry.wl_seats) {
SeatState *ss = wl_seat_get_seat_state(wl_seat);
ERR_FAIL_NULL(ss);
seat_state_update_cursor(ss);
}
last_cursor_shape = p_cursor_shape;
}
void WaylandThread::cursor_shape_set_custom_image(DisplayServer::CursorShape p_cursor_shape, Ref<Image> p_image, const Point2i &p_hotspot) {
ERR_FAIL_COND(!p_image.is_valid());
ERR_FAIL_COND(p_image.is_null());
Size2i image_size = p_image->get_size();
@ -3829,23 +4025,21 @@ void WaylandThread::cursor_shape_set_custom_image(DisplayServer::CursorShape p_c
CustomCursor &cursor = custom_cursors[p_cursor_shape];
cursor.hotspot = p_hotspot;
if (cursor.buffer_data) {
// Clean up the old buffer data.
munmap(cursor.buffer_data, cursor.buffer_data_size);
}
// NOTE: From `wl_keyboard`s of version 7 or later, the spec requires the mmap
// operation to be done with MAP_PRIVATE, as "MAP_SHARED may fail". We'll do it
// regardless of global version.
cursor.buffer_data = (uint32_t *)mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (cursor.wl_buffer) {
// Clean up the old Wayland buffer.
wl_buffer_destroy(cursor.wl_buffer);
}
if (cursor.buffer_data) {
// Clean up the old buffer data.
munmap(cursor.buffer_data, cursor.buffer_data_size);
}
cursor.buffer_data = (uint32_t *)mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
cursor.buffer_data_size = data_size;
// Create the Wayland buffer.
struct wl_shm_pool *wl_shm_pool = wl_shm_create_pool(registry.wl_shm, fd, image_size.height * data_size);
struct wl_shm_pool *wl_shm_pool = wl_shm_create_pool(registry.wl_shm, fd, data_size);
// TODO: Make sure that WL_SHM_FORMAT_ARGB8888 format is supported. It
// technically isn't garaunteed to be supported, but I think that'd be a
// pretty unlikely thing to stumble upon.
@ -3873,8 +4067,6 @@ void WaylandThread::cursor_shape_clear_custom_image(DisplayServer::CursorShape p
CustomCursor cursor = custom_cursors[p_cursor_shape];
custom_cursors.erase(p_cursor_shape);
current_custom_cursor = nullptr;
if (cursor.wl_buffer) {
wl_buffer_destroy(cursor.wl_buffer);
}
@ -3979,6 +4171,7 @@ void WaylandThread::selection_set_text(const String &p_text) {
if (registry.wl_data_device_manager == nullptr) {
DEBUG_LOG_WAYLAND_THREAD("Couldn't set selection, wl_data_device_manager global not available.");
return;
}
if (ss == nullptr) {
@ -3997,10 +4190,10 @@ void WaylandThread::selection_set_text(const String &p_text) {
wl_data_source_add_listener(ss->wl_data_source_selection, &wl_data_source_listener, ss);
wl_data_source_offer(ss->wl_data_source_selection, "text/plain;charset=utf-8");
wl_data_source_offer(ss->wl_data_source_selection, "text/plain");
}
// TODO: Implement a good way of getting the latest serial from the user.
wl_data_device_set_selection(ss->wl_data_device, ss->wl_data_source_selection, MAX(ss->pointer_data.button_serial, ss->last_key_pressed_serial));
// TODO: Implement a good way of getting the latest serial from the user.
wl_data_device_set_selection(ss->wl_data_device, ss->wl_data_source_selection, MAX(ss->pointer_data.button_serial, ss->last_key_pressed_serial));
}
// Wait for the message to get to the server before continuing, otherwise the
// clipboard update might come with a delay.
@ -4106,6 +4299,11 @@ void WaylandThread::primary_set_text(const String &p_text) {
return;
}
if (ss->wp_primary_selection_device == nullptr) {
DEBUG_LOG_WAYLAND_THREAD("Couldn't set primary selection, seat doesn't have wp_primary_selection_device.");
return;
}
ss->primary_data = p_text.to_utf8_buffer();
if (ss->wp_primary_selection_source == nullptr) {
@ -4113,10 +4311,10 @@ void WaylandThread::primary_set_text(const String &p_text) {
zwp_primary_selection_source_v1_add_listener(ss->wp_primary_selection_source, &wp_primary_selection_source_listener, ss);
zwp_primary_selection_source_v1_offer(ss->wp_primary_selection_source, "text/plain;charset=utf-8");
zwp_primary_selection_source_v1_offer(ss->wp_primary_selection_source, "text/plain");
}
// TODO: Implement a good way of getting the latest serial from the user.
zwp_primary_selection_device_v1_set_selection(ss->wp_primary_selection_device, ss->wp_primary_selection_source, MAX(ss->pointer_data.button_serial, ss->last_key_pressed_serial));
// TODO: Implement a good way of getting the latest serial from the user.
zwp_primary_selection_device_v1_set_selection(ss->wp_primary_selection_device, ss->wp_primary_selection_source, MAX(ss->pointer_data.button_serial, ss->last_key_pressed_serial));
}
// Wait for the message to get to the server before continuing, otherwise the
// clipboard update might come with a delay.
@ -4141,6 +4339,16 @@ bool WaylandThread::get_reset_frame() {
// Dispatches events until a frame event is received, a window is reported as
// suspended or the timeout expires.
bool WaylandThread::wait_frame_suspend_ms(int p_timeout) {
// This is a bit of a chicken and egg thing... Looks like the main event loop
// has to call its rightfully forever-blocking poll right in between
// `wl_display_prepare_read` and `wl_display_read`. This means, that it will
// basically be guaranteed to stay stuck in a "prepare read" state, where it
// will block any other attempt at reading the display fd, such as ours. The
// solution? Let's make sure the mutex is locked (it should) and unblock the
// main thread with a roundtrip!
MutexLock mutex_lock(mutex);
wl_display_roundtrip(wl_display);
if (main_window.suspended) {
// The window is suspended! The compositor is telling us _explicitly_ that we
// don't need to draw, without letting us guess through the frame event's
@ -4373,6 +4581,10 @@ void WaylandThread::destroy() {
xdg_activation_v1_destroy(registry.xdg_activation);
}
if (registry.xdg_system_bell) {
xdg_system_bell_v1_destroy(registry.xdg_system_bell);
}
if (registry.xdg_decoration_manager) {
zxdg_decoration_manager_v1_destroy(registry.xdg_decoration_manager);
}
@ -4389,10 +4601,14 @@ void WaylandThread::destroy() {
xdg_wm_base_destroy(registry.xdg_wm_base);
}
if (registry.xdg_exporter) {
zxdg_exporter_v1_destroy(registry.xdg_exporter);
// NOTE: Deprecated.
if (registry.xdg_exporter_v1) {
zxdg_exporter_v1_destroy(registry.xdg_exporter_v1);
}
if (registry.xdg_exporter_v2) {
zxdg_exporter_v2_destroy(registry.xdg_exporter_v2);
}
if (registry.wl_shm) {
wl_shm_destroy(registry.wl_shm);
}

View file

@ -44,7 +44,7 @@
#include <wayland-client-core.h>
#include <wayland-cursor.h>
#ifdef GLES3_ENABLED
#include <wayland-egl.h>
#include <wayland-egl-core.h>
#endif
#include <xkbcommon/xkbcommon.h>
#endif // SOWRAP_ENABLED
@ -67,14 +67,18 @@
#include "wayland/protocol/wayland.gen.h"
#include "wayland/protocol/xdg_activation.gen.h"
#include "wayland/protocol/xdg_decoration.gen.h"
#include "wayland/protocol/xdg_foreign.gen.h"
#include "wayland/protocol/xdg_foreign_v2.gen.h"
#include "wayland/protocol/xdg_shell.gen.h"
#include "wayland/protocol/xdg_system_bell.gen.h"
// NOTE: Deprecated.
#include "wayland/protocol/xdg_foreign_v1.gen.h"
#ifdef LIBDECOR_ENABLED
#ifdef SOWRAP_ENABLED
#include "dynwrappers/libdecor-so_wrap.h"
#else
#include <libdecor-0/libdecor.h>
#include <libdecor.h>
#endif // SOWRAP_ENABLED
#endif // LIBDECOR_ENABLED
@ -148,8 +152,12 @@ public:
struct xdg_wm_base *xdg_wm_base = nullptr;
uint32_t xdg_wm_base_name = 0;
struct zxdg_exporter_v1 *xdg_exporter = nullptr;
uint32_t xdg_exporter_name = 0;
// NOTE: Deprecated.
struct zxdg_exporter_v1 *xdg_exporter_v1 = nullptr;
uint32_t xdg_exporter_v1_name = 0;
uint32_t xdg_exporter_v2_name = 0;
struct zxdg_exporter_v2 *xdg_exporter_v2 = nullptr;
// wayland-protocols globals.
@ -162,6 +170,9 @@ public:
struct zxdg_decoration_manager_v1 *xdg_decoration_manager = nullptr;
uint32_t xdg_decoration_manager_name = 0;
struct xdg_system_bell_v1 *xdg_system_bell = nullptr;
uint32_t xdg_system_bell_name = 0;
struct xdg_activation_v1 *xdg_activation = nullptr;
uint32_t xdg_activation_name = 0;
@ -220,7 +231,11 @@ public:
struct wp_viewport *wp_viewport = nullptr;
struct wp_fractional_scale_v1 *wp_fractional_scale = nullptr;
struct zxdg_exported_v1 *xdg_exported = nullptr;
// NOTE: Deprecated.
struct zxdg_exported_v1 *xdg_exported_v1 = nullptr;
struct zxdg_exported_v2 *xdg_exported_v2 = nullptr;
String exported_handle;
@ -295,7 +310,7 @@ public:
};
struct PointerData {
Point2i position;
Point2 position;
uint32_t motion_time = 0;
// Relative motion has its own optional event and so needs its own time.
@ -305,7 +320,7 @@ public:
BitField<MouseButtonMask> pressed_button_mask;
MouseButton last_button_pressed = MouseButton::NONE;
Point2i last_pressed_position;
Point2 last_pressed_position;
// This is needed to check for a new double click every time.
bool double_click_begun = false;
@ -325,14 +340,14 @@ public:
};
struct TabletToolData {
Point2i position;
Point2 position;
Vector2 tilt;
uint32_t pressure = 0;
BitField<MouseButtonMask> pressed_button_mask;
MouseButton last_button_pressed = MouseButton::NONE;
Point2i last_pressed_position;
Point2 last_pressed_position;
bool double_click_begun = false;
@ -413,6 +428,8 @@ public:
const char *keymap_buffer = nullptr;
uint32_t keymap_buffer_size = 0;
HashMap<xkb_keycode_t, Key> pressed_keycodes;
xkb_layout_index_t current_layout_index = 0;
int32_t repeat_key_delay_msec = 0;
@ -469,7 +486,6 @@ public:
uint32_t *buffer_data = nullptr;
uint32_t buffer_data_size = 0;
RID rid;
Point2i hotspot;
};
@ -506,10 +522,8 @@ private:
HashMap<DisplayServer::CursorShape, CustomCursor> custom_cursors;
struct wl_cursor *current_wl_cursor = nullptr;
struct CustomCursor *current_custom_cursor = nullptr;
DisplayServer::CursorShape last_cursor_shape = DisplayServer::CURSOR_ARROW;
DisplayServer::CursorShape cursor_shape = DisplayServer::CURSOR_ARROW;
bool cursor_visible = true;
PointerConstraint pointer_constraint = PointerConstraint::NONE;
@ -651,7 +665,10 @@ private:
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);
// NOTE: Deprecated.
static void _xdg_exported_v1_on_handle(void *data, zxdg_exported_v1 *exported, const char *handle);
static void _xdg_exported_v2_on_handle(void *data, zxdg_exported_v2 *exported, const char *handle);
static void _xdg_activation_token_on_done(void *data, struct xdg_activation_token_v1 *xdg_activation_token, const char *token);
@ -668,7 +685,7 @@ private:
.preferred_buffer_transform = _wl_surface_on_preferred_buffer_transform,
};
static constexpr struct wl_callback_listener frame_wl_callback_listener {
static constexpr struct wl_callback_listener frame_wl_callback_listener = {
.done = _frame_wl_callback_on_done,
};
@ -686,7 +703,7 @@ private:
.name = _wl_seat_on_name,
};
static constexpr struct wl_callback_listener cursor_frame_callback_listener {
static constexpr struct wl_callback_listener cursor_frame_callback_listener = {
.done = _cursor_frame_callback_on_done,
};
@ -819,8 +836,13 @@ private:
.done = _wp_text_input_on_done,
};
static constexpr struct zxdg_exported_v1_listener xdg_exported_listener = {
.handle = _xdg_exported_on_exported
// NOTE: Deprecated.
static constexpr struct zxdg_exported_v1_listener xdg_exported_v1_listener = {
.handle = _xdg_exported_v1_on_handle,
};
static constexpr struct zxdg_exported_v2_listener xdg_exported_v2_listener = {
.handle = _xdg_exported_v2_on_handle,
};
static constexpr struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_listener = {
@ -883,7 +905,8 @@ private:
static Vector<uint8_t> _wp_primary_selection_offer_read(struct wl_display *wl_display, const char *p_mime, struct zwp_primary_selection_offer_v1 *wp_primary_selection_offer);
static void _seat_state_set_current(WaylandThread::SeatState &p_ss);
static bool _seat_state_configure_key_event(WaylandThread::SeatState &p_seat, Ref<InputEventKey> p_event, xkb_keycode_t p_keycode, bool p_pressed);
static Ref<InputEventKey> _seat_state_get_key_event(SeatState *p_ss, xkb_keycode_t p_keycode, bool p_pressed);
static Ref<InputEventKey> _seat_state_get_unstuck_key_event(SeatState *p_ss, xkb_keycode_t p_keycode, bool p_pressed, Key p_key);
static void _wayland_state_update_cursor();
@ -929,10 +952,14 @@ public:
bool has_message();
Ref<Message> pop_message();
void beep() const;
void window_create(DisplayServer::WindowID p_window_id, int p_width, int p_height);
struct wl_surface *window_get_wl_surface(DisplayServer::WindowID p_window_id) const;
void window_start_resize(DisplayServer::WindowResizeEdge p_edge, DisplayServer::WindowID p_window);
void window_set_max_size(DisplayServer::WindowID p_window_id, const Size2i &p_size);
void window_set_min_size(DisplayServer::WindowID p_window_id, const Size2i &p_size);
@ -949,6 +976,8 @@ public:
// Optional - requires xdg_activation_v1
void window_request_attention(DisplayServer::WindowID p_window_id);
void window_start_drag(DisplayServer::WindowID p_window_id);
// Optional - require idle_inhibit_unstable_v1
void window_set_idle_inhibition(DisplayServer::WindowID p_window_id, bool p_enable);
bool window_get_idle_inhibition(DisplayServer::WindowID p_window_id) const;
@ -962,7 +991,7 @@ public:
DisplayServer::WindowID pointer_get_pointed_window_id() const;
BitField<MouseButtonMask> pointer_get_button_mask() const;
void cursor_hide();
void cursor_set_visible(bool p_visible);
void cursor_set_shape(DisplayServer::CursorShape p_cursor_shape);
void cursor_set_custom_shape(DisplayServer::CursorShape p_cursor_shape);