summaryrefslogtreecommitdiff
path: root/platform/linuxbsd
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r--platform/linuxbsd/crash_handler_linuxbsd.cpp2
-rw-r--r--platform/linuxbsd/detect.py43
-rw-r--r--platform/linuxbsd/detect_prime_x11.h8
-rw-r--r--platform/linuxbsd/display_server_x11.cpp72
-rw-r--r--platform/linuxbsd/display_server_x11.h3
-rw-r--r--platform/linuxbsd/gl_manager_x11.cpp26
-rw-r--r--platform/linuxbsd/key_mapping_x11.cpp26
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp247
-rw-r--r--platform/linuxbsd/os_linuxbsd.h9
9 files changed, 348 insertions, 88 deletions
diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp
index 33da094860..8c8c8588b8 100644
--- a/platform/linuxbsd/crash_handler_linuxbsd.cpp
+++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp
@@ -89,7 +89,7 @@ static void handle_crash(int sig) {
// Try to demangle the function name to provide a more readable one
if (dladdr(bt_buffer[i], &info) && info.dli_sname) {
if (info.dli_sname[0] == '_') {
- int status;
+ int status = 0;
char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
if (status == 0 && demangled) {
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 36644d5f29..ac69f3806b 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -4,6 +4,11 @@ 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():
return True
@@ -44,8 +49,6 @@ def get_opts():
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),
]
@@ -57,7 +60,7 @@ def get_flags():
]
-def configure(env):
+def configure(env: "Environment"):
# Validate arch.
supported_arches = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64"]
if env["arch"] not in supported_arches:
@@ -69,26 +72,9 @@ 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"])
-
- 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"])
-
- if env["debug_symbols"]:
- env.Prepend(CCFLAGS=["-g2"])
-
- 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"])
# CPU architecture flags.
@@ -171,6 +157,10 @@ def configure(env):
env.Append(LINKFLAGS=["-fsanitize=memory"])
# 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"]:
@@ -373,13 +363,16 @@ def configure(env):
if platform.system() == "Linux":
env.Append(LIBS=["dl"])
- if platform.system().find("BSD") >= 0:
+ 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["tools"]:
+ if not env.editor_build:
import subprocess
import re
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 0236e134fb..e78467beff 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -49,10 +49,14 @@
#include "drivers/gles3/rasterizer_gles3.h"
#endif
+#include <dlfcn.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
@@ -66,17 +70,6 @@
#define _NET_WM_STATE_REMOVE 0L // remove/unset property
#define _NET_WM_STATE_ADD 1L // add/set property
-#include <dlfcn.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-//stupid linux.h
-#ifdef KEY_TAB
-#undef KEY_TAB
-#endif
-
#undef CursorShape
#include <X11/XKBlib.h>
@@ -397,7 +390,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(
@@ -433,7 +429,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);
}
@@ -1202,16 +1202,6 @@ float DisplayServerX11::screen_get_refresh_rate(int p_screen) const {
return SCREEN_REFRESH_RATE_FALLBACK;
}
-bool DisplayServerX11::screen_is_touchscreen(int p_screen) const {
- _THREAD_SAFE_METHOD_
-
-#ifndef _MSC_VER
-#warning Need to get from proper window
-#endif
-
- return DisplayServer::screen_is_touchscreen(p_screen);
-}
-
#ifdef DBUS_ENABLED
void DisplayServerX11::screen_set_keep_on(bool p_enable) {
if (screen_is_kept_on() == p_enable) {
@@ -1739,6 +1729,18 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
usleep(10000);
}
+
+ // Keep rendering context window size in sync
+#if defined(VULKAN_ENABLED)
+ if (context_vulkan) {
+ context_vulkan->window_resize(p_window, xwa.width, xwa.height);
+ }
+#endif
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ gl_manager->window_resize(p_window, xwa.width, xwa.height);
+ }
+#endif
}
Size2i DisplayServerX11::window_get_size(WindowID p_window) const {
@@ -3135,9 +3137,14 @@ void DisplayServerX11::_window_changed(XEvent *event) {
return;
}
+ // Query display server about a possible new window state.
+ wd.fullscreen = _window_fullscreen_check(window_id);
+ wd.minimized = _window_minimize_check(window_id);
+ wd.maximized = _window_maximize_check(window_id, "_NET_WM_STATE");
+
{
//the position in xconfigure is not useful here, obtain it manually
- int x, y;
+ int x = 0, y = 0;
Window child;
XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
new_rect.position.x = x;
@@ -3181,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);
}
@@ -3291,7 +3307,7 @@ void DisplayServerX11::_check_pending_events(LocalVector<XEvent> &r_events) {
XFlush(x11_display);
// Non-blocking wait for next event and remove it from the queue.
- XEvent ev;
+ XEvent ev = {};
while (XCheckIfEvent(x11_display, &ev, _predicate_all_events, nullptr)) {
// Check if the input manager wants to process the event.
if (XFilterEvent(&ev, None)) {
@@ -3936,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
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index ea03b2328c..5723abc751 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -284,6 +284,8 @@ class DisplayServerX11 : public DisplayServer {
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);
@@ -347,7 +349,6 @@ public:
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
- virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
#if defined(DBUS_ENABLED)
virtual void screen_set_keep_on(bool p_enable) override;
diff --git a/platform/linuxbsd/gl_manager_x11.cpp b/platform/linuxbsd/gl_manager_x11.cpp
index 04c1df71fb..f586c57dda 100644
--- a/platform/linuxbsd/gl_manager_x11.cpp
+++ b/platform/linuxbsd/gl_manager_x11.cpp
@@ -256,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) {
@@ -276,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);
}
@@ -290,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;
}
@@ -305,7 +310,7 @@ void GLManager_X11::swap_buffers() {
return;
}
- // On X11, when enabled, transparancy is always active, so clear alpha manually.
+ // 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);
@@ -315,13 +320,6 @@ void GLManager_X11::swap_buffers() {
}
}
- // print_line("\tswap_buffers");
-
- // only for debugging without drawing anything
- // glClearColor(Math::randf(), 0, 1, 1);
- //glClear(GL_COLOR_BUFFER_BIT);
-
- //const GLDisplay &disp = get_current_display();
glXSwapBuffers(_x_windisp.x11_display, _x_windisp.x11_window);
}
diff --git a/platform/linuxbsd/key_mapping_x11.cpp b/platform/linuxbsd/key_mapping_x11.cpp
index 047ee74671..f774c99d99 100644
--- a/platform/linuxbsd/key_mapping_x11.cpp
+++ b/platform/linuxbsd/key_mapping_x11.cpp
@@ -108,17 +108,21 @@ static _XTranslatePair _xkeysym_to_keycode[] = {
{ XK_KP_7, Key::KP_7 },
{ XK_KP_8, Key::KP_8 },
{ XK_KP_9, Key::KP_9 },
- // same but with numlock
- { XK_KP_Insert, Key::KP_0 },
- { XK_KP_End, Key::KP_1 },
- { XK_KP_Down, Key::KP_2 },
- { XK_KP_Page_Down, Key::KP_3 },
- { XK_KP_Left, Key::KP_4 },
- { XK_KP_Begin, Key::KP_5 },
- { XK_KP_Right, Key::KP_6 },
- { XK_KP_Home, Key::KP_7 },
- { XK_KP_Up, Key::KP_8 },
- { XK_KP_Page_Up, Key::KP_9 },
+ // same keys but with numlock off
+ { XK_KP_Insert, Key::INSERT },
+ { XK_KP_End, Key::END },
+ { XK_KP_Down, Key::DOWN },
+ { XK_KP_Page_Down, Key::PAGEDOWN },
+ { XK_KP_Left, Key::LEFT },
+ // X11 documents this (numpad 5) as "begin of line" but no toolkit
+ // seems to interpret it this way.
+ // On Windows this is emitting Key::Clear so for consistency it
+ // will be mapped to Key::Clear
+ { XK_KP_Begin, Key::CLEAR },
+ { XK_KP_Right, Key::RIGHT },
+ { XK_KP_Home, Key::HOME },
+ { XK_KP_Up, Key::UP },
+ { XK_KP_Page_Up, Key::PAGEUP },
{ XK_F1, Key::F1 },
{ XK_F2, Key::F2 },
{ XK_F3, Key::F3 },
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 61faf3061c..995a904398 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -34,6 +34,11 @@
#include "main/main.h"
#include "servers/display_server.h"
+#include "modules/modules_enabled.gen.h" // For regex.
+#ifdef MODULE_REGEX_ENABLED
+#include "modules/regex/regex.h"
+#endif
+
#ifdef X11_ENABLED
#include "display_server_x11.h"
#endif
@@ -42,14 +47,13 @@
#include <mntent.h>
#endif
+#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-
-#include <dlfcn.h>
-#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/utsname.h>
#include <unistd.h>
#ifdef FONTCONFIG_ENABLED
@@ -205,6 +209,236 @@ 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;
+}
+
+Vector<String> OS_LinuxBSD::get_video_adapter_driver_info() const {
+ const String rendering_device_name = RenderingServer::get_singleton()->get_rendering_device()->get_device_name(); // e.g. `NVIDIA GeForce GTX 970`
+ const String rendering_device_vendor = RenderingServer::get_singleton()->get_rendering_device()->get_device_vendor_name(); // e.g. `NVIDIA`
+ const String card_name = rendering_device_name.trim_prefix(rendering_device_vendor).strip_edges(); // -> `GeForce GTX 970`
+
+ String vendor_device_id_mappings;
+ List<String> lspci_args;
+ lspci_args.push_back("-n");
+ Error err = const_cast<OS_LinuxBSD *>(this)->execute("lspci", lspci_args, &vendor_device_id_mappings);
+ if (err != OK || vendor_device_id_mappings.is_empty()) {
+ return Vector<String>();
+ }
+
+ // Usually found under "VGA", but for example NVIDIA mobile/laptop adapters are often listed under "3D" and some AMD adapters are under "Display".
+ const String dc_vga = "0300"; // VGA compatible controller
+ const String dc_display = "0302"; // Display controller
+ const String dc_3d = "0380"; // 3D controller
+
+ // splitting results by device class allows prioritizing, if multiple devices are found.
+ Vector<String> class_vga_device_candidates;
+ Vector<String> class_display_device_candidates;
+ Vector<String> class_3d_device_candidates;
+
+#ifdef MODULE_REGEX_ENABLED
+ RegEx regex_id_format = RegEx();
+ regex_id_format.compile("^[a-f0-9]{4}:[a-f0-9]{4}$"); // e.g. `10de:13c2`; IDs are always in hexadecimal
+#endif
+
+ Vector<String> value_lines = vendor_device_id_mappings.split("\n", false); // example: `02:00.0 0300: 10de:13c2 (rev a1)`
+ for (const String &line : value_lines) {
+ Vector<String> columns = line.split(" ", false);
+ if (columns.size() < 3) {
+ continue;
+ }
+ String device_class = columns[1].trim_suffix(":");
+ String vendor_device_id_mapping = columns[2];
+
+#ifdef MODULE_REGEX_ENABLED
+ if (regex_id_format.search(vendor_device_id_mapping).is_null()) {
+ continue;
+ }
+#endif
+
+ if (device_class == dc_vga) {
+ class_vga_device_candidates.push_back(vendor_device_id_mapping);
+ } else if (device_class == dc_display) {
+ class_display_device_candidates.push_back(vendor_device_id_mapping);
+ } else if (device_class == dc_3d) {
+ class_3d_device_candidates.push_back(vendor_device_id_mapping);
+ }
+ }
+
+ // Check results against currently used device (`card_name`), in case the user has multiple graphics cards.
+ const String device_lit = "Device"; // line of interest
+ class_vga_device_candidates = OS_LinuxBSD::lspci_device_filter(class_vga_device_candidates, dc_vga, device_lit, card_name);
+ class_display_device_candidates = OS_LinuxBSD::lspci_device_filter(class_display_device_candidates, dc_display, device_lit, card_name);
+ class_3d_device_candidates = OS_LinuxBSD::lspci_device_filter(class_3d_device_candidates, dc_3d, device_lit, card_name);
+
+ // Get driver names and filter out invalid ones, because some adapters are dummys used only for passthrough.
+ // And they have no indicator besides certain driver names.
+ const String kernel_lit = "Kernel driver in use"; // line of interest
+ const String dummys = "vfio"; // for e.g. pci passthrough dummy kernel driver `vfio-pci`
+ Vector<String> class_vga_device_drivers = OS_LinuxBSD::lspci_get_device_value(class_vga_device_candidates, kernel_lit, dummys);
+ Vector<String> class_display_device_drivers = OS_LinuxBSD::lspci_get_device_value(class_display_device_candidates, kernel_lit, dummys);
+ Vector<String> class_3d_device_drivers = OS_LinuxBSD::lspci_get_device_value(class_3d_device_candidates, kernel_lit, dummys);
+
+ static String driver_name;
+ static String driver_version;
+
+ // Use first valid value:
+ for (const String &driver : class_3d_device_drivers) {
+ driver_name = driver;
+ break;
+ }
+ if (driver_name.is_empty()) {
+ for (const String &driver : class_display_device_drivers) {
+ driver_name = driver;
+ break;
+ }
+ }
+ if (driver_name.is_empty()) {
+ for (const String &driver : class_vga_device_drivers) {
+ driver_name = driver;
+ break;
+ }
+ }
+
+ Vector<String> info;
+ info.push_back(driver_name);
+
+ String modinfo;
+ List<String> modinfo_args;
+ modinfo_args.push_back(driver_name);
+ err = const_cast<OS_LinuxBSD *>(this)->execute("modinfo", modinfo_args, &modinfo);
+ if (err != OK || modinfo.is_empty()) {
+ info.push_back(""); // So that this method always either returns an empty array, or an array of length 2.
+ return info;
+ }
+ Vector<String> lines = modinfo.split("\n", false);
+ for (const String &line : lines) {
+ Vector<String> columns = line.split(":", false, 1);
+ if (columns.size() < 2) {
+ continue;
+ }
+ if (columns[0].strip_edges() == "version") {
+ driver_version = columns[1].strip_edges(); // example value: `510.85.02` on Linux/BSD
+ break;
+ }
+ }
+
+ info.push_back(driver_version);
+
+ return info;
+}
+
+Vector<String> OS_LinuxBSD::lspci_device_filter(Vector<String> vendor_device_id_mapping, String class_suffix, String check_column, String whitelist) const {
+ // NOTE: whitelist can be changed to `Vector<String>`, if the need arises.
+ const String sep = ":";
+ Vector<String> devices;
+ for (const String &mapping : vendor_device_id_mapping) {
+ String device;
+ List<String> d_args;
+ d_args.push_back("-d");
+ d_args.push_back(mapping + sep + class_suffix);
+ d_args.push_back("-vmm");
+ Error err = const_cast<OS_LinuxBSD *>(this)->execute("lspci", d_args, &device); // e.g. `lspci -d 10de:13c2:0300 -vmm`
+ if (err != OK) {
+ return Vector<String>();
+ } else if (device.is_empty()) {
+ continue;
+ }
+
+ Vector<String> device_lines = device.split("\n", false);
+ for (const String &line : device_lines) {
+ Vector<String> columns = line.split(":", false, 1);
+ if (columns.size() < 2) {
+ continue;
+ }
+ if (columns[0].strip_edges() == check_column) {
+ // for `column[0] == "Device"` this may contain `GM204 [GeForce GTX 970]`
+ bool is_valid = true;
+ if (!whitelist.is_empty()) {
+ is_valid = columns[1].strip_edges().contains(whitelist);
+ }
+ if (is_valid) {
+ devices.push_back(mapping);
+ }
+ break;
+ }
+ }
+ }
+ return devices;
+}
+
+Vector<String> OS_LinuxBSD::lspci_get_device_value(Vector<String> vendor_device_id_mapping, String check_column, String blacklist) const {
+ // NOTE: blacklist can be changed to `Vector<String>`, if the need arises.
+ const String sep = ":";
+ Vector<String> values;
+ for (const String &mapping : vendor_device_id_mapping) {
+ String device;
+ List<String> d_args;
+ d_args.push_back("-d");
+ d_args.push_back(mapping);
+ d_args.push_back("-k");
+ Error err = const_cast<OS_LinuxBSD *>(this)->execute("lspci", d_args, &device); // e.g. `lspci -d 10de:13c2 -k`
+ if (err != OK) {
+ return Vector<String>();
+ } else if (device.is_empty()) {
+ continue;
+ }
+
+ Vector<String> device_lines = device.split("\n", false);
+ for (const String &line : device_lines) {
+ Vector<String> columns = line.split(":", false, 1);
+ if (columns.size() < 2) {
+ continue;
+ }
+ if (columns[0].strip_edges() == check_column) {
+ // for `column[0] == "Kernel driver in use"` this may contain `nvidia`
+ bool is_valid = true;
+ const String value = columns[1].strip_edges();
+ if (!blacklist.is_empty()) {
+ is_valid = !value.contains(blacklist);
+ }
+ if (is_valid) {
+ values.push_back(value);
+ }
+ break;
+ }
+ }
+ }
+ return values;
+}
+
Error OS_LinuxBSD::shell_open(String p_uri) {
Error ok;
int err_code;
@@ -686,10 +920,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;
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index d5b2321316..aea04c1363 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -67,6 +67,11 @@ class OS_LinuxBSD : public OS_Unix {
MainLoop *main_loop = nullptr;
+ String get_systemd_os_release_info_value(const String &key) const;
+
+ Vector<String> lspci_device_filter(Vector<String> vendor_device_id_mapping, String class_suffix, String check_column, String whitelist) const;
+ Vector<String> lspci_get_device_value(Vector<String> vendor_device_id_mapping, String check_column, String blacklist) const;
+
protected:
virtual void initialize() override;
virtual void finalize() override;
@@ -77,6 +82,10 @@ protected:
public:
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
+
+ virtual Vector<String> get_video_adapter_driver_info() const override;
virtual MainLoop *get_main_loop() const override;