summaryrefslogtreecommitdiffstats
path: root/platform/linuxbsd
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r--platform/linuxbsd/SCsub3
-rw-r--r--platform/linuxbsd/crash_handler_linuxbsd.cpp4
-rw-r--r--platform/linuxbsd/detect.py99
-rw-r--r--platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml14
-rw-r--r--platform/linuxbsd/export/export_plugin.cpp19
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.cpp216
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.h30
-rw-r--r--platform/linuxbsd/godot_linuxbsd.cpp25
-rw-r--r--platform/linuxbsd/joypad_linux.cpp6
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp41
-rw-r--r--platform/linuxbsd/os_linuxbsd.h4
-rw-r--r--platform/linuxbsd/pck_embed.ld10
-rw-r--r--platform/linuxbsd/pck_embed.legacy.ld10
-rw-r--r--platform/linuxbsd/platform_linuxbsd_builders.py17
-rw-r--r--platform/linuxbsd/wayland/SCsub15
-rw-r--r--platform/linuxbsd/wayland/detect_prime_egl.cpp2
-rw-r--r--platform/linuxbsd/wayland/display_server_wayland.cpp244
-rw-r--r--platform/linuxbsd/wayland/display_server_wayland.h15
-rw-r--r--platform/linuxbsd/wayland/egl_manager_wayland_gles.cpp64
-rw-r--r--platform/linuxbsd/wayland/egl_manager_wayland_gles.h53
-rw-r--r--platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp (renamed from platform/linuxbsd/wayland/vulkan_context_wayland.cpp)39
-rw-r--r--platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h (renamed from platform/linuxbsd/wayland/vulkan_context_wayland.h)21
-rw-r--r--platform/linuxbsd/wayland/wayland_thread.cpp599
-rw-r--r--platform/linuxbsd/wayland/wayland_thread.h92
-rw-r--r--platform/linuxbsd/x11/SCsub2
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp186
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h7
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.cpp14
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.h1
-rw-r--r--platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp (renamed from platform/linuxbsd/x11/vulkan_context_x11.cpp)35
-rw-r--r--platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.h (renamed from platform/linuxbsd/x11/vulkan_context_x11.h)21
31 files changed, 1170 insertions, 738 deletions
diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub
index a3ce773ac2..0802b528f4 100644
--- a/platform/linuxbsd/SCsub
+++ b/platform/linuxbsd/SCsub
@@ -2,7 +2,6 @@
Import("env")
-from platform_methods import run_in_subprocess
import platform_linuxbsd_builders
common_linuxbsd = [
@@ -42,4 +41,4 @@ if env["dbus"]:
prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_linuxbsd)
if env["debug_symbols"] and env["separate_debug_symbols"]:
- env.AddPostAction(prog, run_in_subprocess(platform_linuxbsd_builders.make_debug_linuxbsd))
+ env.AddPostAction(prog, env.Run(platform_linuxbsd_builders.make_debug_linuxbsd))
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 7946ef6228..47f3bcadc9 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -1,13 +1,13 @@
import os
import platform
import sys
-from methods import get_compiler_version, using_gcc
+from methods import print_warning, print_error, get_compiler_version, using_gcc
from platform_methods import detect_arch
from typing import TYPE_CHECKING
if TYPE_CHECKING:
- from SCons import Environment
+ from SCons.Script.SConscript import SConsEnvironment
def get_name():
@@ -20,7 +20,7 @@ def can_build():
pkgconf_error = os.system("pkg-config --version > /dev/null")
if pkgconf_error:
- print("Error: pkg-config not found. Aborting.")
+ print_error("pkg-config not found. Aborting.")
return False
return True
@@ -67,14 +67,15 @@ def get_doc_path():
def get_flags():
return [
("arch", detect_arch()),
+ ("supported", ["mono"]),
]
-def configure(env: "Environment"):
+def configure(env: "SConsEnvironment"):
# Validate arch.
supported_arches = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64"]
if env["arch"] not in supported_arches:
- print(
+ print_error(
'Unsupported CPU architecture "%s" for Linux / *BSD. Supported architectures are: %s.'
% (env["arch"], ", ".join(supported_arches))
)
@@ -127,7 +128,9 @@ def configure(env: "Environment"):
found_wrapper = True
break
if not found_wrapper:
- print("Couldn't locate mold installation path. Make sure it's installed in /usr or /usr/local.")
+ print_error(
+ "Couldn't locate mold installation path. Make sure it's installed in /usr or /usr/local."
+ )
sys.exit(255)
else:
env.Append(LINKFLAGS=["-fuse-ld=mold"])
@@ -184,7 +187,7 @@ def configure(env: "Environment"):
if env["lto"] != "none":
if env["lto"] == "thin":
if not env["use_llvm"]:
- print("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
+ print_error("ThinLTO is only compatible with LLVM, use `use_llvm=yes` or `lto=full`.")
sys.exit(255)
env.Append(CCFLAGS=["-flto=thin"])
env.Append(LINKFLAGS=["-flto=thin"])
@@ -207,8 +210,8 @@ def configure(env: "Environment"):
env.Append(CPPDEFINES=["SOWRAP_ENABLED"])
if env["wayland"]:
- if os.system("wayland-scanner -v") != 0:
- print("wayland-scanner not found. Disabling wayland support.")
+ if os.system("wayland-scanner -v 2>/dev/null") != 0:
+ print_warning("wayland-scanner not found. Disabling Wayland support.")
env["wayland"] = False
if env["touch"]:
@@ -226,7 +229,7 @@ def configure(env: "Environment"):
env["builtin_harfbuzz"],
]
if (not all(ft_linked_deps)) and any(ft_linked_deps): # All or nothing.
- print(
+ print_error(
"These libraries should be either all builtin, or all system provided:\n"
"freetype, libpng, zlib, graphite, harfbuzz.\n"
"Please specify `builtin_<name>=no` for all of them, or none."
@@ -306,7 +309,7 @@ def configure(env: "Environment"):
if not env["builtin_embree"] and env["arch"] in ["x86_64", "arm64"]:
# No pkgconfig file so far, hardcode expected lib name.
- env.Append(LIBS=["embree3"])
+ env.Append(LIBS=["embree4"])
if not env["builtin_openxr"]:
env.ParseConfig("pkg-config openxr --cflags --libs")
@@ -317,7 +320,7 @@ def configure(env: "Environment"):
env.ParseConfig("pkg-config fontconfig --cflags --libs")
env.Append(CPPDEFINES=["FONTCONFIG_ENABLED"])
else:
- print("Warning: fontconfig development libraries not found. Disabling the system fonts support.")
+ print_warning("fontconfig development libraries not found. Disabling the system fonts support.")
env["fontconfig"] = False
else:
env.Append(CPPDEFINES=["FONTCONFIG_ENABLED"])
@@ -328,7 +331,7 @@ def configure(env: "Environment"):
env.ParseConfig("pkg-config alsa --cflags --libs")
env.Append(CPPDEFINES=["ALSA_ENABLED", "ALSAMIDI_ENABLED"])
else:
- print("Warning: ALSA development libraries not found. Disabling the ALSA audio driver.")
+ print_warning("ALSA development libraries not found. Disabling the ALSA audio driver.")
env["alsa"] = False
else:
env.Append(CPPDEFINES=["ALSA_ENABLED", "ALSAMIDI_ENABLED"])
@@ -339,7 +342,7 @@ def configure(env: "Environment"):
env.ParseConfig("pkg-config libpulse --cflags --libs")
env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED"])
else:
- print("Warning: PulseAudio development libraries not found. Disabling the PulseAudio audio driver.")
+ print_warning("PulseAudio development libraries not found. Disabling the PulseAudio audio driver.")
env["pulseaudio"] = False
else:
env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED", "_REENTRANT"])
@@ -350,7 +353,7 @@ def configure(env: "Environment"):
env.ParseConfig("pkg-config dbus-1 --cflags --libs")
env.Append(CPPDEFINES=["DBUS_ENABLED"])
else:
- print("Warning: D-Bus development libraries not found. Disabling screensaver prevention.")
+ print_warning("D-Bus development libraries not found. Disabling screensaver prevention.")
env["dbus"] = False
else:
env.Append(CPPDEFINES=["DBUS_ENABLED"])
@@ -361,7 +364,7 @@ def configure(env: "Environment"):
env.ParseConfig("pkg-config speech-dispatcher --cflags --libs")
env.Append(CPPDEFINES=["SPEECHD_ENABLED"])
else:
- print("Warning: speech-dispatcher development libraries not found. Disabling text to speech support.")
+ print_warning("speech-dispatcher development libraries not found. Disabling text to speech support.")
env["speechd"] = False
else:
env.Append(CPPDEFINES=["SPEECHD_ENABLED"])
@@ -372,11 +375,11 @@ def configure(env: "Environment"):
env.Append(CPPDEFINES=["XKB_ENABLED"])
else:
if env["wayland"]:
- print("Error: libxkbcommon development libraries required by Wayland not found. Aborting.")
+ print_error("libxkbcommon development libraries required by Wayland not found. Aborting.")
sys.exit(255)
else:
- print(
- "Warning: libxkbcommon development libraries not found. Disabling dead key composition and key label support."
+ print_warning(
+ "libxkbcommon development libraries not found. Disabling dead key composition and key label support."
)
else:
env.Append(CPPDEFINES=["XKB_ENABLED"])
@@ -389,7 +392,7 @@ def configure(env: "Environment"):
env.ParseConfig("pkg-config libudev --cflags --libs")
env.Append(CPPDEFINES=["UDEV_ENABLED"])
else:
- print("Warning: libudev development libraries not found. Disabling controller hotplugging support.")
+ print_warning("libudev development libraries not found. Disabling controller hotplugging support.")
env["udev"] = False
else:
env.Append(CPPDEFINES=["UDEV_ENABLED"])
@@ -415,31 +418,31 @@ def configure(env: "Environment"):
if env["x11"]:
if not env["use_sowrap"]:
if os.system("pkg-config --exists x11"):
- print("Error: X11 libraries not found. Aborting.")
+ print_error("X11 libraries not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config x11 --cflags --libs")
if os.system("pkg-config --exists xcursor"):
- print("Error: Xcursor library not found. Aborting.")
+ print_error("Xcursor library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config xcursor --cflags --libs")
if os.system("pkg-config --exists xinerama"):
- print("Error: Xinerama library not found. Aborting.")
+ print_error("Xinerama library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config xinerama --cflags --libs")
if os.system("pkg-config --exists xext"):
- print("Error: Xext library not found. Aborting.")
+ print_error("Xext library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config xext --cflags --libs")
if os.system("pkg-config --exists xrandr"):
- print("Error: XrandR library not found. Aborting.")
+ print_error("XrandR library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config xrandr --cflags --libs")
if os.system("pkg-config --exists xrender"):
- print("Error: XRender library not found. Aborting.")
+ print_error("XRender library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config xrender --cflags --libs")
if os.system("pkg-config --exists xi"):
- print("Error: Xi library not found. Aborting.")
+ print_error("Xi library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config xi --cflags --libs")
env.Append(CPPDEFINES=["X11_ENABLED"])
@@ -447,20 +450,20 @@ def configure(env: "Environment"):
if env["wayland"]:
if not env["use_sowrap"]:
if os.system("pkg-config --exists libdecor-0"):
- print("Warning: libdecor development libraries not found. Disabling client-side decorations.")
+ print_warning("libdecor development libraries not found. Disabling client-side decorations.")
env["libdecor"] = False
else:
env.ParseConfig("pkg-config libdecor-0 --cflags --libs")
if os.system("pkg-config --exists wayland-client"):
- print("Error: Wayland client library not found. Aborting.")
+ print_error("Wayland client library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config wayland-client --cflags --libs")
if os.system("pkg-config --exists wayland-cursor"):
- print("Error: Wayland cursor library not found. Aborting.")
+ print_error("Wayland cursor library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config wayland-cursor --cflags --libs")
if os.system("pkg-config --exists wayland-egl"):
- print("Error: Wayland EGL library not found. Aborting.")
+ print_error("Wayland EGL library not found. Aborting.")
sys.exit(255)
env.ParseConfig("pkg-config wayland-egl --cflags --libs")
@@ -487,32 +490,16 @@ def configure(env: "Environment"):
if platform.system() == "Linux":
env.Append(LIBS=["dl"])
- if not env["execinfo"] and 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 env["execinfo"]:
- env.Append(LIBS=["execinfo"])
-
- if not env.editor_build:
- import subprocess
- import re
-
- linker_version_str = subprocess.check_output(
- [env.subst(env["LINK"]), "-Wl,--version"] + env.subst(env["LINKFLAGS"])
- ).decode("utf-8")
- gnu_ld_version = re.search(r"^GNU ld [^$]*(\d+\.\d+)$", linker_version_str, re.MULTILINE)
- if not gnu_ld_version:
- print(
- "Warning: Creating export template binaries enabled for PCK embedding is currently only supported with GNU ld, not gold, LLD or mold."
- )
+ if platform.libc_ver()[0] != "glibc":
+ if env["execinfo"]:
+ env.Append(LIBS=["execinfo"])
+ env.Append(CPPDEFINES=["CRASH_HANDLER_ENABLED"])
else:
- if float(gnu_ld_version.group(1)) >= 2.30:
- env.Append(LINKFLAGS=["-T", "platform/linuxbsd/pck_embed.ld"])
- else:
- env.Append(LINKFLAGS=["-T", "platform/linuxbsd/pck_embed.legacy.ld"])
+ # The default crash handler depends on glibc, so if the host uses
+ # a different libc (BSD libc, musl), libexecinfo is required.
+ 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/doc_classes/EditorExportPlatformLinuxBSD.xml b/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml
index 07378566c3..a44c86202e 100644
--- a/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml
+++ b/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml
@@ -57,17 +57,11 @@
- [code]{exe_name}[/code] - Name of application executable.
- [code]{cmd_args}[/code] - Array of the command line argument for the application.
</member>
- <member name="texture_format/bptc" type="bool" setter="" getter="">
- If [code]true[/code], project textures are exported in the BPTC format.
+ <member name="texture_format/etc2_astc" type="bool" setter="" getter="">
+ If [code]true[/code], project textures are exported in the ETC2/ASTC format.
</member>
- <member name="texture_format/etc" type="bool" setter="" getter="">
- If [code]true[/code], project textures are exported in the ETC format.
- </member>
- <member name="texture_format/etc2" type="bool" setter="" getter="">
- If [code]true[/code], project textures are exported in the ETC2 format.
- </member>
- <member name="texture_format/s3tc" type="bool" setter="" getter="">
- If [code]true[/code], project textures are exported in the S3TC format.
+ <member name="texture_format/s3tc_bptc" type="bool" setter="" getter="">
+ If [code]true[/code], project textures are exported in the S3TC/BPTC format.
</member>
</members>
</class>
diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp
index 773b124c6a..936adddda3 100644
--- a/platform/linuxbsd/export/export_plugin.cpp
+++ b/platform/linuxbsd/export/export_plugin.cpp
@@ -146,12 +146,19 @@ List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<Edito
}
bool EditorExportPlatformLinuxBSD::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const {
- if (p_preset) {
- // Hide SSH options.
- bool ssh = p_preset->get("ssh_remote_deploy/enabled");
- if (!ssh && p_option != "ssh_remote_deploy/enabled" && p_option.begins_with("ssh_remote_deploy/")) {
- return false;
- }
+ if (p_preset == nullptr) {
+ return true;
+ }
+
+ bool advanced_options_enabled = p_preset->are_advanced_options_enabled();
+
+ // Hide SSH options.
+ bool ssh = p_preset->get("ssh_remote_deploy/enabled");
+ if (!ssh && p_option != "ssh_remote_deploy/enabled" && p_option.begins_with("ssh_remote_deploy/")) {
+ return false;
+ }
+ if (p_option == "dotnet/embed_build_outputs") {
+ return advanced_options_enabled;
}
return true;
}
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp
index a3633e72b7..e65404a531 100644
--- a/platform/linuxbsd/freedesktop_portal_desktop.cpp
+++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp
@@ -367,6 +367,7 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
}
ERR_FAIL_INDEX_V(int(p_mode), DisplayServer::FILE_DIALOG_MODE_SAVE_MAX, FAILED);
+ ERR_FAIL_NULL_V(monitor_connection, FAILED);
Vector<String> filter_names;
Vector<String> filter_exts;
@@ -406,24 +407,16 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
Error rng_err = rng.get_random_bytes(uuid, 64);
ERR_FAIL_COND_V_MSG(rng_err, rng_err, "Failed to generate unique token.");
- fd.connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
- if (dbus_error_is_set(&err)) {
- ERR_PRINT(vformat("Failed to open DBus connection: %s", err.message));
- dbus_error_free(&err);
- unsupported = true;
- return FAILED;
- }
-
- String dbus_unique_name = String::utf8(dbus_bus_get_unique_name(fd.connection));
+ String dbus_unique_name = String::utf8(dbus_bus_get_unique_name(monitor_connection));
String token = String::hex_encode_buffer(uuid, 64);
String path = vformat("/org/freedesktop/portal/desktop/request/%s/%s", dbus_unique_name.replace(".", "_").replace(":", ""), token);
- fd.path = vformat("type='signal',sender='org.freedesktop.portal.Desktop',path='%s',interface='org.freedesktop.portal.Request',member='Response',destination='%s'", path, dbus_unique_name);
- dbus_bus_add_match(fd.connection, fd.path.utf8().get_data(), &err);
+ fd.path = path;
+ fd.filter = vformat("type='signal',sender='org.freedesktop.portal.Desktop',path='%s',interface='org.freedesktop.portal.Request',member='Response',destination='%s'", path, dbus_unique_name);
+ dbus_bus_add_match(monitor_connection, fd.filter.utf8().get_data(), &err);
if (dbus_error_is_set(&err)) {
ERR_PRINT(vformat("Failed to add DBus match: %s", err.message));
dbus_error_free(&err);
- dbus_connection_unref(fd.connection);
return FAILED;
}
@@ -460,14 +453,13 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
dbus_message_iter_close_container(&iter, &arr_iter);
}
- DBusMessage *reply = dbus_connection_send_with_reply_and_block(fd.connection, message, DBUS_TIMEOUT_INFINITE, &err);
+ DBusMessage *reply = dbus_connection_send_with_reply_and_block(monitor_connection, message, DBUS_TIMEOUT_INFINITE, &err);
dbus_message_unref(message);
if (!reply || dbus_error_is_set(&err)) {
ERR_PRINT(vformat("Failed to send DBus message: %s", err.message));
dbus_error_free(&err);
- dbus_bus_remove_match(fd.connection, fd.path.utf8().get_data(), &err);
- dbus_connection_unref(fd.connection);
+ dbus_bus_remove_match(monitor_connection, fd.filter.utf8().get_data(), &err);
return FAILED;
}
@@ -479,19 +471,17 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
const char *new_path = nullptr;
dbus_message_iter_get_basic(&iter, &new_path);
if (String::utf8(new_path) != path) {
- dbus_bus_remove_match(fd.connection, fd.path.utf8().get_data(), &err);
+ dbus_bus_remove_match(monitor_connection, fd.filter.utf8().get_data(), &err);
if (dbus_error_is_set(&err)) {
ERR_PRINT(vformat("Failed to remove DBus match: %s", err.message));
dbus_error_free(&err);
- dbus_connection_unref(fd.connection);
return FAILED;
}
- fd.path = String::utf8(new_path);
- dbus_bus_add_match(fd.connection, fd.path.utf8().get_data(), &err);
+ fd.filter = String::utf8(new_path);
+ dbus_bus_add_match(monitor_connection, fd.filter.utf8().get_data(), &err);
if (dbus_error_is_set(&err)) {
ERR_PRINT(vformat("Failed to add DBus match: %s", err.message));
dbus_error_free(&err);
- dbus_connection_unref(fd.connection);
return FAILED;
}
}
@@ -506,83 +496,111 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
return OK;
}
-void FreeDesktopPortalDesktop::_file_dialog_callback(const Callable &p_callable, const Variant &p_status, const Variant &p_list, const Variant &p_index, const Variant &p_options, bool p_opt_in_cb) {
- if (p_opt_in_cb) {
- Variant ret;
- Callable::CallError ce;
- const Variant *args[4] = { &p_status, &p_list, &p_index, &p_options };
-
- p_callable.callp(args, 4, ret, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callable, args, 4, ce)));
- }
- } else {
- Variant ret;
- Callable::CallError ce;
- const Variant *args[3] = { &p_status, &p_list, &p_index };
+void FreeDesktopPortalDesktop::process_file_dialog_callbacks() {
+ MutexLock lock(file_dialog_mutex);
+ while (!pending_cbs.is_empty()) {
+ FileDialogCallback cb = pending_cbs.front()->get();
+ pending_cbs.pop_front();
+
+ if (cb.opt_in_cb) {
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[4] = { &cb.status, &cb.files, &cb.index, &cb.options };
+
+ cb.callback.callp(args, 4, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(cb.callback, args, 4, ce)));
+ }
+ } else {
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[3] = { &cb.status, &cb.files, &cb.index };
- p_callable.callp(args, 3, ret, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callable, args, 3, ce)));
+ cb.callback.callp(args, 3, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialog callback: %s.", Variant::get_callable_error_text(cb.callback, args, 3, ce)));
+ }
}
}
}
-void FreeDesktopPortalDesktop::_thread_file_dialog_monitor(void *p_ud) {
+void FreeDesktopPortalDesktop::_thread_monitor(void *p_ud) {
FreeDesktopPortalDesktop *portal = (FreeDesktopPortalDesktop *)p_ud;
- while (!portal->file_dialog_thread_abort.is_set()) {
- {
- MutexLock lock(portal->file_dialog_mutex);
- for (int i = portal->file_dialogs.size() - 1; i >= 0; i--) {
- bool remove = false;
- {
- FreeDesktopPortalDesktop::FileDialogData &fd = portal->file_dialogs.write[i];
- if (fd.connection) {
- while (true) {
- DBusMessage *msg = dbus_connection_pop_message(fd.connection);
- if (!msg) {
- break;
- } else if (dbus_message_is_signal(msg, "org.freedesktop.portal.Request", "Response")) {
- DBusMessageIter iter;
- if (dbus_message_iter_init(msg, &iter)) {
- bool cancel = false;
- Vector<String> uris;
- Dictionary options;
- int index = 0;
- file_chooser_parse_response(&iter, fd.filter_names, cancel, uris, index, options);
-
- if (fd.callback.is_valid()) {
- callable_mp(portal, &FreeDesktopPortalDesktop::_file_dialog_callback).call_deferred(fd.callback, !cancel, uris, index, options, fd.opt_in_cb);
- }
- if (fd.prev_focus != DisplayServer::INVALID_WINDOW_ID) {
- callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(fd.prev_focus);
- }
+ while (!portal->monitor_thread_abort.is_set()) {
+ if (portal->monitor_connection) {
+ while (true) {
+ DBusMessage *msg = dbus_connection_pop_message(portal->monitor_connection);
+ if (!msg) {
+ break;
+ } else if (dbus_message_is_signal(msg, "org.freedesktop.portal.Settings", "SettingChanged")) {
+ DBusMessageIter iter;
+ if (dbus_message_iter_init(msg, &iter)) {
+ const char *value;
+ dbus_message_iter_get_basic(&iter, &value);
+ String name_space = String::utf8(value);
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &value);
+ String key = String::utf8(value);
+
+ if (name_space == "org.freedesktop.appearance" && key == "color-scheme") {
+ callable_mp(portal, &FreeDesktopPortalDesktop::_system_theme_changed_callback).call_deferred();
+ }
+ }
+ } else if (dbus_message_is_signal(msg, "org.freedesktop.portal.Request", "Response")) {
+ String path = String::utf8(dbus_message_get_path(msg));
+ MutexLock lock(portal->file_dialog_mutex);
+ for (int i = 0; i < portal->file_dialogs.size(); i++) {
+ FreeDesktopPortalDesktop::FileDialogData &fd = portal->file_dialogs.write[i];
+ if (fd.path == path) {
+ DBusMessageIter iter;
+ if (dbus_message_iter_init(msg, &iter)) {
+ bool cancel = false;
+ Vector<String> uris;
+ Dictionary options;
+ int index = 0;
+ file_chooser_parse_response(&iter, fd.filter_names, cancel, uris, index, options);
+
+ if (fd.callback.is_valid()) {
+ FileDialogCallback cb;
+ cb.callback = fd.callback;
+ cb.status = !cancel;
+ cb.files = uris;
+ cb.index = index;
+ cb.options = options;
+ cb.opt_in_cb = fd.opt_in_cb;
+ portal->pending_cbs.push_back(cb);
+ }
+ if (fd.prev_focus != DisplayServer::INVALID_WINDOW_ID) {
+ callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(fd.prev_focus);
}
- dbus_message_unref(msg);
-
- DBusError err;
- dbus_error_init(&err);
- dbus_bus_remove_match(fd.connection, fd.path.utf8().get_data(), &err);
- dbus_error_free(&err);
- dbus_connection_unref(fd.connection);
- remove = true;
- break;
}
- dbus_message_unref(msg);
+
+ DBusError err;
+ dbus_error_init(&err);
+ dbus_bus_remove_match(portal->monitor_connection, fd.filter.utf8().get_data(), &err);
+ dbus_error_free(&err);
+
+ portal->file_dialogs.remove_at(i);
+ break;
}
- dbus_connection_read_write(fd.connection, 0);
}
}
- if (remove) {
- portal->file_dialogs.remove_at(i);
- }
+ dbus_message_unref(msg);
}
+ dbus_connection_read_write(portal->monitor_connection, 0);
}
+
usleep(50000);
}
}
+void FreeDesktopPortalDesktop::_system_theme_changed_callback() {
+ if (system_theme_changed.is_valid()) {
+ system_theme_changed.call();
+ }
+}
+
FreeDesktopPortalDesktop::FreeDesktopPortalDesktop() {
#ifdef SOWRAP_ENABLED
#ifdef DEBUG_ENABLED
@@ -611,25 +629,45 @@ FreeDesktopPortalDesktop::FreeDesktopPortalDesktop() {
unsupported = true;
}
+ DBusError err;
+ dbus_error_init(&err);
+ monitor_connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
+ if (dbus_error_is_set(&err)) {
+ dbus_error_free(&err);
+ } else {
+ theme_path = "type='signal',sender='org.freedesktop.portal.Desktop',interface='org.freedesktop.portal.Settings',member='SettingChanged'";
+ dbus_bus_add_match(monitor_connection, theme_path.utf8().get_data(), &err);
+ if (dbus_error_is_set(&err)) {
+ dbus_error_free(&err);
+ dbus_connection_unref(monitor_connection);
+ monitor_connection = nullptr;
+ }
+ dbus_connection_read_write(monitor_connection, 0);
+ }
+
if (!unsupported) {
- file_dialog_thread_abort.clear();
- file_dialog_thread.start(FreeDesktopPortalDesktop::_thread_file_dialog_monitor, this);
+ monitor_thread_abort.clear();
+ monitor_thread.start(FreeDesktopPortalDesktop::_thread_monitor, this);
}
}
FreeDesktopPortalDesktop::~FreeDesktopPortalDesktop() {
- file_dialog_thread_abort.set();
- if (file_dialog_thread.is_started()) {
- file_dialog_thread.wait_to_finish();
+ monitor_thread_abort.set();
+ if (monitor_thread.is_started()) {
+ monitor_thread.wait_to_finish();
}
- for (FreeDesktopPortalDesktop::FileDialogData &fd : file_dialogs) {
- if (fd.connection) {
- DBusError err;
+
+ if (monitor_connection) {
+ DBusError err;
+ for (FreeDesktopPortalDesktop::FileDialogData &fd : file_dialogs) {
dbus_error_init(&err);
- dbus_bus_remove_match(fd.connection, fd.path.utf8().get_data(), &err);
+ dbus_bus_remove_match(monitor_connection, fd.filter.utf8().get_data(), &err);
dbus_error_free(&err);
- dbus_connection_unref(fd.connection);
}
+ dbus_error_init(&err);
+ dbus_bus_remove_match(monitor_connection, theme_path.utf8().get_data(), &err);
+ dbus_error_free(&err);
+ dbus_connection_unref(monitor_connection);
}
}
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.h b/platform/linuxbsd/freedesktop_portal_desktop.h
index c9da387241..96c38de2c2 100644
--- a/platform/linuxbsd/freedesktop_portal_desktop.h
+++ b/platform/linuxbsd/freedesktop_portal_desktop.h
@@ -34,6 +34,7 @@
#ifdef DBUS_ENABLED
#include "core/os/thread.h"
+#include "core/os/thread_safe.h"
#include "servers/display_server.h"
struct DBusMessage;
@@ -55,23 +56,36 @@ private:
static void append_dbus_dict_bool(DBusMessageIter *p_iter, const String &p_key, bool p_value);
static bool file_chooser_parse_response(DBusMessageIter *p_iter, const Vector<String> &p_names, bool &r_cancel, Vector<String> &r_urls, int &r_index, Dictionary &r_options);
- void _file_dialog_callback(const Callable &p_callable, const Variant &p_status, const Variant &p_list, const Variant &p_index, const Variant &p_options, bool p_opt_in_cb);
-
struct FileDialogData {
Vector<String> filter_names;
- DBusConnection *connection = nullptr;
DisplayServer::WindowID prev_focus = DisplayServer::INVALID_WINDOW_ID;
Callable callback;
+ String filter;
String path;
bool opt_in_cb = false;
};
+ struct FileDialogCallback {
+ Callable callback;
+ Variant status;
+ Variant files;
+ Variant index;
+ Variant options;
+ bool opt_in_cb = false;
+ };
+ List<FileDialogCallback> pending_cbs;
+
Mutex file_dialog_mutex;
Vector<FileDialogData> file_dialogs;
- Thread file_dialog_thread;
- SafeFlag file_dialog_thread_abort;
+ Thread monitor_thread;
+ SafeFlag monitor_thread_abort;
+ DBusConnection *monitor_connection = nullptr;
+
+ String theme_path;
+ Callable system_theme_changed;
+ void _system_theme_changed_callback();
- static void _thread_file_dialog_monitor(void *p_ud);
+ static void _thread_monitor(void *p_ud);
public:
FreeDesktopPortalDesktop();
@@ -80,12 +94,16 @@ public:
bool is_supported() { return !unsupported; }
Error file_dialog_show(DisplayServer::WindowID p_window_id, const String &p_xid, const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, DisplayServer::FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb);
+ void process_file_dialog_callbacks();
// Retrieve the system's preferred color scheme.
// 0: No preference or unknown.
// 1: Prefer dark appearance.
// 2: Prefer light appearance.
uint32_t get_appearance_color_scheme();
+ void set_system_theme_change_callback(const Callable &p_system_theme_changed) {
+ system_theme_changed = p_system_theme_changed;
+ }
};
#endif // DBUS_ENABLED
diff --git a/platform/linuxbsd/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp
index efad9c8594..b0880c86b8 100644
--- a/platform/linuxbsd/godot_linuxbsd.cpp
+++ b/platform/linuxbsd/godot_linuxbsd.cpp
@@ -41,6 +41,18 @@
#include <sys/resource.h>
#endif
+// For export templates, add a section; the exporter will patch it to enclose
+// the data appended to the executable (bundled PCK).
+#if !defined(TOOLS_ENABLED) && defined(__GNUC__)
+static const char dummy[8] __attribute__((section("pck"), used)) = { 0 };
+
+// Dummy function to prevent LTO from discarding "pck" section.
+extern "C" const char *pck_section_dummy_call() __attribute__((used));
+extern "C" const char *pck_section_dummy_call() {
+ return &dummy[0];
+}
+#endif
+
int main(int argc, char *argv[]) {
#if defined(SANITIZERS_ENABLED)
// Note: Set stack size to be at least 30 MB (vs 8 MB default) to avoid overflow, address sanitizer can increase stack usage up to 3 times.
@@ -60,18 +72,19 @@ int main(int argc, char *argv[]) {
char *ret = getcwd(cwd, PATH_MAX);
Error err = Main::setup(argv[0], argc - 1, &argv[1]);
+
if (err != OK) {
free(cwd);
-
if (err == ERR_HELP) { // Returned by --help and --version, so success.
- return 0;
+ return EXIT_SUCCESS;
}
- return 255;
+ return EXIT_FAILURE;
}
- if (Main::start()) {
- os.set_exit_code(EXIT_SUCCESS);
- os.run(); // it is actually the OS that decides how to run
+ if (Main::start() == EXIT_SUCCESS) {
+ os.run();
+ } else {
+ os.set_exit_code(EXIT_FAILURE);
}
Main::cleanup();
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index 827c567785..6e546c4531 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -175,7 +175,7 @@ void JoypadLinux::enumerate_joypads(udev *p_udev) {
if (devnode) {
String devnode_str = devnode;
- if (devnode_str.find(ignore_str) == -1) {
+ if (!devnode_str.contains(ignore_str)) {
open_joypad(devnode);
}
}
@@ -214,7 +214,7 @@ void JoypadLinux::monitor_joypads(udev *p_udev) {
const char *devnode = udev_device_get_devnode(dev);
if (devnode) {
String devnode_str = devnode;
- if (devnode_str.find(ignore_str) == -1) {
+ if (!devnode_str.contains(ignore_str)) {
if (action == "add") {
open_joypad(devnode);
} else if (String(action) == "remove") {
@@ -244,7 +244,7 @@ void JoypadLinux::monitor_joypads() {
continue;
}
sprintf(fname, "/dev/input/%.*s", 16, current->d_name);
- if (attached_devices.find(fname) == -1) {
+ if (!attached_devices.has(fname)) {
open_joypad(fname);
}
}
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index f9e1aca742..6355562feb 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -34,6 +34,7 @@
#include "core/io/dir_access.h"
#include "main/main.h"
#include "servers/display_server.h"
+#include "servers/rendering_server.h"
#ifdef X11_ENABLED
#include "x11/display_server_x11.h"
@@ -61,6 +62,10 @@
#include <mntent.h>
#endif
+#if defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#endif
+
void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) {
const char *message_programs[] = { "zenity", "kdialog", "Xdialog", "xmessage" };
@@ -127,14 +132,6 @@ void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) {
}
}
-int OS_LinuxBSD::get_low_processor_usage_mode_sleep_usec() const {
- if (DisplayServer::get_singleton() == nullptr || DisplayServer::get_singleton()->get_name() != "Wayland" || is_in_low_processor_usage_mode()) {
- return OS::get_low_processor_usage_mode_sleep_usec();
- }
-
- return 500; // Roughly 2000 FPS, improves frame time when emulating VSync.
-}
-
void OS_LinuxBSD::initialize() {
crash_handler.initialize();
@@ -152,28 +149,48 @@ void OS_LinuxBSD::initialize_joypads() {
String OS_LinuxBSD::get_unique_id() const {
static String machine_id;
if (machine_id.is_empty()) {
+#if defined(__FreeBSD__)
+ const int mib[2] = { CTL_KERN, KERN_HOSTUUID };
+ char buf[4096];
+ memset(buf, 0, sizeof(buf));
+ size_t len = sizeof(buf) - 1;
+ if (sysctl(mib, 2, buf, &len, 0x0, 0) != -1) {
+ machine_id = String::utf8(buf).replace("-", "");
+ }
+#else
Ref<FileAccess> f = FileAccess::open("/etc/machine-id", FileAccess::READ);
if (f.is_valid()) {
while (machine_id.is_empty() && !f->eof_reached()) {
machine_id = f->get_line().strip_edges();
}
}
+#endif
}
return machine_id;
}
String OS_LinuxBSD::get_processor_name() const {
+#if defined(__FreeBSD__)
+ const int mib[2] = { CTL_HW, HW_MODEL };
+ char buf[4096];
+ memset(buf, 0, sizeof(buf));
+ size_t len = sizeof(buf) - 1;
+ if (sysctl(mib, 2, buf, &len, 0x0, 0) != -1) {
+ return String::utf8(buf);
+ }
+#else
Ref<FileAccess> f = FileAccess::open("/proc/cpuinfo", FileAccess::READ);
ERR_FAIL_COND_V_MSG(f.is_null(), "", String("Couldn't open `/proc/cpuinfo` to get the CPU model name. Returning an empty string."));
while (!f->eof_reached()) {
const String line = f->get_line();
- if (line.find("model name") != -1) {
+ if (line.contains("model name")) {
return line.split(":")[1].strip_edges();
}
}
+#endif
- ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name from `/proc/cpuinfo`. Returning an empty string."));
+ ERR_FAIL_V_MSG("", String("Couldn't get the CPU model. Returning an empty string."));
}
bool OS_LinuxBSD::is_sandboxed() const {
@@ -252,7 +269,7 @@ String OS_LinuxBSD::get_systemd_os_release_info_value(const String &key) const {
if (f.is_valid()) {
while (!f->eof_reached()) {
const String line = f->get_line();
- if (line.find(key) != -1) {
+ if (line.contains(key)) {
String value = line.split("=")[1].strip_edges();
value = value.trim_prefix("\"");
return value.trim_suffix("\"");
@@ -486,7 +503,7 @@ Vector<String> OS_LinuxBSD::lspci_get_device_value(Vector<String> vendor_device_
return values;
}
-Error OS_LinuxBSD::shell_open(String p_uri) {
+Error OS_LinuxBSD::shell_open(const String &p_uri) {
Error ok;
int err_code;
List<String> args;
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index 6ea2fc8e94..9084061eb9 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -118,7 +118,7 @@ public:
virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const override;
- virtual Error shell_open(String p_uri) override;
+ virtual Error shell_open(const String &p_uri) override;
virtual String get_unique_id() const override;
virtual String get_processor_name() const override;
@@ -127,8 +127,6 @@ public:
virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
- virtual int get_low_processor_usage_mode_sleep_usec() const override;
-
virtual bool _check_internal_feature_support(const String &p_feature) override;
void run();
diff --git a/platform/linuxbsd/pck_embed.ld b/platform/linuxbsd/pck_embed.ld
deleted file mode 100644
index 57a1994043..0000000000
--- a/platform/linuxbsd/pck_embed.ld
+++ /dev/null
@@ -1,10 +0,0 @@
-SECTIONS
-{
- /* Add a zero-sized section; the exporter will patch it to enclose the data appended to the executable (embedded PCK) */
- pck 0 (INFO) :
- {
- /* binutils >= 2.30 allow it being zero-sized, but needs something between the braces to keep the section */
- . = ALIGN(8);
- }
-}
-INSERT AFTER .rodata;
diff --git a/platform/linuxbsd/pck_embed.legacy.ld b/platform/linuxbsd/pck_embed.legacy.ld
deleted file mode 100644
index a23013ba7a..0000000000
--- a/platform/linuxbsd/pck_embed.legacy.ld
+++ /dev/null
@@ -1,10 +0,0 @@
-SECTIONS
-{
- /* The exporter will patch this section to enclose the data appended to the executable (embedded PCK) */
- pck 0 (INFO) : AT ( ADDR (.rodata) + SIZEOF (.rodata) )
- {
- /* binutils < 2.30 need some actual content for the linker not to discard the section */
- BYTE(0);
- }
-}
-INSERT AFTER .rodata;
diff --git a/platform/linuxbsd/platform_linuxbsd_builders.py b/platform/linuxbsd/platform_linuxbsd_builders.py
index 58234f3748..46fa1947e8 100644
--- a/platform/linuxbsd/platform_linuxbsd_builders.py
+++ b/platform/linuxbsd/platform_linuxbsd_builders.py
@@ -1,17 +1,10 @@
-"""Functions used to generate source files during build time
+"""Functions used to generate source files during build time"""
-All such functions are invoked in a subprocess on Windows to prevent build flakiness.
-
-"""
import os
-from platform_methods import subprocess_main
def make_debug_linuxbsd(target, source, env):
- os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
- os.system("strip --strip-debug --strip-unneeded {0}".format(target[0]))
- os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
-
-
-if __name__ == "__main__":
- subprocess_main(globals())
+ dst = str(target[0])
+ os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(dst))
+ os.system("strip --strip-debug --strip-unneeded {0}".format(dst))
+ os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(dst))
diff --git a/platform/linuxbsd/wayland/SCsub b/platform/linuxbsd/wayland/SCsub
index d2b000ff66..add5bdb504 100644
--- a/platform/linuxbsd/wayland/SCsub
+++ b/platform/linuxbsd/wayland/SCsub
@@ -11,15 +11,15 @@ if env["use_sowrap"]:
WAYLAND_BUILDERS_SOWRAP = {
"WAYLAND_API_HEADER": Builder(
action=Action(
- "wayland-scanner -c client-header < ${SOURCE} | sed 's:wayland-client-core\.h:../dynwrappers/wayland-client-core-so_wrap\.h:' > ${TARGET}",
+ 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}"',
),
single_source=True,
),
"WAYLAND_API_CODE": Builder(
action=Action(
- "wayland-scanner -c private-code < ${SOURCE} | sed 's:wayland-util\.h:../dynwrappers/wayland-client-core-so_wrap\.h:' > ${TARGET}",
- 'Generating Wayland protocol marshalling code: "${TARGET}"',
+ 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}"',
),
single_source=True,
),
@@ -29,15 +29,15 @@ else:
WAYLAND_BUILDERS = {
"WAYLAND_API_HEADER": Builder(
action=Action(
- "wayland-scanner -c client-header < ${SOURCE} > ${TARGET}",
+ r"wayland-scanner -c client-header < ${SOURCE} > ${TARGET}",
'Generating Wayland client header: "${TARGET}"',
),
single_source=True,
),
"WAYLAND_API_CODE": Builder(
action=Action(
- "wayland-scanner -c private-code < ${SOURCE} > ${TARGET}",
- 'Generating Wayland protocol marshalling code: "${TARGET}"',
+ r"wayland-scanner -c private-code < ${SOURCE} > ${TARGET}",
+ 'Generating Wayland protocol marshaling code: "${TARGET}"',
),
single_source=True,
),
@@ -195,10 +195,11 @@ if env["use_sowrap"]:
if env["vulkan"]:
- source_files.append("vulkan_context_wayland.cpp")
+ source_files.append("rendering_context_driver_vulkan_wayland.cpp")
if env["opengl3"]:
source_files.append("egl_manager_wayland.cpp")
+ source_files.append("egl_manager_wayland_gles.cpp")
objects = []
diff --git a/platform/linuxbsd/wayland/detect_prime_egl.cpp b/platform/linuxbsd/wayland/detect_prime_egl.cpp
index 4bee32ae3a..4c97a80039 100644
--- a/platform/linuxbsd/wayland/detect_prime_egl.cpp
+++ b/platform/linuxbsd/wayland/detect_prime_egl.cpp
@@ -69,7 +69,7 @@ void DetectPrimeEGL::create_context() {
EGLConfig egl_config;
EGLContext egl_context = EGL_NO_CONTEXT;
- eglInitialize(egl_display, NULL, NULL);
+ eglInitialize(egl_display, nullptr, nullptr);
#if defined(GLAD_ENABLED)
if (!gladLoaderLoadEGL(egl_display)) {
diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp
index 02b715056a..f7995472d0 100644
--- a/platform/linuxbsd/wayland/display_server_wayland.cpp
+++ b/platform/linuxbsd/wayland/display_server_wayland.cpp
@@ -46,6 +46,8 @@
#ifdef GLES3_ENABLED
#include "detect_prime_egl.h"
#include "drivers/gles3/rasterizer_gles3.h"
+#include "wayland/egl_manager_wayland.h"
+#include "wayland/egl_manager_wayland_gles.h"
#endif
String DisplayServerWayland::_get_app_id_from_context(Context p_context) {
@@ -100,8 +102,8 @@ void DisplayServerWayland::_resize_window(const Size2i &p_size) {
wd.rect.size = p_size;
#ifdef RD_ENABLED
- if (wd.visible && context_rd) {
- context_rd->window_resize(MAIN_WINDOW_ID, wd.rect.size.width, wd.rect.size.height);
+ if (wd.visible && rendering_context) {
+ rendering_context->window_set_size(MAIN_WINDOW_ID, wd.rect.size.width, wd.rect.size.height);
}
#endif
@@ -140,10 +142,10 @@ void DisplayServerWayland::_show_window() {
// the only acceptable way of implementing window showing is to move the
// graphics context window creation logic here.
#ifdef RD_ENABLED
- if (context_rd) {
+ if (rendering_context) {
union {
#ifdef VULKAN_ENABLED
- VulkanContextWayland::WindowPlatformData vulkan;
+ RenderingContextDriverVulkanWayland::WindowPlatformData vulkan;
#endif
} wpd;
#ifdef VULKAN_ENABLED
@@ -152,14 +154,17 @@ void DisplayServerWayland::_show_window() {
wpd.vulkan.display = wayland_thread.get_wl_display();
}
#endif
- Error err = context_rd->window_create(wd.id, wd.vsync_mode, wd.rect.size.width, wd.rect.size.height, &wpd);
- ERR_FAIL_COND_MSG(err != OK, vformat("Can't create a %s window", context_rd->get_api_name()));
+ Error err = rendering_context->window_create(wd.id, &wpd);
+ ERR_FAIL_COND_MSG(err != OK, vformat("Can't create a %s window", rendering_driver));
- emulate_vsync = (context_rd->get_vsync_mode(wd.id) == DisplayServer::VSYNC_ENABLED);
+ rendering_context->window_set_size(wd.id, wd.rect.size.width, wd.rect.size.height);
+ rendering_context->window_set_vsync_mode(wd.id, wd.vsync_mode);
+
+ emulate_vsync = (rendering_context->window_get_vsync_mode(wd.id) == DisplayServer::VSYNC_ENABLED);
if (emulate_vsync) {
print_verbose("VSYNC: manually throttling frames using MAILBOX.");
- context_rd->set_vsync_mode(wd.id, DisplayServer::VSYNC_MAILBOX);
+ rendering_context->window_set_vsync_mode(wd.id, DisplayServer::VSYNC_MAILBOX);
}
}
#endif
@@ -189,19 +194,37 @@ 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;
+
+ //case FEATURE_NATIVE_DIALOG:
+ //case FEATURE_NATIVE_DIALOG_INPUT:
#ifdef DBUS_ENABLED
- case FEATURE_NATIVE_DIALOG:
+ case FEATURE_NATIVE_DIALOG_FILE: {
+ return true;
+ } break;
#endif
- case FEATURE_HIDPI: {
+
+#ifdef SPEECHD_ENABLED
+ case FEATURE_TEXT_TO_SPEECH: {
return true;
} break;
+#endif
default: {
return false;
@@ -272,6 +295,10 @@ bool DisplayServerWayland::is_dark_mode() const {
}
}
+void DisplayServerWayland::set_system_theme_change_callback(const Callable &p_callable) {
+ portal_desktop->set_system_theme_change_callback(p_callable);
+}
+
Error DisplayServerWayland::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
WindowID window_id = MAIN_WINDOW_ID;
// TODO: Use window IDs for multiwindow support.
@@ -523,7 +550,15 @@ float DisplayServerWayland::screen_get_scale(int p_screen) const {
MutexLock mutex_lock(wayland_thread.mutex);
if (p_screen == SCREEN_OF_MAIN_WINDOW) {
- p_screen = window_get_current_screen();
+ // Wayland does not expose fractional scale factors at the screen-level, but
+ // some code relies on it. Since this special screen is the default and a lot
+ // of code relies on it, we'll return the window's scale, which is what we
+ // really care about. After all, we have very little use of the actual screen
+ // enumeration APIs and we're (for now) in single-window mode anyways.
+ struct wl_surface *wl_surface = wayland_thread.window_get_wl_surface(MAIN_WINDOW_ID);
+ WaylandThread::WindowState *ws = wayland_thread.wl_surface_get_window_state(wl_surface);
+
+ return wayland_thread.window_state_get_scale_factor(ws);
}
return wayland_thread.screen_get_data(p_screen).scale;
@@ -562,9 +597,9 @@ void DisplayServerWayland::screen_set_keep_on(bool p_enable) {
bool DisplayServerWayland::screen_is_kept_on() const {
#ifdef DBUS_ENABLED
return wayland_thread.window_get_idle_inhibition(MAIN_WINDOW_ID) || screensaver_inhibited;
-#endif
-
+#else
return wayland_thread.window_get_idle_inhibition(MAIN_WINDOW_ID);
+#endif
}
Vector<DisplayServer::WindowID> DisplayServerWayland::get_window_list() const {
@@ -860,11 +895,11 @@ bool DisplayServerWayland::window_is_focused(WindowID p_window_id) const {
}
bool DisplayServerWayland::window_can_draw(DisplayServer::WindowID p_window_id) const {
- return frame;
+ return !suspended;
}
bool DisplayServerWayland::can_any_window_draw() const {
- return frame;
+ return !suspended;
}
void DisplayServerWayland::window_set_ime_active(const bool p_active, DisplayServer::WindowID p_window_id) {
@@ -885,14 +920,14 @@ void DisplayServerWayland::window_set_vsync_mode(DisplayServer::VSyncMode p_vsyn
MutexLock mutex_lock(wayland_thread.mutex);
#ifdef RD_ENABLED
- if (context_rd) {
- context_rd->set_vsync_mode(p_window_id, p_vsync_mode);
+ if (rendering_context) {
+ rendering_context->window_set_vsync_mode(p_window_id, p_vsync_mode);
- emulate_vsync = (context_rd->get_vsync_mode(p_window_id) == DisplayServer::VSYNC_ENABLED);
+ emulate_vsync = (rendering_context->window_get_vsync_mode(p_window_id) == DisplayServer::VSYNC_ENABLED);
if (emulate_vsync) {
print_verbose("VSYNC: manually throttling frames using MAILBOX.");
- context_rd->set_vsync_mode(p_window_id, DisplayServer::VSYNC_MAILBOX);
+ rendering_context->window_set_vsync_mode(p_window_id, DisplayServer::VSYNC_MAILBOX);
}
}
#endif // VULKAN_ENABLED
@@ -917,8 +952,8 @@ DisplayServer::VSyncMode DisplayServerWayland::window_get_vsync_mode(DisplayServ
}
#ifdef VULKAN_ENABLED
- if (context_rd) {
- return context_rd->get_vsync_mode(p_window_id);
+ if (rendering_context) {
+ return rendering_context->window_get_vsync_mode(p_window_id);
}
#endif // VULKAN_ENABLED
@@ -983,36 +1018,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];
@@ -1136,7 +1144,38 @@ void DisplayServerWayland::process_events() {
wayland_thread.keyboard_echo_keys();
- frame = wayland_thread.get_reset_frame();
+ if (!suspended) {
+ if (emulate_vsync) {
+ // Due to various reasons, we manually handle display synchronization by
+ // waiting for a frame event (request to draw) or, if available, the actual
+ // window's suspend status. When a window is suspended, we can avoid drawing
+ // altogether, either because the compositor told us that we don't need to or
+ // because the pace of the frame events became unreliable.
+ bool frame = wayland_thread.wait_frame_suspend_ms(1000);
+ if (!frame) {
+ suspended = true;
+ }
+ } else {
+ if (wayland_thread.is_suspended()) {
+ suspended = true;
+ }
+ }
+
+ if (suspended) {
+ DEBUG_LOG_WAYLAND("Window suspended.");
+ }
+ } else {
+ if (wayland_thread.get_reset_frame()) {
+ // At last, a sign of life! We're no longer suspended.
+ suspended = false;
+ }
+ }
+
+#ifdef DBUS_ENABLED
+ if (portal_desktop) {
+ portal_desktop->process_file_dialog_callbacks();
+ }
+#endif
wayland_thread.mutex.unlock();
@@ -1151,14 +1190,6 @@ void DisplayServerWayland::release_rendering_thread() {
#endif
}
-void DisplayServerWayland::make_rendering_thread() {
-#ifdef GLES3_ENABLED
- if (egl_manager) {
- egl_manager->make_current();
- }
-#endif
-}
-
void DisplayServerWayland::swap_buffers() {
#ifdef GLES3_ENABLED
if (egl_manager) {
@@ -1187,6 +1218,7 @@ Vector<String> DisplayServerWayland::get_rendering_drivers_func() {
#ifdef GLES3_ENABLED
drivers.push_back("opengl3");
+ drivers.push_back("opengl3_es");
#endif
return drivers;
@@ -1226,6 +1258,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);
@@ -1235,16 +1269,16 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
#ifdef RD_ENABLED
#ifdef VULKAN_ENABLED
- if (p_rendering_driver == "vulkan") {
- context_rd = memnew(VulkanContextWayland);
+ if (rendering_driver == "vulkan") {
+ rendering_context = memnew(RenderingContextDriverVulkanWayland);
}
#endif
- if (context_rd) {
- if (context_rd->initialize() != OK) {
- ERR_PRINT(vformat("Could not initialize %s", context_rd->get_api_name()));
- memdelete(context_rd);
- context_rd = nullptr;
+ 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;
}
@@ -1252,7 +1286,14 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
#endif
#ifdef GLES3_ENABLED
- if (p_rendering_driver == "opengl3") {
+ if (rendering_driver == "opengl3" || rendering_driver == "opengl3_es") {
+#ifdef SOWRAP_ENABLED
+ if (initialize_wayland_egl(dylibloader_verbose) != 0) {
+ WARN_PRINT("Can't load the Wayland EGL library.");
+ return;
+ }
+#endif // SOWRAP_ENABLED
+
if (getenv("DRI_PRIME") == nullptr) {
int prime_idx = -1;
@@ -1295,23 +1336,38 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
}
}
- egl_manager = memnew(EGLManagerWayland);
+ if (rendering_driver == "opengl3") {
+ egl_manager = memnew(EGLManagerWayland);
-#ifdef SOWRAP_ENABLED
- if (initialize_wayland_egl(dylibloader_verbose) != 0) {
- WARN_PRINT("Can't load the Wayland EGL library.");
- return;
- }
-#endif // SOWRAP_ENABLED
+ if (egl_manager->initialize() != OK || egl_manager->open_display(wayland_thread.get_wl_display()) != OK) {
+ memdelete(egl_manager);
+ egl_manager = nullptr;
- if (egl_manager->initialize() != OK) {
- memdelete(egl_manager);
- egl_manager = nullptr;
- r_error = ERR_CANT_CREATE;
- ERR_FAIL_MSG("Could not initialize GLES3.");
+ bool fallback = GLOBAL_GET("rendering/gl_compatibility/fallback_to_gles");
+ if (fallback) {
+ WARN_PRINT("Your video card drivers seem not to support the required OpenGL version, switching to OpenGLES.");
+ rendering_driver = "opengl3_es";
+ } else {
+ r_error = ERR_UNAVAILABLE;
+ ERR_FAIL_MSG("Could not initialize OpenGL.");
+ }
+ } else {
+ RasterizerGLES3::make_current(true);
+ }
}
- RasterizerGLES3::make_current(true);
+ if (rendering_driver == "opengl3_es") {
+ egl_manager = memnew(EGLManagerWaylandGLES);
+
+ if (egl_manager->initialize() != OK) {
+ memdelete(egl_manager);
+ egl_manager = nullptr;
+ r_error = ERR_CANT_CREATE;
+ ERR_FAIL_MSG("Could not initialize GLES3.");
+ }
+
+ RasterizerGLES3::make_current(false);
+ }
}
#endif // GLES3_ENABLED
@@ -1329,9 +1385,10 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
_show_window();
#ifdef RD_ENABLED
- if (context_rd) {
+ if (rendering_context) {
rendering_device = memnew(RenderingDevice);
- rendering_device->initialize(context_rd);
+ rendering_device->initialize(rendering_context, MAIN_WINDOW_ID);
+ rendering_device->screen_create(MAIN_WINDOW_ID);
RendererCompositorRD::make_current();
}
@@ -1349,10 +1406,20 @@ 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 (context_rd) {
- context_rd->window_destroy(MAIN_WINDOW_ID);
+ if (rendering_device) {
+ rendering_device->screen_free(MAIN_WINDOW_ID);
+ }
+
+ if (rendering_context) {
+ rendering_context->window_destroy(MAIN_WINDOW_ID);
}
#endif
@@ -1374,12 +1441,11 @@ DisplayServerWayland::~DisplayServerWayland() {
// Destroy all drivers.
#ifdef RD_ENABLED
if (rendering_device) {
- rendering_device->finalize();
memdelete(rendering_device);
}
- if (context_rd) {
- memdelete(context_rd);
+ if (rendering_context) {
+ memdelete(rendering_context);
}
#endif
diff --git a/platform/linuxbsd/wayland/display_server_wayland.h b/platform/linuxbsd/wayland/display_server_wayland.h
index 3e7f3c4cb4..1bad358462 100644
--- a/platform/linuxbsd/wayland/display_server_wayland.h
+++ b/platform/linuxbsd/wayland/display_server_wayland.h
@@ -39,13 +39,13 @@
#include "servers/rendering/rendering_device.h"
#ifdef VULKAN_ENABLED
-#include "wayland/vulkan_context_wayland.h"
+#include "wayland/rendering_context_driver_vulkan_wayland.h"
#endif
#endif //RD_ENABLED
#ifdef GLES3_ENABLED
-#include "wayland/egl_manager_wayland.h"
+#include "drivers/egl/egl_manager.h"
#endif
#if defined(SPEECHD_ENABLED)
@@ -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>
@@ -117,23 +115,24 @@ class DisplayServerWayland : public DisplayServer {
Context context;
- bool frame = false;
+ bool suspended = false;
bool emulate_vsync = false;
String rendering_driver;
#ifdef RD_ENABLED
- ApiContextRD *context_rd = nullptr;
+ RenderingContextDriver *rendering_context = nullptr;
RenderingDevice *rendering_device = nullptr;
#endif
#ifdef GLES3_ENABLED
- EGLManagerWayland *egl_manager = nullptr;
+ EGLManager *egl_manager = nullptr;
#endif
#ifdef SPEECHD_ENABLED
TTS_Linux *tts = nullptr;
#endif
+ NativeMenu *native_menu = nullptr;
#if DBUS_ENABLED
FreeDesktopPortalDesktop *portal_desktop = nullptr;
@@ -171,6 +170,7 @@ public:
#ifdef DBUS_ENABLED
virtual bool is_dark_mode_supported() const override;
virtual bool is_dark_mode() const override;
+ virtual void set_system_theme_change_callback(const Callable &p_callable) override;
virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) override;
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;
@@ -276,7 +276,6 @@ public:
virtual void process_events() override;
virtual void release_rendering_thread() override;
- virtual void make_rendering_thread() override;
virtual void swap_buffers() override;
virtual void set_context(Context p_context) override;
diff --git a/platform/linuxbsd/wayland/egl_manager_wayland_gles.cpp b/platform/linuxbsd/wayland/egl_manager_wayland_gles.cpp
new file mode 100644
index 0000000000..9431b18f05
--- /dev/null
+++ b/platform/linuxbsd/wayland/egl_manager_wayland_gles.cpp
@@ -0,0 +1,64 @@
+/**************************************************************************/
+/* egl_manager_wayland_gles.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "egl_manager_wayland_gles.h"
+
+#ifdef WAYLAND_ENABLED
+#ifdef EGL_ENABLED
+#ifdef GLES3_ENABLED
+
+const char *EGLManagerWaylandGLES::_get_platform_extension_name() const {
+ return "EGL_KHR_platform_wayland";
+}
+
+EGLenum EGLManagerWaylandGLES::_get_platform_extension_enum() const {
+ return EGL_PLATFORM_WAYLAND_KHR;
+}
+
+EGLenum EGLManagerWaylandGLES::_get_platform_api_enum() const {
+ return EGL_OPENGL_ES_API;
+}
+
+Vector<EGLAttrib> EGLManagerWaylandGLES::_get_platform_display_attributes() const {
+ return Vector<EGLAttrib>();
+}
+
+Vector<EGLint> EGLManagerWaylandGLES::_get_platform_context_attribs() const {
+ Vector<EGLint> ret;
+ ret.push_back(EGL_CONTEXT_MAJOR_VERSION);
+ ret.push_back(3);
+ ret.push_back(EGL_NONE);
+
+ return ret;
+}
+
+#endif // GLES3_ENABLED
+#endif // EGL_ENABLED
+#endif // WAYLAND_ENABLED
diff --git a/platform/linuxbsd/wayland/egl_manager_wayland_gles.h b/platform/linuxbsd/wayland/egl_manager_wayland_gles.h
new file mode 100644
index 0000000000..f526f18277
--- /dev/null
+++ b/platform/linuxbsd/wayland/egl_manager_wayland_gles.h
@@ -0,0 +1,53 @@
+/**************************************************************************/
+/* egl_manager_wayland_gles.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef EGL_MANAGER_WAYLAND_GLES_H
+#define EGL_MANAGER_WAYLAND_GLES_H
+
+#ifdef WAYLAND_ENABLED
+#ifdef EGL_ENABLED
+#ifdef GLES3_ENABLED
+
+#include "drivers/egl/egl_manager.h"
+
+class EGLManagerWaylandGLES : public EGLManager {
+public:
+ virtual const char *_get_platform_extension_name() const override;
+ virtual EGLenum _get_platform_extension_enum() const override;
+ virtual EGLenum _get_platform_api_enum() const override;
+ virtual Vector<EGLAttrib> _get_platform_display_attributes() const override;
+ virtual Vector<EGLint> _get_platform_context_attribs() const override;
+};
+
+#endif // GLES3_ENABLED
+#endif // EGL_ENABLED
+#endif // WAYLAND_ENABLED
+
+#endif // EGL_MANAGER_WAYLAND_GLES_H
diff --git a/platform/linuxbsd/wayland/vulkan_context_wayland.cpp b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp
index b3f28a1678..c874c45a8a 100644
--- a/platform/linuxbsd/wayland/vulkan_context_wayland.cpp
+++ b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.cpp
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* vulkan_context_wayland.cpp */
+/* rendering_context_driver_vulkan_wayland.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,32 +28,43 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#include "vulkan_context_wayland.h"
-
#ifdef VULKAN_ENABLED
+#include "rendering_context_driver_vulkan_wayland.h"
+
#ifdef USE_VOLK
#include <volk.h>
#else
#include <vulkan/vulkan.h>
#endif
-const char *VulkanContextWayland::_get_platform_surface_extension() const {
+const char *RenderingContextDriverVulkanWayland::_get_platform_surface_extension() const {
return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
}
-Error VulkanContextWayland::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
- const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkanWayland::surface_create(const void *p_platform_data) {
+ const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
+
+ VkWaylandSurfaceCreateInfoKHR create_info = {};
+ create_info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
+ create_info.display = wpd->display;
+ create_info.surface = wpd->surface;
+
+ VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+ VkResult err = vkCreateWaylandSurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface);
+ ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
- VkWaylandSurfaceCreateInfoKHR createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
- createInfo.display = wpd->display;
- createInfo.surface = wpd->surface;
+ Surface *surface = memnew(Surface);
+ surface->vk_surface = vk_surface;
+ return SurfaceID(surface);
+}
+
+RenderingContextDriverVulkanWayland::RenderingContextDriverVulkanWayland() {
+ // Does nothing.
+}
- VkSurfaceKHR surface = VK_NULL_HANDLE;
- VkResult err = vkCreateWaylandSurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
- ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
- return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
+RenderingContextDriverVulkanWayland::~RenderingContextDriverVulkanWayland() {
+ // Does nothing.
}
#endif // VULKAN_ENABLED
diff --git a/platform/linuxbsd/wayland/vulkan_context_wayland.h b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h
index b0a7d1ff87..dfebca1890 100644
--- a/platform/linuxbsd/wayland/vulkan_context_wayland.h
+++ b/platform/linuxbsd/wayland/rendering_context_driver_vulkan_wayland.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* vulkan_context_wayland.h */
+/* rendering_context_driver_vulkan_wayland.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,15 +28,19 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef VULKAN_CONTEXT_WAYLAND_H
-#define VULKAN_CONTEXT_WAYLAND_H
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_WAYLAND_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_WAYLAND_H
#ifdef VULKAN_ENABLED
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
-class VulkanContextWayland : public VulkanContext {
- const char *_get_platform_surface_extension() const override final;
+class RenderingContextDriverVulkanWayland : public RenderingContextDriverVulkan {
+private:
+ virtual const char *_get_platform_surface_extension() const override final;
+
+protected:
+ SurfaceID surface_create(const void *p_platform_data) override final;
public:
struct WindowPlatformData {
@@ -44,9 +48,10 @@ public:
struct wl_surface *surface;
};
- Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
+ RenderingContextDriverVulkanWayland();
+ ~RenderingContextDriverVulkanWayland();
};
#endif // VULKAN_ENABLED
-#endif // VULKAN_CONTEXT_WAYLAND_H
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_WAYLAND_H
diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp
index 7e96f2dd75..aabf1abdda 100644
--- a/platform/linuxbsd/wayland/wayland_thread.cpp
+++ b/platform/linuxbsd/wayland/wayland_thread.cpp
@@ -371,28 +371,22 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
}
if (strcmp(interface, zxdg_exporter_v1_interface.name) == 0) {
- registry->wl_exporter = (struct zxdg_exporter_v1 *)wl_registry_bind(wl_registry, name, &zxdg_exporter_v1_interface, 1);
- registry->wl_exporter_name = name;
+ registry->xdg_exporter = (struct zxdg_exporter_v1 *)wl_registry_bind(wl_registry, name, &zxdg_exporter_v1_interface, 1);
+ registry->xdg_exporter_name = name;
return;
}
if (strcmp(interface, wl_compositor_interface.name) == 0) {
- registry->wl_compositor = (struct wl_compositor *)wl_registry_bind(wl_registry, name, &wl_compositor_interface, 4);
+ registry->wl_compositor = (struct wl_compositor *)wl_registry_bind(wl_registry, name, &wl_compositor_interface, CLAMP((int)version, 1, 6));
registry->wl_compositor_name = name;
return;
}
- if (strcmp(interface, wl_subcompositor_interface.name) == 0) {
- registry->wl_subcompositor = (struct wl_subcompositor *)wl_registry_bind(wl_registry, name, &wl_subcompositor_interface, 1);
- registry->wl_subcompositor_name = name;
- return;
- }
-
if (strcmp(interface, wl_data_device_manager_interface.name) == 0) {
- registry->wl_data_device_manager = (struct wl_data_device_manager *)wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 3);
+ registry->wl_data_device_manager = (struct wl_data_device_manager *)wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, CLAMP((int)version, 1, 3));
registry->wl_data_device_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);
@@ -406,7 +400,7 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
}
if (strcmp(interface, wl_output_interface.name) == 0) {
- struct wl_output *wl_output = (struct wl_output *)wl_registry_bind(wl_registry, name, &wl_output_interface, 2);
+ struct wl_output *wl_output = (struct wl_output *)wl_registry_bind(wl_registry, name, &wl_output_interface, CLAMP((int)version, 1, 4));
wl_proxy_tag_godot((struct wl_proxy *)wl_output);
registry->wl_outputs.push_back(wl_output);
@@ -421,7 +415,7 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
}
if (strcmp(interface, wl_seat_interface.name) == 0) {
- struct wl_seat *wl_seat = (struct wl_seat *)wl_registry_bind(wl_registry, name, &wl_seat_interface, 5);
+ struct wl_seat *wl_seat = (struct wl_seat *)wl_registry_bind(wl_registry, name, &wl_seat_interface, CLAMP((int)version, 1, 9));
wl_proxy_tag_godot((struct wl_proxy *)wl_seat);
SeatState *ss = memnew(SeatState);
@@ -448,14 +442,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);
@@ -469,7 +460,7 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
}
if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
- registry->xdg_wm_base = (struct xdg_wm_base *)wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, MAX(2, MIN(5, (int)version)));
+ registry->xdg_wm_base = (struct xdg_wm_base *)wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, CLAMP((int)version, 1, 6));
registry->xdg_wm_base_name = name;
xdg_wm_base_add_listener(registry->xdg_wm_base, &xdg_wm_base_listener, nullptr);
@@ -505,7 +496,7 @@ void WaylandThread::_wl_registry_on_global(void *data, struct wl_registry *wl_re
if (strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name) == 0) {
registry->wp_primary_selection_device_manager = (struct zwp_primary_selection_device_manager_v1 *)wl_registry_bind(wl_registry, name, &zwp_primary_selection_device_manager_v1_interface, 1);
- // 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);
@@ -541,13 +532,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 +547,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) {
@@ -576,13 +564,13 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry
return;
}
- if (name == registry->wl_exporter_name) {
- if (registry->wl_exporter) {
- zxdg_exporter_v1_destroy(registry->wl_exporter);
- registry->wl_exporter = nullptr;
+ if (name == registry->xdg_exporter_name) {
+ if (registry->xdg_exporter) {
+ zxdg_exporter_v1_destroy(registry->xdg_exporter);
+ registry->xdg_exporter = nullptr;
}
- registry->wl_exporter_name = 0;
+ registry->xdg_exporter_name = 0;
return;
}
@@ -598,17 +586,6 @@ void WaylandThread::_wl_registry_on_global_remove(void *data, struct wl_registry
return;
}
- if (name == registry->wl_subcompositor_name) {
- if (registry->wl_subcompositor) {
- wl_subcompositor_destroy(registry->wl_subcompositor);
- registry->wl_subcompositor = nullptr;
- }
-
- registry->wl_subcompositor_name = 0;
-
- return;
- }
-
if (name == registry->wl_data_device_manager_name) {
if (registry->wl_data_device_manager) {
wl_data_device_manager_destroy(registry->wl_data_device_manager);
@@ -820,8 +797,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 +810,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 +844,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;
}
}
@@ -986,6 +961,14 @@ void WaylandThread::_wl_surface_on_leave(void *data, struct wl_surface *wl_surfa
DEBUG_LOG_WAYLAND_THREAD(vformat("Window left output %x.\n", (size_t)wl_output));
}
+// TODO: Add support to this event.
+void WaylandThread::_wl_surface_on_preferred_buffer_scale(void *data, struct wl_surface *wl_surface, int32_t factor) {
+}
+
+// TODO: Add support to this event.
+void WaylandThread::_wl_surface_on_preferred_buffer_transform(void *data, struct wl_surface *wl_surface, uint32_t transform) {
+}
+
void WaylandThread::_wl_output_on_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char *make, const char *model, int32_t transform) {
ScreenState *ss = (ScreenState *)data;
ERR_FAIL_NULL(ss);
@@ -1000,6 +983,12 @@ void WaylandThread::_wl_output_on_geometry(void *data, struct wl_output *wl_outp
ss->pending_data.make.parse_utf8(make);
ss->pending_data.model.parse_utf8(model);
+
+ // `wl_output::done` is a version 2 addition. We'll directly update the data
+ // for compatibility.
+ if (wl_output_get_version(wl_output) == 1) {
+ ss->data = ss->pending_data;
+ }
}
void WaylandThread::_wl_output_on_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
@@ -1010,8 +999,17 @@ void WaylandThread::_wl_output_on_mode(void *data, struct wl_output *wl_output,
ss->pending_data.size.height = height;
ss->pending_data.refresh_rate = refresh ? refresh / 1000.0f : -1;
+
+ // `wl_output::done` is a version 2 addition. We'll directly update the data
+ // for compatibility.
+ if (wl_output_get_version(wl_output) == 1) {
+ ss->data = ss->pending_data;
+ }
}
+// NOTE: The following `wl_output` events are only for version 2 onwards, so we
+// can assume that they're "atomic" (i.e. rely on the `wl_output::done` event).
+
void WaylandThread::_wl_output_on_done(void *data, struct wl_output *wl_output) {
ScreenState *ss = (ScreenState *)data;
ERR_FAIL_NULL(ss);
@@ -1055,9 +1053,10 @@ void WaylandThread::_xdg_toplevel_on_configure(void *data, struct xdg_toplevel *
WindowState *ws = (WindowState *)data;
ERR_FAIL_NULL(ws);
- // Expect the window to be in windowed mode. The mode will get overridden if
- // the compositor reports otherwise.
+ // Expect the window to be in a plain state. It will get properly set if the
+ // compositor reports otherwise below.
ws->mode = DisplayServer::WINDOW_MODE_WINDOWED;
+ ws->suspended = false;
uint32_t *state = nullptr;
wl_array_for_each(state, states) {
@@ -1070,6 +1069,10 @@ void WaylandThread::_xdg_toplevel_on_configure(void *data, struct xdg_toplevel *
ws->mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
} break;
+ case XDG_TOPLEVEL_STATE_SUSPENDED: {
+ ws->suspended = true;
+ } break;
+
default: {
// We don't care about the other states (for now).
} break;
@@ -1168,9 +1171,10 @@ void WaylandThread::libdecor_frame_on_configure(struct libdecor_frame *frame, st
libdecor_window_state window_state = LIBDECOR_WINDOW_STATE_NONE;
- // Expect the window to be in windowed mode. The mode will get overridden if
- // the compositor reports otherwise.
+ // Expect the window to be in a plain state. It will get properly set if the
+ // compositor reports otherwise below.
ws->mode = DisplayServer::WINDOW_MODE_WINDOWED;
+ ws->suspended = false;
if (libdecor_configuration_get_window_state(configuration, &window_state)) {
if (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) {
@@ -1180,6 +1184,10 @@ void WaylandThread::libdecor_frame_on_configure(struct libdecor_frame *frame, st
if (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) {
ws->mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
}
+
+ if (window_state & LIBDECOR_WINDOW_STATE_SUSPENDED) {
+ ws->suspended = true;
+ }
}
window_state_update_size(ws, width, height);
@@ -1221,8 +1229,6 @@ void WaylandThread::_wl_seat_on_capabilities(void *data, struct wl_seat *wl_seat
// Pointer handling.
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
ss->cursor_surface = wl_compositor_create_surface(ss->registry->wl_compositor);
- ss->cursor_frame_callback = wl_surface_frame(ss->cursor_surface);
- wl_callback_add_listener(ss->cursor_frame_callback, &cursor_frame_callback_listener, ss);
wl_surface_commit(ss->cursor_surface);
ss->wl_pointer = wl_seat_get_pointer(wl_seat);
@@ -1303,11 +1309,9 @@ void WaylandThread::_cursor_frame_callback_on_done(void *data, struct wl_callbac
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
- ss->cursor_time_ms = time_ms;
+ ss->cursor_frame_callback = nullptr;
- ss->cursor_frame_callback = wl_surface_frame(ss->cursor_surface);
- wl_callback_add_listener(ss->cursor_frame_callback, &cursor_frame_callback_listener, ss);
- wl_surface_commit(ss->cursor_surface);
+ ss->cursor_time_ms = time_ms;
seat_state_update_cursor(ss);
}
@@ -1506,6 +1510,8 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point
mm->set_relative(pd.position - old_pd.position);
mm->set_velocity((Vector2)pos_delta / time_delta);
}
+ mm->set_relative_screen_position(mm->get_relative());
+ mm->set_screen_velocity(mm->get_velocity());
Ref<InputEventMessage> msg;
msg.instantiate();
@@ -1515,7 +1521,7 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point
wayland_thread->push_message(msg);
}
- if (pd.discrete_scroll_vector - old_pd.discrete_scroll_vector != Vector2i()) {
+ if (pd.discrete_scroll_vector_120 - old_pd.discrete_scroll_vector_120 != Vector2i()) {
// This is a discrete scroll (eg. from a scroll wheel), so we'll just emit
// scroll wheel buttons.
if (pd.scroll_vector.y != 0) {
@@ -1555,7 +1561,7 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point
}
if (old_pd.pressed_button_mask != pd.pressed_button_mask) {
- BitField<MouseButtonMask> pressed_mask_delta = BitField<MouseButtonMask>((uint32_t)old_pd.pressed_button_mask ^ (uint32_t)pd.pressed_button_mask);
+ BitField<MouseButtonMask> pressed_mask_delta = old_pd.pressed_button_mask ^ pd.pressed_button_mask;
const MouseButton buttons_to_test[] = {
MouseButton::LEFT,
@@ -1588,13 +1594,13 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point
if (test_button == MouseButton::WHEEL_UP || test_button == MouseButton::WHEEL_DOWN) {
// If this is a discrete scroll, specify how many "clicks" it did for this
// pointer frame.
- mb->set_factor(abs(pd.discrete_scroll_vector.y));
+ mb->set_factor(Math::abs(pd.discrete_scroll_vector_120.y / (float)120));
}
if (test_button == MouseButton::WHEEL_RIGHT || test_button == MouseButton::WHEEL_LEFT) {
// If this is a discrete scroll, specify how many "clicks" it did for this
// pointer frame.
- mb->set_factor(abs(pd.discrete_scroll_vector.x));
+ mb->set_factor(fabs(pd.discrete_scroll_vector_120.x / (float)120));
}
mb->set_button_mask(pd.pressed_button_mask);
@@ -1653,7 +1659,7 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point
// Reset the scroll vectors as we already handled them.
pd.scroll_vector = Vector2();
- pd.discrete_scroll_vector = Vector2();
+ pd.discrete_scroll_vector_120 = Vector2i();
// Update the data all getters read. Wayland's specification requires us to do
// this, since all pointer actions are sent in individual events.
@@ -1675,6 +1681,9 @@ void WaylandThread::_wl_pointer_on_axis_source(void *data, struct wl_pointer *wl
void WaylandThread::_wl_pointer_on_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis) {
}
+// NOTE: This event is deprecated since version 8 and superseded by
+// `wl_pointer::axis_value120`. This thus converts the data to its
+// fraction-of-120 format.
void WaylandThread::_wl_pointer_on_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
@@ -1686,17 +1695,41 @@ void WaylandThread::_wl_pointer_on_axis_discrete(void *data, struct wl_pointer *
PointerData &pd = ss->pointer_data_buffer;
+ // NOTE: We can allow ourselves to not accumulate this data (and thus just
+ // assign it) as the spec guarantees only one event per axis type.
+
if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
- pd.discrete_scroll_vector.y = discrete;
+ pd.discrete_scroll_vector_120.y = discrete * 120;
}
if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
- pd.discrete_scroll_vector.x = discrete;
+ pd.discrete_scroll_vector_120.x = discrete * 120;
}
}
-// TODO: Add support to this event.
+// Supersedes `wl_pointer::axis_discrete` Since version 8.
void WaylandThread::_wl_pointer_on_axis_value120(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t value120) {
+ SeatState *ss = (SeatState *)data;
+ ERR_FAIL_NULL(ss);
+
+ if (!ss->pointed_surface) {
+ // We're probably on a decoration or some other third-party thing.
+ return;
+ }
+
+ PointerData &pd = ss->pointer_data_buffer;
+
+ if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
+ pd.discrete_scroll_vector_120.y += value120;
+ }
+
+ if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
+ pd.discrete_scroll_vector_120.x += value120;
+ }
+}
+
+// TODO: Add support to this event.
+void WaylandThread::_wl_pointer_on_axis_relative_direction(void *data, struct wl_pointer *wl_pointer, uint32_t axis, uint32_t direction) {
}
void WaylandThread::_wl_keyboard_on_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) {
@@ -1712,7 +1745,7 @@ void WaylandThread::_wl_keyboard_on_keymap(void *data, struct wl_keyboard *wl_ke
ss->keymap_buffer = nullptr;
}
- ss->keymap_buffer = (const char *)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+ ss->keymap_buffer = (const char *)mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
ss->keymap_buffer_size = size;
xkb_keymap_unref(ss->xkb_keymap);
@@ -1987,7 +2020,7 @@ void WaylandThread::_wp_relative_pointer_on_relative_motion(void *data, struct z
pd.relative_motion_time = uptime_lo;
}
-void WaylandThread::_wp_pointer_gesture_pinch_on_begin(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, struct wl_surface *surface, uint32_t fingers) {
+void WaylandThread::_wp_pointer_gesture_pinch_on_begin(void *data, struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, struct wl_surface *surface, uint32_t fingers) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
@@ -1997,7 +2030,7 @@ void WaylandThread::_wp_pointer_gesture_pinch_on_begin(void *data, struct zwp_po
}
}
-void WaylandThread::_wp_pointer_gesture_pinch_on_update(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, wl_fixed_t rotation) {
+void WaylandThread::_wp_pointer_gesture_pinch_on_update(void *data, struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch_v1, uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, wl_fixed_t rotation) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
@@ -2056,7 +2089,7 @@ void WaylandThread::_wp_pointer_gesture_pinch_on_update(void *data, struct zwp_p
}
}
-void WaylandThread::_wp_pointer_gesture_pinch_on_end(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, int32_t cancelled) {
+void WaylandThread::_wp_pointer_gesture_pinch_on_end(void *data, struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, int32_t cancelled) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
@@ -2081,7 +2114,7 @@ void WaylandThread::_wp_primary_selection_device_on_selection(void *data, struct
ss->wp_primary_selection_offer = id;
}
-void WaylandThread::_wp_primary_selection_offer_on_offer(void *data, struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1, const char *mime_type) {
+void WaylandThread::_wp_primary_selection_offer_on_offer(void *data, struct zwp_primary_selection_offer_v1 *wp_primary_selection_offer_v1, const char *mime_type) {
OfferState *os = (OfferState *)data;
ERR_FAIL_NULL(os);
@@ -2135,83 +2168,91 @@ 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_tablet_added(void *data, struct zwp_tablet_seat_v2 *wp_tablet_seat_v2, struct zwp_tablet_v2 *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) {
+void WaylandThread::_wp_tablet_seat_on_tool_added(void *data, struct zwp_tablet_seat_v2 *wp_tablet_seat_v2, struct zwp_tablet_tool_v2 *id) {
SeatState *ss = (SeatState *)data;
ERR_FAIL_NULL(ss);
+ TabletToolState *state = memnew(TabletToolState);
+ state->wl_seat = ss->wl_seat;
+
+ wl_proxy_tag_godot((struct wl_proxy *)id);
+ zwp_tablet_tool_v2_add_listener(id, &wp_tablet_tool_listener, state);
+
ss->tablet_tools.push_back(id);
+}
+
+void WaylandThread::_wp_tablet_seat_on_pad_added(void *data, struct zwp_tablet_seat_v2 *wp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id) {
+}
- zwp_tablet_tool_v2_add_listener(id, &wp_tablet_tool_listener, ss);
+void WaylandThread::_wp_tablet_tool_on_type(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t tool_type) {
+ TabletToolState *state = wp_tablet_tool_get_state(wp_tablet_tool_v2);
- DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet seat %x on tool %x added", (size_t)zwp_tablet_seat_v2, (size_t)id));
+ if (state && tool_type == ZWP_TABLET_TOOL_V2_TYPE_ERASER) {
+ state->is_eraser = true;
+ }
}
-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_hardware_serial(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t hardware_serial_hi, uint32_t hardware_serial_lo) {
}
-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));
+void WaylandThread::_wp_tablet_tool_on_hardware_id_wacom(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t hardware_id_hi, uint32_t hardware_id_lo) {
}
-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_capability(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t capability) {
}
-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_done(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2) {
}
-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);
+void WaylandThread::_wp_tablet_tool_on_removed(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
- if (capability == ZWP_TABLET_TOOL_V2_TYPE_ERASER) {
- ss->tablet_tool_data_buffer.is_eraser = true;
+ if (!ts) {
+ return;
}
- DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on capability %d", (size_t)zwp_tablet_tool_v2, capability));
-}
+ SeatState *ss = wl_seat_get_seat_state(ts->wl_seat);
-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));
-}
+ if (!ss) {
+ return;
+ }
-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);
+ List<struct zwp_tablet_tool_v2 *>::Element *E = ss->tablet_tools.find(wp_tablet_tool_v2);
- List<struct zwp_tablet_tool_v2 *>::Element *it = ss->tablet_tools.front();
+ if (E && E->get()) {
+ struct zwp_tablet_tool_v2 *tool = E->get();
+ TabletToolState *state = wp_tablet_tool_get_state(tool);
+ if (state) {
+ memdelete(state);
+ }
+
+ zwp_tablet_tool_v2_destroy(tool);
+ ss->tablet_tools.erase(E);
+ }
+}
- while (it) {
- struct zwp_tablet_tool_v2 *tool = it->get();
+void WaylandThread::_wp_tablet_tool_on_proximity_in(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
- if (tool == zwp_tablet_tool_v2) {
- zwp_tablet_tool_v2_destroy(tool);
- ss->tablet_tools.erase(it);
- break;
- }
+ if (!ts) {
+ return;
}
- DEBUG_LOG_WAYLAND_THREAD(vformat("wp tablet tool %x on removed", (size_t)zwp_tablet_tool_v2));
-}
+ SeatState *ss = wl_seat_get_seat_state(ts->wl_seat);
-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);
+ if (!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();
@@ -2219,21 +2260,25 @@ 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);
+void WaylandThread::_wp_tablet_tool_on_proximity_out(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
+
+ if (!ts) {
+ return;
+ }
+
+ SeatState *ss = wl_seat_get_seat_state(ts->wl_seat);
+
+ if (!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();
@@ -2241,16 +2286,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);
+void WaylandThread::_wp_tablet_tool_on_down(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_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;
@@ -2258,76 +2305,92 @@ 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);
+void WaylandThread::_wp_tablet_tool_on_up(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
+
+ if (!ts) {
+ return;
+ }
- TabletToolData &td = ss->tablet_tool_data_buffer;
+ 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);
+void WaylandThread::_wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t x, wl_fixed_t y) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_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);
+void WaylandThread::_wp_tablet_tool_on_pressure(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t pressure) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
- ss->tablet_tool_data_buffer.pressure = pressure;
+ if (!ts) {
+ return;
+ }
+
+ 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) {
+void WaylandThread::_wp_tablet_tool_on_distance(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t distance) {
// Unsupported
}
-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);
+void WaylandThread::_wp_tablet_tool_on_tilt(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t tilt_x, wl_fixed_t tilt_y) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_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) {
+void WaylandThread::_wp_tablet_tool_on_rotation(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t degrees) {
// Unsupported.
}
-void WaylandThread::_wp_tablet_tool_on_slider(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, int32_t position) {
+void WaylandThread::_wp_tablet_tool_on_slider(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, int32_t position) {
// Unsupported.
}
-void WaylandThread::_wp_tablet_tool_on_wheel(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees, int32_t clicks) {
+void WaylandThread::_wp_tablet_tool_on_wheel(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t degrees, int32_t clicks) {
// TODO
}
-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);
+void WaylandThread::_wp_tablet_tool_on_button(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial, uint32_t button, uint32_t state) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
- TabletToolData &td = ss->tablet_tool_data_buffer;
+ if (!ts) {
+ return;
+ }
+
+ TabletToolData &td = ts->data_pending;
MouseButton mouse_button = MouseButton::NONE;
@@ -2356,15 +2419,24 @@ 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);
+void WaylandThread::_wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t time) {
+ TabletToolState *ts = wp_tablet_tool_get_state(wp_tablet_tool_v2);
+
+ if (!ts) {
+ return;
+ }
+
+ SeatState *ss = wl_seat_get_seat_state(ts->wl_seat);
+
+ if (!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;
@@ -2387,23 +2459,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.clampf(-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());
+ Vector2i 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);
Ref<InputEventMessage> inputev_msg;
inputev_msg.instantiate();
@@ -2592,6 +2665,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) {
@@ -2793,7 +2875,7 @@ void WaylandThread::seat_state_lock_pointer(SeatState *p_ss) {
ERR_FAIL_NULL(locked_surface);
- p_ss->wp_locked_pointer = zwp_pointer_constraints_v1_lock_pointer(registry.wp_pointer_constraints, locked_surface, p_ss->wl_pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+ p_ss->wp_locked_pointer = zwp_pointer_constraints_v1_lock_pointer(registry.wp_pointer_constraints, locked_surface, p_ss->wl_pointer, nullptr, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
}
@@ -2825,7 +2907,7 @@ void WaylandThread::seat_state_confine_pointer(SeatState *p_ss) {
ERR_FAIL_NULL(confined_surface);
- p_ss->wp_confined_pointer = zwp_pointer_constraints_v1_confine_pointer(registry.wp_pointer_constraints, confined_surface, p_ss->wl_pointer, NULL, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+ p_ss->wp_confined_pointer = zwp_pointer_constraints_v1_confine_pointer(registry.wp_pointer_constraints, confined_surface, p_ss->wl_pointer, nullptr, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
}
}
@@ -2854,7 +2936,18 @@ void WaylandThread::seat_state_update_cursor(SeatState *p_ss) {
// compositor do it for us (badly).
scale = 1;
} else if (wl_cursor) {
- int frame_idx = wl_cursor_frame(wl_cursor, p_ss->cursor_time_ms);
+ int frame_idx = 0;
+
+ if (wl_cursor->image_count > 1) {
+ // The cursor is animated.
+ frame_idx = wl_cursor_frame(wl_cursor, p_ss->cursor_time_ms);
+
+ if (!p_ss->cursor_frame_callback) {
+ // Since it's animated, we'll re-update it the next frame.
+ p_ss->cursor_frame_callback = wl_surface_frame(p_ss->cursor_surface);
+ wl_callback_add_listener(p_ss->cursor_frame_callback, &cursor_frame_callback_listener, p_ss);
+ }
+ }
struct wl_cursor_image *wl_cursor_image = wl_cursor->images[frame_idx];
@@ -2999,8 +3092,8 @@ void WaylandThread::window_create(DisplayServer::WindowID p_window_id, int p_wid
// "loop".
wl_surface_commit(ws.wl_surface);
- if (registry.wl_exporter) {
- ws.xdg_exported = zxdg_exporter_v1_export(registry.wl_exporter, ws.wl_surface);
+ 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);
}
@@ -3334,7 +3427,7 @@ bool WaylandThread::window_get_idle_inhibition(DisplayServer::WindowID p_window_
WaylandThread::ScreenData WaylandThread::screen_get_data(int p_screen) const {
ERR_FAIL_INDEX_V(p_screen, registry.wl_outputs.size(), ScreenData());
- return wl_output_get_screen_state(registry.wl_outputs[p_screen])->data;
+ return wl_output_get_screen_state(registry.wl_outputs.get(p_screen))->data;
}
int WaylandThread::get_screen_count() const {
@@ -3457,9 +3550,6 @@ Error WaylandThread::init() {
ERR_FAIL_NULL_V_MSG(registry.wl_shm, ERR_UNAVAILABLE, "Can't obtain the Wayland shared memory global.");
ERR_FAIL_NULL_V_MSG(registry.wl_compositor, ERR_UNAVAILABLE, "Can't obtain the Wayland compositor global.");
- ERR_FAIL_NULL_V_MSG(registry.wl_subcompositor, ERR_UNAVAILABLE, "Can't obtain the Wayland subcompositor global.");
- ERR_FAIL_NULL_V_MSG(registry.wl_data_device_manager, ERR_UNAVAILABLE, "Can't obtain the Wayland data device manager global.");
- ERR_FAIL_NULL_V_MSG(registry.wp_pointer_constraints, ERR_UNAVAILABLE, "Can't obtain the Wayland pointer constraints global.");
ERR_FAIL_NULL_V_MSG(registry.xdg_wm_base, ERR_UNAVAILABLE, "Can't obtain the Wayland XDG shell global.");
if (!registry.xdg_decoration_manager) {
@@ -3588,7 +3678,10 @@ void WaylandThread::cursor_shape_set_custom_image(DisplayServer::CursorShape p_c
munmap(cursor.buffer_data, cursor.buffer_data_size);
}
- cursor.buffer_data = (uint32_t *)mmap(NULL, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ // 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.
@@ -3856,6 +3949,102 @@ bool WaylandThread::get_reset_frame() {
return old_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) {
+ 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
+ // timing and stuff like that. Our job here is done.
+ return false;
+ }
+
+ if (frame) {
+ // We already have a frame! Probably it got there while the caller locked :D
+ frame = false;
+ return true;
+ }
+
+ struct pollfd poll_fd;
+ poll_fd.fd = wl_display_get_fd(wl_display);
+ poll_fd.events = POLLIN | POLLHUP;
+
+ int begin_ms = OS::get_singleton()->get_ticks_msec();
+ int remaining_ms = p_timeout;
+
+ while (remaining_ms > 0) {
+ // Empty the event queue while it's full.
+ while (wl_display_prepare_read(wl_display) != 0) {
+ if (wl_display_dispatch_pending(wl_display) == -1) {
+ // Oh no. We'll check and handle any display error below.
+ break;
+ }
+
+ if (main_window.suspended) {
+ return false;
+ }
+
+ if (frame) {
+ // We had a frame event in the queue :D
+ frame = false;
+ return true;
+ }
+ }
+
+ int werror = wl_display_get_error(wl_display);
+
+ if (werror) {
+ if (werror == EPROTO) {
+ struct wl_interface *wl_interface = nullptr;
+ uint32_t id = 0;
+
+ int error_code = wl_display_get_protocol_error(wl_display, (const struct wl_interface **)&wl_interface, &id);
+ CRASH_NOW_MSG(vformat("Wayland protocol error %d on interface %s@%d.", error_code, wl_interface ? wl_interface->name : "unknown", id));
+ } else {
+ CRASH_NOW_MSG(vformat("Wayland client error code %d.", werror));
+ }
+ }
+
+ wl_display_flush(wl_display);
+
+ // Wait for the event file descriptor to have new data.
+ poll(&poll_fd, 1, remaining_ms);
+
+ if (poll_fd.revents | POLLIN) {
+ // Load the queues with fresh new data.
+ wl_display_read_events(wl_display);
+ } else {
+ // Oh well... Stop signaling that we want to read.
+ wl_display_cancel_read(wl_display);
+
+ // We've got no new events :(
+ // We won't even bother with checking the frame flag.
+ return false;
+ }
+
+ // Let's try dispatching now...
+ wl_display_dispatch_pending(wl_display);
+
+ if (main_window.suspended) {
+ return false;
+ }
+
+ if (frame) {
+ frame = false;
+ return true;
+ }
+
+ remaining_ms -= OS::get_singleton()->get_ticks_msec() - begin_ms;
+ }
+
+ DEBUG_LOG_WAYLAND_THREAD("Frame timeout.");
+ return false;
+}
+
+bool WaylandThread::is_suspended() const {
+ return main_window.suspended;
+}
+
void WaylandThread::destroy() {
if (!initialized) {
return;
@@ -3948,14 +4137,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);
}
@@ -4009,18 +4200,14 @@ void WaylandThread::destroy() {
xdg_wm_base_destroy(registry.xdg_wm_base);
}
- if (registry.wl_exporter) {
- zxdg_exporter_v1_destroy(registry.wl_exporter);
+ if (registry.xdg_exporter) {
+ zxdg_exporter_v1_destroy(registry.xdg_exporter);
}
if (registry.wl_shm) {
wl_shm_destroy(registry.wl_shm);
}
- if (registry.wl_subcompositor) {
- wl_subcompositor_destroy(registry.wl_subcompositor);
- }
-
if (registry.wl_compositor) {
wl_compositor_destroy(registry.wl_compositor);
}
diff --git a/platform/linuxbsd/wayland/wayland_thread.h b/platform/linuxbsd/wayland/wayland_thread.h
index 43c562aade..d35a5b7139 100644
--- a/platform/linuxbsd/wayland/wayland_thread.h
+++ b/platform/linuxbsd/wayland/wayland_thread.h
@@ -133,8 +133,8 @@ public:
struct xdg_wm_base *xdg_wm_base = nullptr;
uint32_t xdg_wm_base_name = 0;
- struct zxdg_exporter_v1 *wl_exporter = nullptr;
- uint32_t wl_exporter_name = 0;
+ struct zxdg_exporter_v1 *xdg_exporter = nullptr;
+ uint32_t xdg_exporter_name = 0;
// wayland-protocols globals.
@@ -177,6 +177,7 @@ public:
Rect2i rect;
DisplayServer::WindowMode mode = DisplayServer::WINDOW_MODE_WINDOWED;
+ bool suspended = false;
// These are true by default as it isn't guaranteed that we'll find an
// xdg-shell implementation with wm_capabilities available. If and once we
@@ -299,15 +300,15 @@ public:
// The amount "scrolled" in pixels, in each direction.
Vector2 scroll_vector;
- // The amount of scroll "clicks" in each direction.
- Vector2i discrete_scroll_vector;
+ // The amount of scroll "clicks" in each direction, in fractions of 120.
+ Vector2i discrete_scroll_vector_120;
uint32_t pinch_scale = 1;
};
struct TabletToolData {
Point2i position;
- Vector2i tilt;
+ Vector2 tilt;
uint32_t pressure = 0;
BitField<MouseButtonMask> pressed_button_mask;
@@ -321,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 {
@@ -424,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 {
@@ -502,6 +510,8 @@ private:
static void _wl_surface_on_enter(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output);
static void _wl_surface_on_leave(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output);
+ static void _wl_surface_on_preferred_buffer_scale(void *data, struct wl_surface *wl_surface, int32_t factor);
+ static void _wl_surface_on_preferred_buffer_transform(void *data, struct wl_surface *wl_surface, uint32_t transform);
static void _frame_wl_callback_on_done(void *data, struct wl_callback *wl_callback, uint32_t callback_data);
@@ -527,6 +537,7 @@ private:
static void _wl_pointer_on_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis);
static void _wl_pointer_on_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete);
static void _wl_pointer_on_axis_value120(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t value120);
+ static void _wl_pointer_on_axis_relative_direction(void *data, struct wl_pointer *wl_pointer, uint32_t axis, uint32_t direction);
static void _wl_keyboard_on_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size);
static void _wl_keyboard_on_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys);
@@ -568,41 +579,41 @@ private:
static void _wp_relative_pointer_on_relative_motion(void *data, struct zwp_relative_pointer_v1 *wp_relative_pointer_v1, uint32_t uptime_hi, uint32_t uptime_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel, wl_fixed_t dy_unaccel);
- static void _wp_pointer_gesture_pinch_on_begin(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, struct wl_surface *surface, uint32_t fingers);
- static void _wp_pointer_gesture_pinch_on_update(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, wl_fixed_t rotation);
- static void _wp_pointer_gesture_pinch_on_end(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, int32_t cancelled);
+ static void _wp_pointer_gesture_pinch_on_begin(void *data, struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, struct wl_surface *surface, uint32_t fingers);
+ static void _wp_pointer_gesture_pinch_on_update(void *data, struct zwp_pointer_gesture_pinch_v1 *wp_pointer_gesture_pinch_v1, uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale, wl_fixed_t rotation);
+ static void _wp_pointer_gesture_pinch_on_end(void *data, struct zwp_pointer_gesture_pinch_v1 *zp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, int32_t cancelled);
static void _wp_primary_selection_device_on_data_offer(void *data, struct zwp_primary_selection_device_v1 *wp_primary_selection_device_v1, struct zwp_primary_selection_offer_v1 *offer);
static void _wp_primary_selection_device_on_selection(void *data, struct zwp_primary_selection_device_v1 *wp_primary_selection_device_v1, struct zwp_primary_selection_offer_v1 *id);
- static void _wp_primary_selection_offer_on_offer(void *data, struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer_v1, const char *mime_type);
+ static void _wp_primary_selection_offer_on_offer(void *data, struct zwp_primary_selection_offer_v1 *wp_primary_selection_offer_v1, const char *mime_type);
static void _wp_primary_selection_source_on_send(void *data, struct zwp_primary_selection_source_v1 *wp_primary_selection_source_v1, const char *mime_type, int32_t fd);
static void _wp_primary_selection_source_on_cancelled(void *data, struct zwp_primary_selection_source_v1 *wp_primary_selection_source_v1);
- static void _wp_tablet_seat_on_tablet_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_v2 *id);
- static void _wp_tablet_seat_on_tool_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_tool_v2 *id);
- static void _wp_tablet_seat_on_pad_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id);
-
- static void _wp_tablet_tool_on_type(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t tool_type);
- static void _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);
- static void _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);
- static void _wp_tablet_tool_on_capability(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t capability);
- static void _wp_tablet_tool_on_done(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2);
- static void _wp_tablet_tool_on_removed(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2);
- static void _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);
- static void _wp_tablet_tool_on_proximity_out(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2);
- static void _wp_tablet_tool_on_down(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t serial);
- static void _wp_tablet_tool_on_up(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2);
- static void _wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t x, wl_fixed_t y);
- static void _wp_tablet_tool_on_pressure(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t pressure);
- static void _wp_tablet_tool_on_distance(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t distance);
- static void _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);
- static void _wp_tablet_tool_on_rotation(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees);
- static void _wp_tablet_tool_on_slider(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, int32_t position);
- static void _wp_tablet_tool_on_wheel(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, wl_fixed_t degrees, int32_t clicks);
- static void _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);
- static void _wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2, uint32_t time);
+ static void _wp_tablet_seat_on_tablet_added(void *data, struct zwp_tablet_seat_v2 *wp_tablet_seat_v2, struct zwp_tablet_v2 *id);
+ static void _wp_tablet_seat_on_tool_added(void *data, struct zwp_tablet_seat_v2 *wp_tablet_seat_v2, struct zwp_tablet_tool_v2 *id);
+ static void _wp_tablet_seat_on_pad_added(void *data, struct zwp_tablet_seat_v2 *wp_tablet_seat_v2, struct zwp_tablet_pad_v2 *id);
+
+ static void _wp_tablet_tool_on_type(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t tool_type);
+ static void _wp_tablet_tool_on_hardware_serial(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t hardware_serial_hi, uint32_t hardware_serial_lo);
+ static void _wp_tablet_tool_on_hardware_id_wacom(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t hardware_id_hi, uint32_t hardware_id_lo);
+ static void _wp_tablet_tool_on_capability(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t capability);
+ static void _wp_tablet_tool_on_done(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2);
+ static void _wp_tablet_tool_on_removed(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2);
+ static void _wp_tablet_tool_on_proximity_in(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface);
+ static void _wp_tablet_tool_on_proximity_out(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2);
+ static void _wp_tablet_tool_on_down(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial);
+ static void _wp_tablet_tool_on_up(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2);
+ static void _wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t x, wl_fixed_t y);
+ static void _wp_tablet_tool_on_pressure(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t pressure);
+ static void _wp_tablet_tool_on_distance(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t distance);
+ static void _wp_tablet_tool_on_tilt(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t tilt_x, wl_fixed_t tilt_y);
+ static void _wp_tablet_tool_on_rotation(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t degrees);
+ static void _wp_tablet_tool_on_slider(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, int32_t position);
+ static void _wp_tablet_tool_on_wheel(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, wl_fixed_t degrees, int32_t clicks);
+ static void _wp_tablet_tool_on_button(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t serial, uint32_t button, uint32_t state);
+ static void _wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_v2 *wp_tablet_tool_v2, uint32_t time);
static void _xdg_toplevel_decoration_on_configure(void *data, struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration, uint32_t mode);
@@ -619,6 +630,8 @@ private:
static constexpr struct wl_surface_listener wl_surface_listener = {
.enter = _wl_surface_on_enter,
.leave = _wl_surface_on_leave,
+ .preferred_buffer_scale = _wl_surface_on_preferred_buffer_scale,
+ .preferred_buffer_transform = _wl_surface_on_preferred_buffer_transform,
};
static constexpr struct wl_callback_listener frame_wl_callback_listener {
@@ -654,6 +667,7 @@ private:
.axis_stop = _wl_pointer_on_axis_stop,
.axis_discrete = _wl_pointer_on_axis_discrete,
.axis_value120 = _wl_pointer_on_axis_value120,
+ .axis_relative_direction = _wl_pointer_on_axis_relative_direction,
};
static constexpr struct wl_keyboard_listener wl_keyboard_listener = {
@@ -848,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);
@@ -933,6 +948,9 @@ public:
void set_frame();
bool get_reset_frame();
+ bool wait_frame_suspend_ms(int p_timeout);
+
+ bool is_suspended() const;
Error init();
void destroy();
diff --git a/platform/linuxbsd/x11/SCsub b/platform/linuxbsd/x11/SCsub
index bbfaaf10d1..75fe584ad5 100644
--- a/platform/linuxbsd/x11/SCsub
+++ b/platform/linuxbsd/x11/SCsub
@@ -21,7 +21,7 @@ if env["use_sowrap"]:
)
if env["vulkan"]:
- source_files.append("vulkan_context_x11.cpp")
+ source_files.append("rendering_context_driver_vulkan_x11.cpp")
if env["opengl3"]:
env.Append(CPPDEFINES=["GLAD_GLX_NO_X11"])
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 20e2e897f2..9174b65b1b 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:
@@ -124,8 +128,10 @@ bool DisplayServerX11::has_feature(Feature p_feature) const {
//case FEATURE_HIDPI:
case FEATURE_ICON:
#ifdef DBUS_ENABLED
- case FEATURE_NATIVE_DIALOG:
+ case FEATURE_NATIVE_DIALOG_FILE:
#endif
+ //case FEATURE_NATIVE_DIALOG:
+ //case FEATURE_NATIVE_DIALOG_INPUT:
//case FEATURE_NATIVE_ICON:
case FEATURE_SWAP_BUFFERS:
#ifdef DBUS_ENABLED
@@ -364,6 +370,10 @@ bool DisplayServerX11::is_dark_mode() const {
}
}
+void DisplayServerX11::set_system_theme_change_callback(const Callable &p_callable) {
+ portal_desktop->set_system_theme_change_callback(p_callable);
+}
+
Error DisplayServerX11::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
WindowID window_id = last_focused_window;
@@ -1670,7 +1680,11 @@ DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, V
window_set_flag(WindowFlags(i), true, id);
}
}
-
+#ifdef RD_ENABLED
+ if (rendering_device) {
+ rendering_device->screen_create(id);
+ }
+#endif
return id;
}
@@ -1719,8 +1733,12 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
}
#if defined(RD_ENABLED)
- if (context_rd) {
- context_rd->window_destroy(p_id);
+ if (rendering_device) {
+ rendering_device->screen_free(p_id);
+ }
+
+ if (rendering_context) {
+ rendering_context->window_destroy(p_id);
}
#endif
#ifdef GLES3_ENABLED
@@ -1979,8 +1997,7 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window
Size2i wsize = window_get_size(p_window);
wpos += srect.position;
if (srect != Rect2i()) {
- wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3);
- wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3);
+ wpos = wpos.clamp(srect.position, srect.position + srect.size - wsize / 3);
}
window_set_position(wpos, p_window);
}
@@ -2208,8 +2225,7 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
ERR_FAIL_COND(!windows.has(p_window));
Size2i size = p_size;
- size.x = MAX(1, size.x);
- size.y = MAX(1, size.y);
+ size = size.maxi(1);
WindowData &wd = windows[p_window];
@@ -2245,8 +2261,8 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
// Keep rendering context window size in sync
#if defined(RD_ENABLED)
- if (context_rd) {
- context_rd->window_resize(p_window, xwa.width, xwa.height);
+ if (rendering_context) {
+ rendering_context->window_set_size(p_window, xwa.width, xwa.height);
}
#endif
#if defined(GLES3_ENABLED)
@@ -3052,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);
@@ -3103,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);
}
@@ -3970,8 +3957,8 @@ void DisplayServerX11::_window_changed(XEvent *event) {
wd.size = new_rect.size;
#if defined(RD_ENABLED)
- if (context_rd) {
- context_rd->window_resize(window_id, wd.size.width, wd.size.height);
+ if (rendering_context) {
+ rendering_context->window_set_size(window_id, wd.size.width, wd.size.height);
}
#endif
#if defined(GLES3_ENABLED)
@@ -4281,7 +4268,9 @@ bool DisplayServerX11::_window_focus_check() {
}
void DisplayServerX11::process_events() {
- _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND(!Thread::is_main_thread());
+
+ _THREAD_SAFE_LOCK_
#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
static int frame = 0;
@@ -4524,6 +4513,7 @@ void DisplayServerX11::process_events() {
sd->set_index(index);
sd->set_position(pos);
sd->set_relative(pos - curr_pos_elem->value);
+ sd->set_relative_screen_position(sd->get_relative());
Input::get_singleton()->parse_input_event(sd);
curr_pos_elem->value = pos;
@@ -4718,19 +4708,6 @@ void DisplayServerX11::process_events() {
break;
}
- const WindowData &wd = windows[window_id];
-
- XWindowAttributes xwa;
- XSync(x11_display, False);
- XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
-
- // Set focus when menu window is re-used.
- // RevertToPointerRoot is used to make sure we don't lose all focus in case
- // a subwindow and its parent are both destroyed.
- if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup && _window_focus_check()) {
- _set_input_focus(wd.x11_window, RevertToPointerRoot);
- }
-
_window_changed(&event);
} break;
@@ -4945,8 +4922,10 @@ void DisplayServerX11::process_events() {
mm->set_position(pos);
mm->set_global_position(pos);
mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());
+ mm->set_screen_velocity(mm->get_velocity());
mm->set_relative(rel);
+ mm->set_relative_screen_position(rel);
last_mouse_pos = pos;
@@ -5015,7 +4994,7 @@ void DisplayServerX11::process_events() {
files.write[i] = files[i].replace("file://", "").uri_decode();
}
- if (!windows[window_id].drop_files_callback.is_null()) {
+ if (windows[window_id].drop_files_callback.is_valid()) {
windows[window_id].drop_files_callback.call(files);
}
@@ -5120,6 +5099,14 @@ void DisplayServerX11::process_events() {
*/
}
+#ifdef DBUS_ENABLED
+ if (portal_desktop) {
+ portal_desktop->process_file_dialog_callbacks();
+ }
+#endif
+
+ _THREAD_SAFE_UNLOCK_
+
Input::get_singleton()->flush_buffered_events();
}
@@ -5134,17 +5121,6 @@ void DisplayServerX11::release_rendering_thread() {
#endif
}
-void DisplayServerX11::make_rendering_thread() {
-#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->make_current();
- }
- if (gl_manager_egl) {
- gl_manager_egl->make_current();
- }
-#endif
-}
-
void DisplayServerX11::swap_buffers() {
#if defined(GLES3_ENABLED)
if (gl_manager) {
@@ -5235,7 +5211,7 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
if (g_set_icon_error) {
g_set_icon_error = false;
- WARN_PRINT("Icon too large, attempting to resize icon.");
+ WARN_PRINT(vformat("Icon too large (%dx%d), attempting to downscale icon.", w, h));
int new_width, new_height;
if (w > h) {
@@ -5297,8 +5273,8 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
_THREAD_SAFE_METHOD_
#if defined(RD_ENABLED)
- if (context_rd) {
- context_rd->set_vsync_mode(p_window, p_vsync_mode);
+ if (rendering_context) {
+ rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
}
#endif
@@ -5315,8 +5291,8 @@ void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mo
DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_window) const {
_THREAD_SAFE_METHOD_
#if defined(RD_ENABLED)
- if (context_rd) {
- return context_rd->get_vsync_mode(p_window);
+ if (rendering_context) {
+ return rendering_context->window_get_vsync_mode(p_window);
}
#endif
#if defined(GLES3_ENABLED)
@@ -5474,8 +5450,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
} else {
Rect2i srect = screen_get_usable_rect(rq_screen);
Point2i wpos = p_rect.position;
- wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3);
- wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3);
+ wpos = wpos.clamp(srect.position, srect.position + srect.size - p_rect.size / 3);
win_rect.position = wpos;
}
@@ -5659,10 +5634,10 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
_update_size_hints(id);
#if defined(RD_ENABLED)
- if (context_rd) {
+ if (rendering_context) {
union {
#ifdef VULKAN_ENABLED
- VulkanContextX11::WindowPlatformData vulkan;
+ RenderingContextDriverVulkanX11::WindowPlatformData vulkan;
#endif
} wpd;
#ifdef VULKAN_ENABLED
@@ -5671,8 +5646,11 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
wpd.vulkan.display = x11_display;
}
#endif
- Error err = context_rd->window_create(id, p_vsync_mode, win_rect.size.width, win_rect.size.height, &wpd);
- ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, vformat("Can't create a %s window", context_rd->get_api_name()));
+ Error err = rendering_context->window_create(id, &wpd);
+ ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, vformat("Can't create a %s window", rendering_driver));
+
+ rendering_context->window_set_size(id, win_rect.size.width, win_rect.size.height);
+ rendering_context->window_set_vsync_mode(id, p_vsync_mode);
}
#endif
#ifdef GLES3_ENABLED
@@ -5777,6 +5755,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;
@@ -6074,16 +6054,17 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
#if defined(RD_ENABLED)
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
- context_rd = memnew(VulkanContextX11);
+ rendering_context = memnew(RenderingContextDriverVulkanX11);
}
#endif
- if (context_rd) {
- if (context_rd->initialize() != OK) {
- memdelete(context_rd);
- context_rd = nullptr;
+ 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;
- ERR_FAIL_MSG(vformat("Could not initialize %s", context_rd->get_api_name()));
+ return;
}
driver_found = true;
}
@@ -6193,9 +6174,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
show_window(main_window);
#if defined(RD_ENABLED)
- if (context_rd) {
+ if (rendering_context) {
rendering_device = memnew(RenderingDevice);
- rendering_device->initialize(context_rd);
+ rendering_device->initialize(rendering_context, MAIN_WINDOW_ID);
+ rendering_device->screen_create(MAIN_WINDOW_ID);
RendererCompositorRD::make_current();
}
@@ -6367,11 +6349,20 @@ 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)
- if (context_rd) {
- context_rd->window_destroy(E.key);
+ if (rendering_device) {
+ rendering_device->screen_free(E.key);
+ }
+
+ if (rendering_context) {
+ rendering_context->window_destroy(E.key);
}
#endif
#ifdef GLES3_ENABLED
@@ -6415,14 +6406,13 @@ DisplayServerX11::~DisplayServerX11() {
//destroy drivers
#if defined(RD_ENABLED)
if (rendering_device) {
- rendering_device->finalize();
memdelete(rendering_device);
rendering_device = nullptr;
}
- if (context_rd) {
- memdelete(context_rd);
- context_rd = nullptr;
+ if (rendering_context) {
+ memdelete(rendering_context);
+ rendering_context = nullptr;
}
#endif
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index da4085772a..8a7062857c 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -61,7 +61,7 @@
#include "servers/rendering/rendering_device.h"
#if defined(VULKAN_ENABLED)
-#include "x11/vulkan_context_x11.h"
+#include "x11/rendering_context_driver_vulkan_x11.h"
#endif
#endif
@@ -144,7 +144,7 @@ class DisplayServerX11 : public DisplayServer {
GLManagerEGL_X11 *gl_manager_egl = nullptr;
#endif
#if defined(RD_ENABLED)
- ApiContextRD *context_rd = nullptr;
+ RenderingContextDriver *rendering_context = nullptr;
RenderingDevice *rendering_device = nullptr;
#endif
@@ -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;
@@ -400,6 +401,7 @@ public:
#if defined(DBUS_ENABLED)
virtual bool is_dark_mode_supported() const override;
virtual bool is_dark_mode() const override;
+ virtual void set_system_theme_change_callback(const Callable &p_callable) override;
virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) override;
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;
@@ -524,7 +526,6 @@ public:
virtual void process_events() override;
virtual void release_rendering_thread() override;
- virtual void make_rendering_thread() override;
virtual void swap_buffers() override;
virtual void set_context(Context p_context) override;
diff --git a/platform/linuxbsd/x11/gl_manager_x11.cpp b/platform/linuxbsd/x11/gl_manager_x11.cpp
index 602dd784e0..febb7ae584 100644
--- a/platform/linuxbsd/x11/gl_manager_x11.cpp
+++ b/platform/linuxbsd/x11/gl_manager_x11.cpp
@@ -311,20 +311,6 @@ void GLManager_X11::window_make_current(DisplayServer::WindowID p_window_id) {
_internal_set_current_window(&win);
}
-void GLManager_X11::make_current() {
- if (!_current_window) {
- return;
- }
- if (!_current_window->in_use) {
- WARN_PRINT("current window not in use!");
- return;
- }
- const GLDisplay &disp = get_current_display();
- if (!glXMakeCurrent(_x_windisp.x11_display, _x_windisp.x11_window, disp.context->glx_context)) {
- ERR_PRINT("glXMakeCurrent failed");
- }
-}
-
void GLManager_X11::swap_buffers() {
if (!_current_window) {
return;
diff --git a/platform/linuxbsd/x11/gl_manager_x11.h b/platform/linuxbsd/x11/gl_manager_x11.h
index 235c7d22f9..06e147e39f 100644
--- a/platform/linuxbsd/x11/gl_manager_x11.h
+++ b/platform/linuxbsd/x11/gl_manager_x11.h
@@ -117,7 +117,6 @@ public:
void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
void release_current();
- void make_current();
void swap_buffers();
void window_make_current(DisplayServer::WindowID p_window_id);
diff --git a/platform/linuxbsd/x11/vulkan_context_x11.cpp b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp
index 3eee1706b0..bf44062266 100644
--- a/platform/linuxbsd/x11/vulkan_context_x11.cpp
+++ b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* vulkan_context_x11.cpp */
+/* rendering_context_driver_vulkan_x11.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -30,7 +30,7 @@
#ifdef VULKAN_ENABLED
-#include "vulkan_context_x11.h"
+#include "rendering_context_driver_vulkan_x11.h"
#ifdef USE_VOLK
#include <volk.h>
@@ -38,28 +38,33 @@
#include <vulkan/vulkan.h>
#endif
-const char *VulkanContextX11::_get_platform_surface_extension() const {
+const char *RenderingContextDriverVulkanX11::_get_platform_surface_extension() const {
return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
}
-Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
- const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkanX11::surface_create(const void *p_platform_data) {
+ const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
- VkXlibSurfaceCreateInfoKHR createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
- createInfo.dpy = wpd->display;
- createInfo.window = wpd->window;
+ VkXlibSurfaceCreateInfoKHR create_info = {};
+ create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
+ create_info.dpy = wpd->display;
+ create_info.window = wpd->window;
- VkSurfaceKHR surface = VK_NULL_HANDLE;
- VkResult err = vkCreateXlibSurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
- ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
- return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
+ VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+ VkResult err = vkCreateXlibSurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface);
+ ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
+
+ Surface *surface = memnew(Surface);
+ surface->vk_surface = vk_surface;
+ return SurfaceID(surface);
}
-VulkanContextX11::VulkanContextX11() {
+RenderingContextDriverVulkanX11::RenderingContextDriverVulkanX11() {
+ // Does nothing.
}
-VulkanContextX11::~VulkanContextX11() {
+RenderingContextDriverVulkanX11::~RenderingContextDriverVulkanX11() {
+ // Does nothing.
}
#endif // VULKAN_ENABLED
diff --git a/platform/linuxbsd/x11/vulkan_context_x11.h b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.h
index 2390326b44..d525b69ec7 100644
--- a/platform/linuxbsd/x11/vulkan_context_x11.h
+++ b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* vulkan_context_x11.h */
+/* rendering_context_driver_vulkan_x11.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,29 +28,32 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef VULKAN_CONTEXT_X11_H
-#define VULKAN_CONTEXT_X11_H
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_X11_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_X11_H
#ifdef VULKAN_ENABLED
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
#include <X11/Xlib.h>
-class VulkanContextX11 : public VulkanContext {
+class RenderingContextDriverVulkanX11 : public RenderingContextDriverVulkan {
+private:
virtual const char *_get_platform_surface_extension() const override final;
+protected:
+ SurfaceID surface_create(const void *p_platform_data) override final;
+
public:
struct WindowPlatformData {
::Window window;
Display *display;
};
- virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
- VulkanContextX11();
- ~VulkanContextX11();
+ RenderingContextDriverVulkanX11();
+ ~RenderingContextDriverVulkanX11();
};
#endif // VULKAN_ENABLED
-#endif // VULKAN_CONTEXT_X11_H
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_X11_H