summaryrefslogtreecommitdiff
path: root/platform/linuxbsd
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r--platform/linuxbsd/README.md14
-rw-r--r--platform/linuxbsd/SCsub1
-rw-r--r--platform/linuxbsd/detect.py102
-rw-r--r--platform/linuxbsd/detect_prime_x11.h8
-rw-r--r--platform/linuxbsd/display_server_x11.cpp321
-rw-r--r--platform/linuxbsd/display_server_x11.h19
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.cpp135
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.h59
-rw-r--r--platform/linuxbsd/gl_manager_x11.cpp50
-rw-r--r--platform/linuxbsd/gl_manager_x11.h3
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp63
-rw-r--r--platform/linuxbsd/os_linuxbsd.h6
12 files changed, 556 insertions, 225 deletions
diff --git a/platform/linuxbsd/README.md b/platform/linuxbsd/README.md
index 0d3fb37be5..efa8682062 100644
--- a/platform/linuxbsd/README.md
+++ b/platform/linuxbsd/README.md
@@ -2,10 +2,20 @@
This folder contains the C++ code for the Linux/*BSD platform port.
+See also [`misc/dist/linux`](/misc/dist/linux) folder for additional files
+used by this platform.
+
+## Documentation
+
+- [Compiling for Linux/*BSD](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_linuxbsd.html)
+ - Instructions on building this platform port from source.
+- [Exporting for Linux/*BSD](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_linux.html)
+ - Instructions on using the compiled export templates to export a project.
+
## Artwork license
[`logo.png`](logo.png) is derived from the [Linux logo](https://isc.tamu.edu/~lewing/linux/):
> Permission to use and/or modify this image is granted provided you acknowledge me
- <lewing@isc.tamu.edu> and [The GIMP](https://isc.tamu.edu/~lewing/gimp/)
- if someone asks.
+> <lewing@isc.tamu.edu> and [The GIMP](https://isc.tamu.edu/~lewing/gimp/)
+> if someone asks.
diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub
index 35c41556ee..91d45627b9 100644
--- a/platform/linuxbsd/SCsub
+++ b/platform/linuxbsd/SCsub
@@ -9,6 +9,7 @@ common_linuxbsd = [
"crash_handler_linuxbsd.cpp",
"os_linuxbsd.cpp",
"joypad_linux.cpp",
+ "freedesktop_portal_desktop.cpp",
"freedesktop_screensaver.cpp",
]
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 00e2b9e6eb..dfde0d249c 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -2,6 +2,12 @@ import os
import platform
import sys
from methods import get_compiler_version, using_gcc
+from platform_methods import detect_arch
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from SCons import Environment
def is_active():
@@ -30,7 +36,6 @@ def get_opts():
return [
EnumVariable("linker", "Linker program", "default", ("default", "bfd", "gold", "lld", "mold")),
BoolVariable("use_llvm", "Use the LLVM compiler", False),
- BoolVariable("use_thinlto", "Use ThinLTO (LLVM only, requires linker=lld, implies use_lto=yes)", False),
BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True),
BoolVariable("use_coverage", "Test Godot coverage", False),
BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
@@ -39,64 +44,40 @@ def get_opts():
BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False),
BoolVariable("use_msan", "Use LLVM compiler memory sanitizer (MSAN)", False),
BoolVariable("pulseaudio", "Detect and use PulseAudio", True),
- BoolVariable("dbus", "Detect and use D-Bus to handle screensaver", True),
+ BoolVariable("dbus", "Detect and use D-Bus to handle screensaver and portal desktop settings", True),
BoolVariable("speechd", "Detect and use Speech Dispatcher for Text-to-Speech support", True),
BoolVariable("fontconfig", "Detect and use fontconfig for system fonts support", True),
BoolVariable("udev", "Use udev for gamepad connection callbacks", True),
BoolVariable("x11", "Enable X11 display", True),
- BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True),
- BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
BoolVariable("touch", "Enable touch events", True),
BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False),
]
def get_flags():
- return []
-
-
-def configure(env):
- ## Build type
-
- if env["target"] == "release":
- if env["optimize"] == "speed": # optimize for speed (default)
- env.Prepend(CCFLAGS=["-O3"])
- elif env["optimize"] == "size": # optimize for size
- env.Prepend(CCFLAGS=["-Os"])
+ return [
+ ("arch", detect_arch()),
+ ]
- if env["debug_symbols"]:
- env.Prepend(CCFLAGS=["-g2"])
- elif env["target"] == "release_debug":
- if env["optimize"] == "speed": # optimize for speed (default)
- env.Prepend(CCFLAGS=["-O2"])
- elif env["optimize"] == "size": # optimize for size
- env.Prepend(CCFLAGS=["-Os"])
+def configure(env: "Environment"):
+ # Validate arch.
+ supported_arches = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64"]
+ if env["arch"] not in supported_arches:
+ print(
+ 'Unsupported CPU architecture "%s" for Linux / *BSD. Supported architectures are: %s.'
+ % (env["arch"], ", ".join(supported_arches))
+ )
+ sys.exit()
- if env["debug_symbols"]:
- env.Prepend(CCFLAGS=["-g2"])
+ ## Build type
- elif env["target"] == "debug":
- env.Prepend(CCFLAGS=["-g3"])
+ if env.dev_build:
+ # This is needed for our crash handler to work properly.
+ # gdb works fine without it though, so maybe our crash handler could too.
env.Append(LINKFLAGS=["-rdynamic"])
- ## Architecture
-
- is64 = sys.maxsize > 2**32
- if env["bits"] == "default":
- env["bits"] = "64" if is64 else "32"
-
- machines = {
- "riscv64": "rv64",
- "ppc64le": "ppc64",
- "ppc64": "ppc64",
- "ppcle": "ppc",
- "ppc": "ppc",
- }
-
- if env["arch"] == "" and platform.machine() in machines:
- env["arch"] = machines[platform.machine()]
-
+ # CPU architecture flags.
if env["arch"] == "rv64":
# G = General-purpose extensions, C = Compression extension (very common).
env.Append(CCFLAGS=["-march=rv64gc"])
@@ -133,13 +114,6 @@ def configure(env):
else:
env.Append(LINKFLAGS=["-fuse-ld=%s" % env["linker"]])
- if env["use_thinlto"]:
- if not env["use_llvm"] or env["linker"] != "lld":
- print("ThinLTO is only compatible with LLVM and the LLD linker, use `use_llvm=yes linker=lld`.")
- sys.exit(255)
- else:
- env["use_lto"] = True # ThinLTO implies LTO
-
if env["use_coverage"]:
env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"])
env.Append(LINKFLAGS=["-ftest-coverage", "-fprofile-arcs"])
@@ -182,8 +156,16 @@ def configure(env):
env.Append(CCFLAGS=["-fsanitize-recover=memory"])
env.Append(LINKFLAGS=["-fsanitize=memory"])
- if env["use_lto"]:
- if env["use_thinlto"]:
+ # LTO
+
+ if env["lto"] == "auto": # Full LTO for production.
+ env["lto"] = "full"
+
+ 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`.")
+ sys.exit(255)
env.Append(CCFLAGS=["-flto=thin"])
env.Append(LINKFLAGS=["-flto=thin"])
elif not env["use_llvm"] and env.GetOption("num_jobs") > 1:
@@ -262,8 +244,7 @@ def configure(env):
env["builtin_libvorbis"] = False # Needed to link against system libtheora
env.ParseConfig("pkg-config theora theoradec --cflags --libs")
else:
- list_of_x86 = ["x86_64", "x86", "i386", "i586"]
- if any(platform.machine() in s for s in list_of_x86):
+ if env["arch"] in ["x86_64", "x86_32"]:
env["x86_libtheora_opt_gcc"] = True
if not env["builtin_libvorbis"]:
@@ -388,11 +369,13 @@ def configure(env):
if env["execinfo"]:
env.Append(LIBS=["execinfo"])
- if not env["tools"]:
+ if not env.editor_build:
import subprocess
import re
- linker_version_str = subprocess.check_output([env.subst(env["LINK"]), "-Wl,--version"]).decode("utf-8")
+ linker_version_str = subprocess.check_output(
+ [env.subst(env["LINK"]), "-Wl,--version"] + env.subst(env["LINKFLAGS"])
+ ).decode("utf-8")
gnu_ld_version = re.search("^GNU ld [^$]*(\d+\.\d+)$", linker_version_str, re.MULTILINE)
if not gnu_ld_version:
print(
@@ -405,11 +388,12 @@ def configure(env):
env.Append(LINKFLAGS=["-T", "platform/linuxbsd/pck_embed.legacy.ld"])
## Cross-compilation
-
- if is64 and env["bits"] == "32":
+ # TODO: Support cross-compilation on architectures other than x86.
+ host_is_64_bit = sys.maxsize > 2**32
+ if host_is_64_bit and env["arch"] == "x86_32":
env.Append(CCFLAGS=["-m32"])
env.Append(LINKFLAGS=["-m32", "-L/usr/lib/i386-linux-gnu"])
- elif not is64 and env["bits"] == "64":
+ elif not host_is_64_bit and env["arch"] == "x86_64":
env.Append(CCFLAGS=["-m64"])
env.Append(LINKFLAGS=["-m64", "-L/usr/lib/i686-linux-gnu"])
diff --git a/platform/linuxbsd/detect_prime_x11.h b/platform/linuxbsd/detect_prime_x11.h
index 21ebaead32..7eb7064cc5 100644
--- a/platform/linuxbsd/detect_prime_x11.h
+++ b/platform/linuxbsd/detect_prime_x11.h
@@ -28,11 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef X11_ENABLED
-#if defined(GLES3_ENABLED)
+#ifndef DETECT_PRIME_X11_H
+#define DETECT_PRIME_X11_H
+
+#if defined(X11_ENABLED) && defined(GLES3_ENABLED)
int detect_prime();
-#endif
+#endif // X11_ENABLED && GLES3_ENABLED
#endif // DETECT_PRIME_X11_H
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 63998e2fde..66dea6cf1b 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -349,6 +349,28 @@ void DisplayServerX11::tts_stop() {
#endif
+#ifdef DBUS_ENABLED
+
+bool DisplayServerX11::is_dark_mode_supported() const {
+ return portal_desktop->is_supported();
+}
+
+bool DisplayServerX11::is_dark_mode() const {
+ switch (portal_desktop->get_appearance_color_scheme()) {
+ case 1:
+ // Prefers dark theme.
+ return true;
+ case 2:
+ // Prefers light theme.
+ return false;
+ default:
+ // Preference unknown.
+ return false;
+ }
+}
+
+#endif
+
void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
_THREAD_SAFE_METHOD_
@@ -375,7 +397,10 @@ void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
//flush pending motion events
_flush_mouse_motion();
- WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
WindowData &window = windows[window_id];
if (XGrabPointer(
@@ -411,7 +436,11 @@ void DisplayServerX11::warp_mouse(const Point2i &p_position) {
if (mouse_mode == MOUSE_MODE_CAPTURED) {
last_mouse_pos = p_position;
} else {
- WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
+
XWarpPointer(x11_display, None, windows[window_id].x11_window,
0, 0, 0, 0, (int)p_position.x, (int)p_position.y);
}
@@ -993,7 +1022,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
Rect2i left_rect(pos.x, pos.y + left_start_y, left, left_end_y - left_start_y);
if (left_rect.size.x > 0) {
Rect2i intersection = rect.intersection(left_rect);
- if (!intersection.has_no_area() && intersection.size.x < rect.size.x) {
+ if (intersection.has_area() && intersection.size.x < rect.size.x) {
rect.position.x = left_rect.size.x;
rect.size.x = rect.size.x - intersection.size.x;
}
@@ -1002,7 +1031,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
Rect2i right_rect(pos.x + size.x - right, pos.y + right_start_y, right, right_end_y - right_start_y);
if (right_rect.size.x > 0) {
Rect2i intersection = rect.intersection(right_rect);
- if (!intersection.has_no_area() && right_rect.size.x < rect.size.x) {
+ if (intersection.has_area() && right_rect.size.x < rect.size.x) {
rect.size.x = intersection.position.x - rect.position.x;
}
}
@@ -1010,7 +1039,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
Rect2i top_rect(pos.x + top_start_x, pos.y, top_end_x - top_start_x, top);
if (top_rect.size.y > 0) {
Rect2i intersection = rect.intersection(top_rect);
- if (!intersection.has_no_area() && intersection.size.y < rect.size.y) {
+ if (intersection.has_area() && intersection.size.y < rect.size.y) {
rect.position.y = top_rect.size.y;
rect.size.y = rect.size.y - intersection.size.y;
}
@@ -1019,7 +1048,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const {
Rect2i bottom_rect(pos.x + bottom_start_x, pos.y + size.y - bottom, bottom_end_x - bottom_start_x, bottom);
if (bottom_rect.size.y > 0) {
Rect2i intersection = rect.intersection(bottom_rect);
- if (!intersection.has_no_area() && right_rect.size.y < rect.size.y) {
+ if (intersection.has_area() && right_rect.size.y < rect.size.y) {
rect.size.y = intersection.position.y - rect.position.y;
}
}
@@ -1522,11 +1551,15 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent
XSetTransientForHint(x11_display, wd_window.x11_window, None);
+ XWindowAttributes xwa;
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, wd_parent.x11_window, &xwa);
+
// Set focus to parent sub window to avoid losing all focus when closing a nested sub-menu.
// RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed.
if (!wd_window.no_focus && !wd_window.is_popup && wd_window.focused) {
- if (!wd_parent.no_focus && !wd_window.is_popup) {
+ if ((xwa.map_state == IsViewable) && !wd_parent.no_focus && !wd_window.is_popup) {
XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime);
}
}
@@ -1819,6 +1852,47 @@ bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_a
return retval;
}
+bool DisplayServerX11::_window_minimize_check(WindowID p_window) const {
+ const WindowData &wd = windows[p_window];
+
+ // Using ICCCM -- Inter-Client Communication Conventions Manual
+ Atom property = XInternAtom(x11_display, "WM_STATE", True);
+ if (property == None) {
+ return false;
+ }
+
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = nullptr;
+
+ int result = XGetWindowProperty(
+ x11_display,
+ wd.x11_window,
+ property,
+ 0,
+ 32,
+ False,
+ AnyPropertyType,
+ &type,
+ &format,
+ &len,
+ &remaining,
+ &data);
+
+ if (result == Success && data) {
+ long *state = (long *)data;
+ if (state[0] == WM_IconicState) {
+ XFree(data);
+ return true;
+ }
+ XFree(data);
+ }
+
+ return false;
+}
+
bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
ERR_FAIL_COND_V(!windows.has(p_window), false);
const WindowData &wd = windows[p_window];
@@ -1865,6 +1939,18 @@ bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
return retval;
}
+void DisplayServerX11::_validate_mode_on_map(WindowID p_window) {
+ // Check if we applied any window modes that didn't take effect while unmapped
+ const WindowData &wd = windows[p_window];
+ if (wd.fullscreen && !_window_fullscreen_check(p_window)) {
+ _set_wm_fullscreen(p_window, true);
+ } else if (wd.maximized && !_window_maximize_check(p_window, "_NET_WM_STATE")) {
+ _set_wm_maximized(p_window, true);
+ } else if (wd.minimized && !_window_minimize_check(p_window)) {
+ _set_wm_minimized(p_window, true);
+ }
+}
+
bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const {
_THREAD_SAFE_METHOD_
return _window_maximize_check(p_window, "_NET_WM_ALLOWED_ACTIONS");
@@ -1899,6 +1985,37 @@ void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) {
usleep(10000);
}
}
+ wd.maximized = p_enabled;
+}
+
+void DisplayServerX11::_set_wm_minimized(WindowID p_window, bool p_enabled) {
+ WindowData &wd = windows[p_window];
+ // Using ICCCM -- Inter-Client Communication Conventions Manual
+ XEvent xev;
+ Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_change;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = p_enabled ? WM_IconicState : WM_NormalState;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_state;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+ xev.xclient.data.l[1] = wm_hidden;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ wd.minimized = p_enabled;
}
void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) {
@@ -1980,32 +2097,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
//do nothing
} break;
case WINDOW_MODE_MINIMIZED: {
- //Un-Minimize
- // Using ICCCM -- Inter-Client Communication Conventions Manual
- XEvent xev;
- Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = wm_change;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = WM_NormalState;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
-
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
- xev.xclient.data.l[1] = wm_hidden;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ _set_wm_minimized(p_window, false);
} break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: {
@@ -2034,31 +2126,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
//do nothing
} break;
case WINDOW_MODE_MINIMIZED: {
- // Using ICCCM -- Inter-Client Communication Conventions Manual
- XEvent xev;
- Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = wm_change;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = WM_IconicState;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
-
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
- xev.xclient.data.l[1] = wm_hidden;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ _set_wm_minimized(p_window, true);
} break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: {
@@ -2093,40 +2161,9 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c
return WINDOW_MODE_MAXIMIZED;
}
- { // Test minimized.
- // Using ICCCM -- Inter-Client Communication Conventions Manual
- Atom property = XInternAtom(x11_display, "WM_STATE", True);
- if (property == None) {
- return WINDOW_MODE_WINDOWED;
- }
-
- Atom type;
- int format;
- unsigned long len;
- unsigned long remaining;
- unsigned char *data = nullptr;
-
- int result = XGetWindowProperty(
- x11_display,
- wd.x11_window,
- property,
- 0,
- 32,
- False,
- AnyPropertyType,
- &type,
- &format,
- &len,
- &remaining,
- &data);
-
- if (result == Success && data) {
- long *state = (long *)data;
- if (state[0] == WM_IconicState) {
- XFree(data);
- return WINDOW_MODE_MINIMIZED;
- }
- XFree(data);
+ {
+ if (_window_minimize_check(p_window)) {
+ return WINDOW_MODE_MINIMIZED;
}
}
@@ -2191,7 +2228,7 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
} break;
case WINDOW_FLAG_TRANSPARENT: {
- //todo reimplement
+ wd.layered_window = p_enabled;
} break;
case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled;
@@ -2244,7 +2281,7 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co
return wd.on_top;
} break;
case WINDOW_FLAG_TRANSPARENT: {
- //todo reimplement
+ return wd.layered_window;
} break;
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
@@ -3151,6 +3188,15 @@ void DisplayServerX11::_window_changed(XEvent *event) {
}
}
+DisplayServer::WindowID DisplayServerX11::_get_focused_window_or_popup() const {
+ const List<WindowID>::Element *E = popup_list.back();
+ if (E) {
+ return E->get();
+ }
+
+ return last_focused_window;
+}
+
void DisplayServerX11::_dispatch_input_events(const Ref<InputEvent> &p_event) {
static_cast<DisplayServerX11 *>(get_singleton())->_dispatch_input_event(p_event);
}
@@ -3646,12 +3692,19 @@ void DisplayServerX11::process_events() {
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 started.
// RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed.
- if (!wd.no_focus && !wd.is_popup) {
+ if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) {
XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
}
+
+ // Have we failed to set fullscreen while the window was unmapped?
+ _validate_mode_on_map(window_id);
} break;
case Expose: {
@@ -3671,8 +3724,7 @@ void DisplayServerX11::process_events() {
case VisibilityNotify: {
DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state);
- XVisibilityEvent *visibility = (XVisibilityEvent *)&event;
- windows[window_id].minimized = (visibility->state == VisibilityFullyObscured);
+ windows[window_id].minimized = _window_minimize_check(window_id);
} break;
case LeaveNotify: {
@@ -3900,7 +3952,11 @@ void DisplayServerX11::process_events() {
// The X11 API requires filtering one-by-one through the motion
// notify events, in order to figure out which event is the one
// generated by warping the mouse pointer.
- WindowID focused_window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID focused_window_id = _get_focused_window_or_popup();
+ if (!windows.has(focused_window_id)) {
+ focused_window_id = MAIN_WINDOW_ID;
+ }
+
while (true) {
if (mouse_mode == MOUSE_MODE_CAPTURED && event.xmotion.x == windows[focused_window_id].size.width / 2 && event.xmotion.y == windows[focused_window_id].size.height / 2) {
//this is likely the warp event since it was warped here
@@ -4390,13 +4446,41 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W
DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) {
//Create window
- long visualMask = VisualScreenMask;
- int numberOfVisuals;
- XVisualInfo vInfoTemplate = {};
- vInfoTemplate.screen = DefaultScreen(x11_display);
- XVisualInfo *visualInfo = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals);
+ XVisualInfo visualInfo;
+ bool vi_selected = false;
+
+#ifdef GLES3_ENABLED
+ if (gl_manager) {
+ visualInfo = gl_manager->get_vi(x11_display);
+ vi_selected = true;
+ }
+#endif
+
+ if (!vi_selected) {
+ long visualMask = VisualScreenMask;
+ int numberOfVisuals;
+ XVisualInfo vInfoTemplate = {};
+ vInfoTemplate.screen = DefaultScreen(x11_display);
+ XVisualInfo *vi_list = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals);
+ ERR_FAIL_COND_V(!vi_list, INVALID_WINDOW_ID);
+
+ visualInfo = vi_list[0];
+ if (OS::get_singleton()->is_layered_allowed()) {
+ for (int i = 0; i < numberOfVisuals; i++) {
+ XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi_list[i].visual);
+ if (!pict_format) {
+ continue;
+ }
+ visualInfo = vi_list[i];
+ if (pict_format->direct.alphaMask > 0) {
+ break;
+ }
+ }
+ }
+ XFree(vi_list);
+ }
- Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, vInfoTemplate.screen), visualInfo->visual, AllocNone);
+ Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, visualInfo.screen), visualInfo.visual, AllocNone);
XSetWindowAttributes windowAttributes = {};
windowAttributes.colormap = colormap;
@@ -4406,6 +4490,13 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
+ if (OS::get_singleton()->is_layered_allowed()) {
+ windowAttributes.background_pixmap = None;
+ windowAttributes.background_pixel = 0;
+ windowAttributes.border_pixmap = None;
+ valuemask |= CWBackPixel;
+ }
+
WindowID id = window_id_counter++;
WindowData &wd = windows[id];
@@ -4429,7 +4520,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
}
{
- wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes);
+ wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo.screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes);
// Enable receiving notification when the window is initialized (MapNotify)
// so the focus can be set at the right time.
@@ -4566,8 +4657,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
XSync(x11_display, False);
//XSetErrorHandler(oldHandler);
-
- XFree(visualInfo);
}
window_set_mode(p_mode, id);
@@ -4831,6 +4920,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
}
show_window(main_window);
+ XSync(x11_display, False);
+ _validate_mode_on_map(main_window);
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
@@ -4977,14 +5068,13 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
cursor_set_shape(CURSOR_BUSY);
- XEvent xevent;
- while (XPending(x11_display) > 0) {
- XNextEvent(x11_display, &xevent);
- if (xevent.type == ConfigureNotify) {
- _window_changed(&xevent);
- }
+ // Search the X11 event queue for ConfigureNotify events and process all
+ // that are currently queued early, so we can get the final window size
+ // for correctly drawing of the bootsplash.
+ XEvent config_event;
+ while (XCheckTypedEvent(x11_display, ConfigureNotify, &config_event)) {
+ _window_changed(&config_event);
}
-
events_thread.start(_poll_events_thread, this);
_update_real_mouse_position(windows[MAIN_WINDOW_ID]);
@@ -4992,6 +5082,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
#ifdef DBUS_ENABLED
screensaver = memnew(FreeDesktopScreenSaver);
screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
+
+ portal_desktop = memnew(FreeDesktopPortalDesktop);
#endif
r_error = OK;
@@ -5077,6 +5169,7 @@ DisplayServerX11::~DisplayServerX11() {
#ifdef DBUS_ENABLED
memdelete(screensaver);
+ memdelete(portal_desktop);
#endif
}
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 0174cfb881..a5fa7613bc 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -60,6 +60,7 @@
#endif
#if defined(DBUS_ENABLED)
+#include "freedesktop_portal_desktop.h"
#include "freedesktop_screensaver.h"
#endif
@@ -120,6 +121,10 @@ class DisplayServerX11 : public DisplayServer {
TTS_Linux *tts = nullptr;
#endif
+#if defined(DBUS_ENABLED)
+ FreeDesktopPortalDesktop *portal_desktop = nullptr;
+#endif
+
struct WindowData {
Window x11_window;
::XIC xic;
@@ -152,7 +157,9 @@ class DisplayServerX11 : public DisplayServer {
Vector2i last_position_before_fs;
bool focused = true;
bool minimized = false;
+ bool maximized = false;
bool is_popup = false;
+ bool layered_window = false;
Rect2i parent_safe_rect;
@@ -245,8 +252,6 @@ class DisplayServerX11 : public DisplayServer {
CursorShape current_cursor = CURSOR_ARROW;
HashMap<CursorShape, Vector<Variant>> cursors_cache;
- bool layered_window = false;
-
String rendering_driver;
void set_wm_fullscreen(bool p_enabled);
void set_wm_above(bool p_enabled);
@@ -268,14 +273,19 @@ class DisplayServerX11 : public DisplayServer {
void _update_real_mouse_position(const WindowData &wd);
bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const;
bool _window_fullscreen_check(WindowID p_window) const;
+ bool _window_minimize_check(WindowID p_window) const;
+ void _validate_mode_on_map(WindowID p_window);
void _update_size_hints(WindowID p_window);
void _set_wm_fullscreen(WindowID p_window, bool p_enabled);
void _set_wm_maximized(WindowID p_window, bool p_enabled);
+ void _set_wm_minimized(WindowID p_window, bool p_enabled);
void _update_context(WindowData &wd);
Context context = CONTEXT_ENGINE;
+ WindowID _get_focused_window_or_popup() const;
+
void _send_window_event(const WindowData &wd, WindowEvent p_event);
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
void _dispatch_input_event(const Ref<InputEvent> &p_event);
@@ -316,6 +326,11 @@ public:
virtual void tts_stop() override;
#endif
+#if defined(DBUS_ENABLED)
+ virtual bool is_dark_mode_supported() const override;
+ virtual bool is_dark_mode() const override;
+#endif
+
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp
new file mode 100644
index 0000000000..ed54084694
--- /dev/null
+++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp
@@ -0,0 +1,135 @@
+/*************************************************************************/
+/* freedesktop_portal_desktop.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 "freedesktop_portal_desktop.h"
+
+#ifdef DBUS_ENABLED
+
+#include "core/error/error_macros.h"
+#include "core/os/os.h"
+#include "core/string/ustring.h"
+
+#include "dbus-so_wrap.h"
+
+#include "core/variant/variant.h"
+
+#define BUS_OBJECT_NAME "org.freedesktop.portal.Desktop"
+#define BUS_OBJECT_PATH "/org/freedesktop/portal/desktop"
+
+#define BUS_INTERFACE_SETTINGS "org.freedesktop.portal.Settings"
+
+static bool try_parse_variant(DBusMessage *p_reply_message, int p_type, void *r_value) {
+ DBusMessageIter iter[3];
+
+ dbus_message_iter_init(p_reply_message, &iter[0]);
+ if (dbus_message_iter_get_arg_type(&iter[0]) != DBUS_TYPE_VARIANT) {
+ return false;
+ }
+
+ dbus_message_iter_recurse(&iter[0], &iter[1]);
+ if (dbus_message_iter_get_arg_type(&iter[1]) != DBUS_TYPE_VARIANT) {
+ return false;
+ }
+
+ dbus_message_iter_recurse(&iter[1], &iter[2]);
+ if (dbus_message_iter_get_arg_type(&iter[2]) != p_type) {
+ return false;
+ }
+
+ dbus_message_iter_get_basic(&iter[2], r_value);
+ return true;
+}
+
+bool FreeDesktopPortalDesktop::read_setting(const char *p_namespace, const char *p_key, int p_type, void *r_value) {
+ if (unsupported) {
+ return false;
+ }
+
+ DBusError error;
+ dbus_error_init(&error);
+
+ DBusConnection *bus = dbus_bus_get(DBUS_BUS_SESSION, &error);
+ if (dbus_error_is_set(&error)) {
+ dbus_error_free(&error);
+ unsupported = true;
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ ERR_PRINT(String() + "Error opening D-Bus connection: " + error.message);
+ }
+ return false;
+ }
+
+ DBusMessage *message = dbus_message_new_method_call(
+ BUS_OBJECT_NAME, BUS_OBJECT_PATH, BUS_INTERFACE_SETTINGS,
+ "Read");
+ dbus_message_append_args(
+ message,
+ DBUS_TYPE_STRING, &p_namespace,
+ DBUS_TYPE_STRING, &p_key,
+ DBUS_TYPE_INVALID);
+
+ DBusMessage *reply = dbus_connection_send_with_reply_and_block(bus, message, 50, &error);
+ dbus_message_unref(message);
+ if (dbus_error_is_set(&error)) {
+ dbus_error_free(&error);
+ dbus_connection_unref(bus);
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ ERR_PRINT(String() + "Error on D-Bus communication: " + error.message);
+ }
+ return false;
+ }
+
+ bool success = try_parse_variant(reply, p_type, r_value);
+
+ dbus_message_unref(reply);
+ dbus_connection_unref(bus);
+
+ return success;
+}
+
+uint32_t FreeDesktopPortalDesktop::get_appearance_color_scheme() {
+ if (unsupported) {
+ return 0;
+ }
+
+ uint32_t value = 0;
+ read_setting("org.freedesktop.appearance", "color-scheme", DBUS_TYPE_UINT32, &value);
+ return value;
+}
+
+FreeDesktopPortalDesktop::FreeDesktopPortalDesktop() {
+#ifdef DEBUG_ENABLED
+ int dylibloader_verbose = 1;
+#else
+ int dylibloader_verbose = 0;
+#endif
+ unsupported = (initialize_dbus(dylibloader_verbose) != 0);
+}
+
+#endif // DBUS_ENABLED
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.h b/platform/linuxbsd/freedesktop_portal_desktop.h
new file mode 100644
index 0000000000..3d976b1ede
--- /dev/null
+++ b/platform/linuxbsd/freedesktop_portal_desktop.h
@@ -0,0 +1,59 @@
+/*************************************************************************/
+/* freedesktop_portal_desktop.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 FREEDESKTOP_PORTAL_DESKTOP_H
+#define FREEDESKTOP_PORTAL_DESKTOP_H
+
+#ifdef DBUS_ENABLED
+
+#include <stdint.h>
+
+class FreeDesktopPortalDesktop {
+private:
+ bool unsupported = false;
+
+ // Read a setting from org.freekdesktop.portal.Settings
+ bool read_setting(const char *p_namespace, const char *p_key, int p_type, void *r_value);
+
+public:
+ FreeDesktopPortalDesktop();
+
+ bool is_supported() { return !unsupported; }
+
+ // 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();
+};
+
+#endif // DBUS_ENABLED
+
+#endif // FREEDESKTOP_PORTAL_DESKTOP_H
diff --git a/platform/linuxbsd/gl_manager_x11.cpp b/platform/linuxbsd/gl_manager_x11.cpp
index d3fb1d6705..f586c57dda 100644
--- a/platform/linuxbsd/gl_manager_x11.cpp
+++ b/platform/linuxbsd/gl_manager_x11.cpp
@@ -127,10 +127,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
GLXFBConfig fbconfig = nullptr;
XVisualInfo *vi = nullptr;
- gl_display.x_swa.event_mask = StructureNotifyMask;
- gl_display.x_swa.border_pixel = 0;
- gl_display.x_valuemask = CWBorderPixel | CWColormap | CWEventMask;
-
if (OS::get_singleton()->is_layered_allowed()) {
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount);
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
@@ -156,12 +152,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
XFree(fbc);
ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED);
-
- gl_display.x_swa.background_pixmap = None;
- gl_display.x_swa.background_pixel = 0;
- gl_display.x_swa.border_pixmap = None;
- gl_display.x_valuemask |= CWBackPixel;
-
} else {
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
@@ -189,8 +179,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
} break;
}
- gl_display.x_swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone);
-
XSync(x11_display, False);
XSetErrorHandler(oldHandler);
@@ -205,6 +193,10 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
return OK;
}
+XVisualInfo GLManager_X11::get_vi(Display *p_display) {
+ return _displays[_find_or_create_display(p_display)].x_vi;
+}
+
Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) {
// make sure vector is big enough...
// we can mirror the external vector, it is simpler
@@ -223,8 +215,6 @@ Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window
// the display could be invalid .. check NYI
GLDisplay &gl_display = _displays[win.gldisplay_id];
- //const XVisualInfo &vi = gl_display.x_vi;
- //XSetWindowAttributes &swa = gl_display.x_swa;
::Display *x11_display = gl_display.x11_display;
::Window &x11_window = win.x11_window;
@@ -266,7 +256,11 @@ void GLManager_X11::release_current() {
if (!_current_window) {
return;
}
- glXMakeCurrent(_x_windisp.x11_display, None, nullptr);
+
+ if (!glXMakeCurrent(_x_windisp.x11_display, None, nullptr)) {
+ ERR_PRINT("glXMakeCurrent failed");
+ }
+ _current_window = nullptr;
}
void GLManager_X11::window_make_current(DisplayServer::WindowID p_window_id) {
@@ -286,7 +280,9 @@ void GLManager_X11::window_make_current(DisplayServer::WindowID p_window_id) {
const GLDisplay &disp = get_display(win.gldisplay_id);
- glXMakeCurrent(disp.x11_display, win.x11_window, disp.context->glx_context);
+ if (!glXMakeCurrent(disp.x11_display, win.x11_window, disp.context->glx_context)) {
+ ERR_PRINT("glXMakeCurrent failed");
+ }
_internal_set_current_window(&win);
}
@@ -300,13 +296,12 @@ void GLManager_X11::make_current() {
return;
}
const GLDisplay &disp = get_current_display();
- glXMakeCurrent(_x_windisp.x11_display, _x_windisp.x11_window, disp.context->glx_context);
+ if (!glXMakeCurrent(_x_windisp.x11_display, _x_windisp.x11_window, disp.context->glx_context)) {
+ ERR_PRINT("glXMakeCurrent failed");
+ }
}
void GLManager_X11::swap_buffers() {
- // NO NEED TO CALL SWAP BUFFERS for each window...
- // see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml
-
if (!_current_window) {
return;
}
@@ -315,13 +310,16 @@ void GLManager_X11::swap_buffers() {
return;
}
- // print_line("\tswap_buffers");
-
- // only for debugging without drawing anything
- // glClearColor(Math::randf(), 0, 1, 1);
- //glClear(GL_COLOR_BUFFER_BIT);
+ // On X11, when enabled, transparency is always active, so clear alpha manually.
+ if (OS::get_singleton()->is_layered_allowed()) {
+ if (!DisplayServer::get_singleton()->window_get_flag(DisplayServer::WINDOW_FLAG_TRANSPARENT, _current_window->window_id)) {
+ glColorMask(false, false, false, true);
+ glClearColor(0, 0, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColorMask(true, true, true, true);
+ }
+ }
- //const GLDisplay &disp = get_current_display();
glXSwapBuffers(_x_windisp.x11_display, _x_windisp.x11_window);
}
diff --git a/platform/linuxbsd/gl_manager_x11.h b/platform/linuxbsd/gl_manager_x11.h
index fb2c74a2b6..4f78c45c88 100644
--- a/platform/linuxbsd/gl_manager_x11.h
+++ b/platform/linuxbsd/gl_manager_x11.h
@@ -68,8 +68,6 @@ private:
GLManager_X11_Private *context = nullptr;
::Display *x11_display;
XVisualInfo x_vi;
- XSetWindowAttributes x_swa;
- unsigned long x_valuemask;
};
// just for convenience, window and display struct
@@ -102,6 +100,7 @@ private:
Error _create_context(GLDisplay &gl_display);
public:
+ XVisualInfo get_vi(Display *p_display);
Error window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height);
void window_destroy(DisplayServer::WindowID p_window_id);
void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 197d31dc81..f4e94f1a91 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -50,6 +50,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/utsname.h>
#include <unistd.h>
#ifdef FONTCONFIG_ENABLED
@@ -65,7 +66,7 @@ void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) {
for (int i = 0; i < path_elems.size(); i++) {
for (uint64_t k = 0; k < sizeof(message_programs) / sizeof(char *); k++) {
- String tested_path = path_elems[i].plus_file(message_programs[k]);
+ String tested_path = path_elems[i].path_join(message_programs[k]);
if (FileAccess::exists(tested_path)) {
program = tested_path;
@@ -205,6 +206,42 @@ String OS_LinuxBSD::get_name() const {
#endif
}
+String OS_LinuxBSD::get_systemd_os_release_info_value(const String &key) const {
+ static String info;
+ if (info.is_empty()) {
+ Ref<FileAccess> f = FileAccess::open("/etc/os-release", FileAccess::READ);
+ if (f.is_valid()) {
+ while (!f->eof_reached()) {
+ const String line = f->get_line();
+ if (line.find(key) != -1) {
+ return line.split("=")[1].strip_edges();
+ }
+ }
+ }
+ }
+ return info;
+}
+
+String OS_LinuxBSD::get_distribution_name() const {
+ static String systemd_name = get_systemd_os_release_info_value("NAME"); // returns a value for systemd users, otherwise an empty string.
+ if (!systemd_name.is_empty()) {
+ return systemd_name;
+ }
+ struct utsname uts; // returns a decent value for BSD family.
+ uname(&uts);
+ return uts.sysname;
+}
+
+String OS_LinuxBSD::get_version() const {
+ static String systemd_version = get_systemd_os_release_info_value("VERSION"); // returns a value for systemd users, otherwise an empty string.
+ if (!systemd_version.is_empty()) {
+ return systemd_version;
+ }
+ struct utsname uts; // returns a decent value for BSD family.
+ uname(&uts);
+ return uts.version;
+}
+
Error OS_LinuxBSD::shell_open(String p_uri) {
Error ok;
int err_code;
@@ -432,10 +469,10 @@ String OS_LinuxBSD::get_config_path() const {
return get_environment("XDG_CONFIG_HOME");
} else {
WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.config` or `.` per the XDG Base Directory specification.");
- return has_environment("HOME") ? get_environment("HOME").plus_file(".config") : ".";
+ return has_environment("HOME") ? get_environment("HOME").path_join(".config") : ".";
}
} else if (has_environment("HOME")) {
- return get_environment("HOME").plus_file(".config");
+ return get_environment("HOME").path_join(".config");
} else {
return ".";
}
@@ -447,10 +484,10 @@ String OS_LinuxBSD::get_data_path() const {
return get_environment("XDG_DATA_HOME");
} else {
WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.local/share` or `get_config_path()` per the XDG Base Directory specification.");
- return has_environment("HOME") ? get_environment("HOME").plus_file(".local/share") : get_config_path();
+ return has_environment("HOME") ? get_environment("HOME").path_join(".local/share") : get_config_path();
}
} else if (has_environment("HOME")) {
- return get_environment("HOME").plus_file(".local/share");
+ return get_environment("HOME").path_join(".local/share");
} else {
return get_config_path();
}
@@ -462,10 +499,10 @@ String OS_LinuxBSD::get_cache_path() const {
return get_environment("XDG_CACHE_HOME");
} else {
WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.cache` or `get_config_path()` per the XDG Base Directory specification.");
- return has_environment("HOME") ? get_environment("HOME").plus_file(".cache") : get_config_path();
+ return has_environment("HOME") ? get_environment("HOME").path_join(".cache") : get_config_path();
}
} else if (has_environment("HOME")) {
- return get_environment("HOME").plus_file(".cache");
+ return get_environment("HOME").path_join(".cache");
} else {
return get_config_path();
}
@@ -519,8 +556,6 @@ String OS_LinuxBSD::get_system_dir(SystemDir p_dir, bool p_shared_storage) const
}
void OS_LinuxBSD::run() {
- force_quit = false;
-
if (!main_loop) {
return;
}
@@ -532,7 +567,7 @@ void OS_LinuxBSD::run() {
//int frames=0;
//uint64_t frame=0;
- while (!force_quit) {
+ while (true) {
DisplayServer::get_singleton()->process_events(); // get rid of pending events
#ifdef JOYDEV_ENABLED
joypad->process_joypads();
@@ -688,10 +723,9 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
String renamed_path = path.get_base_dir() + "/" + file_name;
// Generates the .trashinfo file
- OS::Date date = OS::get_singleton()->get_date(false);
- OS::Time time = OS::get_singleton()->get_time(false);
- String timestamp = vformat("%04d-%02d-%02dT%02d:%02d:", date.year, (int)date.month, date.day, time.hour, time.minute);
- timestamp = vformat("%s%02d", timestamp, time.second); // vformat only supports up to 6 arguments.
+ OS::DateTime dt = OS::get_singleton()->get_datetime(false);
+ String timestamp = vformat("%04d-%02d-%02dT%02d:%02d:", dt.year, (int)dt.month, dt.day, dt.hour, dt.minute);
+ timestamp = vformat("%s%02d", timestamp, dt.second); // vformat only supports up to 6 arguments.
String trash_info = "[Trash Info]\nPath=" + path.uri_encode() + "\nDeletionDate=" + timestamp + "\n";
{
Error err;
@@ -730,7 +764,6 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
OS_LinuxBSD::OS_LinuxBSD() {
main_loop = nullptr;
- force_quit = false;
#ifdef PULSEAUDIO_ENABLED
AudioDriverManager::add_driver(&driver_pulseaudio);
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index cc4e91e885..722d83ba19 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -43,8 +43,6 @@
class OS_LinuxBSD : public OS_Unix {
virtual void delete_main_loop() override;
- bool force_quit;
-
#ifdef FONTCONFIG_ENABLED
bool font_config_initialized = false;
#endif
@@ -69,6 +67,8 @@ class OS_LinuxBSD : public OS_Unix {
MainLoop *main_loop = nullptr;
+ String get_systemd_os_release_info_value(const String &key) const;
+
protected:
virtual void initialize() override;
virtual void finalize() override;
@@ -79,6 +79,8 @@ protected:
public:
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual MainLoop *get_main_loop() const override;