diff options
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r-- | platform/linuxbsd/freedesktop_portal_desktop.cpp | 5 | ||||
-rw-r--r-- | platform/linuxbsd/freedesktop_screensaver.cpp | 5 | ||||
-rw-r--r-- | platform/linuxbsd/joypad_linux.cpp | 48 | ||||
-rw-r--r-- | platform/linuxbsd/os_linuxbsd.cpp | 44 | ||||
-rw-r--r-- | platform/linuxbsd/os_linuxbsd.h | 3 | ||||
-rw-r--r-- | platform/linuxbsd/x11/detect_prime_x11.cpp | 3 | ||||
-rw-r--r-- | platform/linuxbsd/x11/display_server_x11.cpp | 126 | ||||
-rw-r--r-- | platform/linuxbsd/x11/display_server_x11.h | 6 | ||||
-rw-r--r-- | platform/linuxbsd/x11/gl_manager_x11.cpp | 3 |
9 files changed, 218 insertions, 25 deletions
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp index b45b7e676d..6dfa8ed93c 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.cpp +++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp @@ -138,6 +138,11 @@ FreeDesktopPortalDesktop::FreeDesktopPortalDesktop() { #else unsupported = false; #endif + + if (unsupported) { + return; + } + bool ver_ok = false; int version_major = 0; int version_minor = 0; diff --git a/platform/linuxbsd/freedesktop_screensaver.cpp b/platform/linuxbsd/freedesktop_screensaver.cpp index 78f2337599..cf179b5735 100644 --- a/platform/linuxbsd/freedesktop_screensaver.cpp +++ b/platform/linuxbsd/freedesktop_screensaver.cpp @@ -141,6 +141,11 @@ FreeDesktopScreenSaver::FreeDesktopScreenSaver() { #else unsupported = false; #endif + + if (unsupported) { + return; + } + bool ver_ok = false; int version_major = 0; int version_minor = 0; diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index 5c623b8ba2..a9725fff2e 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -32,6 +32,8 @@ #include "joypad_linux.h" +#include "core/os/os.h" + #include <dirent.h> #include <errno.h> #include <fcntl.h> @@ -72,6 +74,26 @@ void JoypadLinux::Joypad::reset() { events.clear(); } +// This function is derived from SDL: +// https://github.com/libsdl-org/SDL/blob/main/src/core/linux/SDL_sandbox.c#L28-L45 +static bool detect_sandbox() { + if (access("/.flatpak-info", F_OK) == 0) { + return true; + } + + // For Snap, we check multiple variables because they might be set for + // unrelated reasons. This is the same thing WebKitGTK does. + if (OS::get_singleton()->has_environment("SNAP") && OS::get_singleton()->has_environment("SNAP_NAME") && OS::get_singleton()->has_environment("SNAP_REVISION")) { + return true; + } + + if (access("/run/host/container-manager", F_OK) == 0) { + return true; + } + + return false; +} + JoypadLinux::JoypadLinux(Input *in) { #ifdef UDEV_ENABLED #ifdef SOWRAP_ENABLED @@ -80,17 +102,25 @@ JoypadLinux::JoypadLinux(Input *in) { #else int dylibloader_verbose = 0; #endif - use_udev = initialize_libudev(dylibloader_verbose) == 0; - if (use_udev) { - if (!udev_new || !udev_unref || !udev_enumerate_new || !udev_enumerate_add_match_subsystem || !udev_enumerate_scan_devices || !udev_enumerate_get_list_entry || !udev_list_entry_get_next || !udev_list_entry_get_name || !udev_device_new_from_syspath || !udev_device_get_devnode || !udev_device_get_action || !udev_device_unref || !udev_enumerate_unref || !udev_monitor_new_from_netlink || !udev_monitor_filter_add_match_subsystem_devtype || !udev_monitor_enable_receiving || !udev_monitor_get_fd || !udev_monitor_receive_device || !udev_monitor_unref) { - // There's no API to check version, check if functions are available instead. - use_udev = false; - print_verbose("JoypadLinux: Unsupported udev library version!"); + if (detect_sandbox()) { + // Linux binaries in sandboxes / containers need special handling because + // libudev doesn't work there. So we need to fallback to manual parsing + // of /dev/input in such case. + use_udev = false; + print_verbose("JoypadLinux: udev enabled, but detected incompatible sandboxed mode. Falling back to /dev/input to detect joypads."); + } else { + use_udev = initialize_libudev(dylibloader_verbose) == 0; + if (use_udev) { + if (!udev_new || !udev_unref || !udev_enumerate_new || !udev_enumerate_add_match_subsystem || !udev_enumerate_scan_devices || !udev_enumerate_get_list_entry || !udev_list_entry_get_next || !udev_list_entry_get_name || !udev_device_new_from_syspath || !udev_device_get_devnode || !udev_device_get_action || !udev_device_unref || !udev_enumerate_unref || !udev_monitor_new_from_netlink || !udev_monitor_filter_add_match_subsystem_devtype || !udev_monitor_enable_receiving || !udev_monitor_get_fd || !udev_monitor_receive_device || !udev_monitor_unref) { + // There's no API to check version, check if functions are available instead. + use_udev = false; + print_verbose("JoypadLinux: Unsupported udev library version!"); + } else { + print_verbose("JoypadLinux: udev enabled and loaded successfully."); + } } else { - print_verbose("JoypadLinux: udev enabled and loaded successfully."); + print_verbose("JoypadLinux: udev enabled, but couldn't be loaded. Falling back to /dev/input to detect joypads."); } - } else { - print_verbose("JoypadLinux: udev enabled, but couldn't be loaded. Falling back to /dev/input to detect joypads."); } #endif #else diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index 11c81be4a9..8d8c8ce27b 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -30,6 +30,7 @@ #include "os_linuxbsd.h" +#include "core/io/certs_compressed.gen.h" #include "core/io/dir_access.h" #include "main/main.h" #include "servers/display_server.h" @@ -195,6 +196,10 @@ void OS_LinuxBSD::set_main_loop(MainLoop *p_main_loop) { main_loop = p_main_loop; } +String OS_LinuxBSD::get_identifier() const { + return "linuxbsd"; +} + String OS_LinuxBSD::get_name() const { #ifdef __linux__ return "Linux"; @@ -490,6 +495,11 @@ bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) { return true; } + // Match against the specific OS (linux, freebsd, etc). + if (p_feature == get_name().to_lower()) { + return true; + } + return false; } @@ -1076,6 +1086,40 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) { return OK; } +String OS_LinuxBSD::get_system_ca_certificates() { + String certfile; + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + + // Compile time preferred certificates path. + if (!String(_SYSTEM_CERTS_PATH).is_empty() && da->file_exists(_SYSTEM_CERTS_PATH)) { + certfile = _SYSTEM_CERTS_PATH; + } else if (da->file_exists("/etc/ssl/certs/ca-certificates.crt")) { + // Debian/Ubuntu + certfile = "/etc/ssl/certs/ca-certificates.crt"; + } else if (da->file_exists("/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem")) { + // Fedora + certfile = "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem"; + } else if (da->file_exists("/etc/ca-certificates/extracted/tls-ca-bundle.pem")) { + // Arch Linux + certfile = "/etc/ca-certificates/extracted/tls-ca-bundle.pem"; + } else if (da->file_exists("/var/lib/ca-certificates/ca-bundle.pem")) { + // openSUSE + certfile = "/var/lib/ca-certificates/ca-bundle.pem"; + } else if (da->file_exists("/etc/ssl/cert.pem")) { + // FreeBSD/OpenBSD + certfile = "/etc/ssl/cert.pem"; + } + + if (certfile.is_empty()) { + return ""; + } + + Ref<FileAccess> f = FileAccess::open(certfile, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), "", vformat("Failed to open system CA certificates file: '%s'", certfile)); + + return f->get_as_text(); +} + OS_LinuxBSD::OS_LinuxBSD() { main_loop = nullptr; diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h index 9423514944..c1e735b0d4 100644 --- a/platform/linuxbsd/os_linuxbsd.h +++ b/platform/linuxbsd/os_linuxbsd.h @@ -96,6 +96,7 @@ protected: virtual void set_main_loop(MainLoop *p_main_loop) override; public: + virtual String get_identifier() const override; virtual String get_name() const override; virtual String get_distribution_name() const override; virtual String get_version() const override; @@ -132,6 +133,8 @@ public: virtual Error move_to_trash(const String &p_path) override; + virtual String get_system_ca_certificates() override; + OS_LinuxBSD(); ~OS_LinuxBSD(); }; diff --git a/platform/linuxbsd/x11/detect_prime_x11.cpp b/platform/linuxbsd/x11/detect_prime_x11.cpp index 3d07be1c76..78778a8b56 100644 --- a/platform/linuxbsd/x11/detect_prime_x11.cpp +++ b/platform/linuxbsd/x11/detect_prime_x11.cpp @@ -60,6 +60,9 @@ typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *); +// To prevent shadowing warnings +#undef glGetString + struct vendor { const char *glxvendor = nullptr; int priority = 0; diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index ac4fbe2068..9506189573 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -186,6 +186,7 @@ bool DisplayServerX11::_refresh_device_info() { xi.absolute_devices.clear(); xi.touch_devices.clear(); xi.pen_inverted_devices.clear(); + xi.last_relative_time = 0; int dev_count; XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count); @@ -1205,6 +1206,105 @@ Color DisplayServerX11::screen_get_pixel(const Point2i &p_position) const { return Color(); } +Ref<Image> DisplayServerX11::screen_get_image(int p_screen) const { + ERR_FAIL_INDEX_V(p_screen, get_screen_count(), Ref<Image>()); + + switch (p_screen) { + case SCREEN_PRIMARY: { + p_screen = get_primary_screen(); + } break; + case SCREEN_OF_MAIN_WINDOW: { + p_screen = window_get_current_screen(MAIN_WINDOW_ID); + } break; + default: + break; + } + + ERR_FAIL_COND_V(p_screen < 0, Ref<Image>()); + + XImage *image = nullptr; + + int event_base, error_base; + if (XineramaQueryExtension(x11_display, &event_base, &error_base)) { + int xin_count; + XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &xin_count); + if (p_screen < xin_count) { + int x_count = XScreenCount(x11_display); + for (int i = 0; i < x_count; i++) { + Window root = XRootWindow(x11_display, i); + XWindowAttributes root_attrs; + XGetWindowAttributes(x11_display, root, &root_attrs); + if ((xsi[p_screen].x_org >= root_attrs.x) && (xsi[p_screen].x_org <= root_attrs.x + root_attrs.width) && (xsi[p_screen].y_org >= root_attrs.y) && (xsi[p_screen].y_org <= root_attrs.y + root_attrs.height)) { + image = XGetImage(x11_display, root, xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height, AllPlanes, ZPixmap); + break; + } + } + } else { + ERR_FAIL_V_MSG(Ref<Image>(), "Invalid screen index: " + itos(p_screen) + "(count: " + itos(xin_count) + ")."); + } + } else { + int x_count = XScreenCount(x11_display); + if (p_screen < x_count) { + Window root = XRootWindow(x11_display, p_screen); + + XWindowAttributes root_attrs; + XGetWindowAttributes(x11_display, root, &root_attrs); + + image = XGetImage(x11_display, root, root_attrs.x, root_attrs.y, root_attrs.width, root_attrs.height, AllPlanes, ZPixmap); + } else { + ERR_FAIL_V_MSG(Ref<Image>(), "Invalid screen index: " + itos(p_screen) + "(count: " + itos(x_count) + ")."); + } + } + + Ref<Image> img; + if (image) { + int width = image->width; + int height = image->height; + + Vector<uint8_t> img_data; + img_data.resize(height * width * 4); + + uint8_t *sr = (uint8_t *)image->data; + uint8_t *wr = (uint8_t *)img_data.ptrw(); + + if (image->bits_per_pixel == 24 && image->red_mask == 0xff0000 && image->green_mask == 0x00ff00 && image->blue_mask == 0x0000ff) { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + wr[(y * width + x) * 4 + 0] = sr[(y * width + x) * 3 + 2]; + wr[(y * width + x) * 4 + 1] = sr[(y * width + x) * 3 + 1]; + wr[(y * width + x) * 4 + 2] = sr[(y * width + x) * 3 + 0]; + wr[(y * width + x) * 4 + 3] = 255; + } + } + } else if (image->bits_per_pixel == 24 && image->red_mask == 0x0000ff && image->green_mask == 0x00ff00 && image->blue_mask == 0xff0000) { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + wr[(y * width + x) * 4 + 0] = sr[(y * width + x) * 3 + 2]; + wr[(y * width + x) * 4 + 1] = sr[(y * width + x) * 3 + 1]; + wr[(y * width + x) * 4 + 2] = sr[(y * width + x) * 3 + 0]; + wr[(y * width + x) * 4 + 3] = 255; + } + } + } else if (image->bits_per_pixel == 32 && image->red_mask == 0xff0000 && image->green_mask == 0x00ff00 && image->blue_mask == 0x0000ff) { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + wr[(y * width + x) * 4 + 0] = sr[(y * width + x) * 4 + 2]; + wr[(y * width + x) * 4 + 1] = sr[(y * width + x) * 4 + 1]; + wr[(y * width + x) * 4 + 2] = sr[(y * width + x) * 4 + 0]; + wr[(y * width + x) * 4 + 3] = 255; + } + } + } else { + XFree(image); + ERR_FAIL_V_MSG(Ref<Image>(), vformat("XImage with RGB mask %x %x %x and depth %d is not supported.", image->red_mask, image->green_mask, image->blue_mask, image->bits_per_pixel)); + } + img = Image::create_from_data(width, height, false, Image::FORMAT_RGBA8, img_data); + XFree(image); + } + + return img; +} + float DisplayServerX11::screen_get_refresh_rate(int p_screen) const { _THREAD_SAFE_METHOD_ @@ -2724,8 +2824,8 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu XcursorImageDestroy(cursor_image); } else { // Reset to default system cursor - if (img[p_shape]) { - cursors[p_shape] = XcursorImageLoadCursor(x11_display, img[p_shape]); + if (cursor_img[p_shape]) { + cursors[p_shape] = XcursorImageLoadCursor(x11_display, cursor_img[p_shape]); } CursorShape c = current_cursor; @@ -3497,8 +3597,8 @@ void DisplayServerX11::_window_changed(XEvent *event) { // 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"); + wd.maximized = _window_maximize_check(window_id, "_NET_WM_STATE") && !wd.fullscreen; + wd.minimized = _window_minimize_check(window_id) && !wd.fullscreen && !wd.maximized; // Readjusting the window position if the window is being reparented by the window manager for decoration Window root, parent, *children; @@ -5359,7 +5459,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode for (int i = 0; i < CURSOR_MAX; i++) { cursors[i] = None; - img[i] = nullptr; + cursor_img[i] = nullptr; } XInitThreads(); //always use threads @@ -5716,8 +5816,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode "question_arrow" }; - img[i] = XcursorLibraryLoadImage(cursor_file[i], cursor_theme, cursor_size); - if (!img[i]) { + cursor_img[i] = XcursorLibraryLoadImage(cursor_file[i], cursor_theme, cursor_size); + if (!cursor_img[i]) { const char *fallback = nullptr; switch (i) { @@ -5755,7 +5855,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode fallback = "bd_double_arrow"; break; case CURSOR_MOVE: - img[i] = img[CURSOR_DRAG]; + cursor_img[i] = cursor_img[CURSOR_DRAG]; break; case CURSOR_VSPLIT: fallback = "sb_v_double_arrow"; @@ -5768,11 +5868,11 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode break; } if (fallback != nullptr) { - img[i] = XcursorLibraryLoadImage(fallback, cursor_theme, cursor_size); + cursor_img[i] = XcursorLibraryLoadImage(fallback, cursor_theme, cursor_size); } } - if (img[i]) { - cursors[i] = XcursorImageLoadCursor(x11_display, img[i]); + if (cursor_img[i]) { + cursors[i] = XcursorImageLoadCursor(x11_display, cursor_img[i]); } else { print_verbose("Failed loading custom cursor: " + String(cursor_file[i])); } @@ -5911,8 +6011,8 @@ DisplayServerX11::~DisplayServerX11() { if (cursors[i] != None) { XFreeCursor(x11_display, cursors[i]); } - if (img[i] != nullptr) { - XcursorImageDestroy(img[i]); + if (cursor_img[i] != nullptr) { + XcursorImageDestroy(cursor_img[i]); } } diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index e8e0680c14..fd3a5dccfa 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -119,8 +119,7 @@ typedef struct _xrr_monitor_info { #undef CursorShape class DisplayServerX11 : public DisplayServer { - //No need to register, it's platform-specific and nothing is added - //GDCLASS(DisplayServerX11, DisplayServer) + // No need to register with GDCLASS, it's platform-specific and nothing is added. _THREAD_SAFE_CLASS_ @@ -307,7 +306,7 @@ class DisplayServerX11 : public DisplayServer { const char *cursor_theme = nullptr; int cursor_size = 0; - XcursorImage *img[CURSOR_MAX]; + XcursorImage *cursor_img[CURSOR_MAX]; Cursor cursors[CURSOR_MAX]; Cursor null_cursor; CursorShape current_cursor = CURSOR_ARROW; @@ -413,6 +412,7 @@ public: 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 Color screen_get_pixel(const Point2i &p_position) const override; + virtual Ref<Image> screen_get_image(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/x11/gl_manager_x11.cpp b/platform/linuxbsd/x11/gl_manager_x11.cpp index ee767dfa80..1e579c9f01 100644 --- a/platform/linuxbsd/x11/gl_manager_x11.cpp +++ b/platform/linuxbsd/x11/gl_manager_x11.cpp @@ -44,6 +44,9 @@ typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *); +// To prevent shadowing warnings +#undef glXCreateContextAttribsARB + struct GLManager_X11_Private { ::GLXContext glx_context; }; |