From efa15e1dc2a18b2e1441886eb0683a1854de38d8 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 29 Jan 2026 19:51:04 +0100 Subject: [PATCH] [client,sdl] implement a static SdlWindow::query function The display settings can not be proplerly queried by SDL without a window. Create a temporary, invisible window for a requested monitor and query the required details from that window. --- client/SDL/SDL3/sdl_monitor.cpp | 57 +++-------- client/SDL/SDL3/sdl_window.cpp | 170 +++++++++++++++++++++++--------- client/SDL/SDL3/sdl_window.hpp | 7 ++ 3 files changed, 140 insertions(+), 94 deletions(-) diff --git a/client/SDL/SDL3/sdl_monitor.cpp b/client/SDL/SDL3/sdl_monitor.cpp index 9b8b78031..7fbab74e1 100644 --- a/client/SDL/SDL3/sdl_monitor.cpp +++ b/client/SDL/SDL3/sdl_monitor.cpp @@ -21,6 +21,7 @@ #include +#include #include #include #include @@ -181,10 +182,12 @@ int sdl_list_monitors([[maybe_unused]] SdlContext* sdl) [[nodiscard]] static BOOL sdl_apply_monitor_properties(rdpMonitor& monitor, SDL_DisplayID id, bool isPrimary) { + auto mode = SDL_GetCurrentDisplayMode(id); + if (!mode) + return FALSE; - float dpi = SDL_GetDisplayContentScale(id); - float hdpi = dpi; - float vdpi = dpi; + const float dpi = roundf(mode->pixel_density * 100.0f); + const float factor = mode->pixel_density; SDL_Rect rect = {}; if (!SDL_GetDisplayBounds(id, &rect)) @@ -195,58 +198,20 @@ int sdl_list_monitors([[maybe_unused]] SdlContext* sdl) bool highDpi = dpi > 100; - if (highDpi) - { - // HighDPI is problematic with SDL: We can only get native resolution by creating a - // window. Work around this by checking the supported resolutions (and keep maximum) - // Also scale the DPI - const SDL_Rect scaleRect = rect; - int count = 0; - auto modes = SDL_GetFullscreenDisplayModes(id, &count); - for (int i = 0; i < count; i++) - { - auto mode = modes[i]; - if (!mode) - break; - - if (mode->w > rect.w) - { - rect.w = mode->w; - rect.h = mode->h; - } - else if (mode->w == rect.w) - { - if (mode->h > rect.h) - { - rect.w = mode->w; - rect.h = mode->h; - } - } - } - SDL_free(static_cast(modes)); - - const float dw = 1.0f * static_cast(rect.w) / static_cast(scaleRect.w); - const float dh = 1.0f * static_cast(rect.h) / static_cast(scaleRect.h); - hdpi /= dw; - vdpi /= dh; - } - const SDL_DisplayOrientation orientation = SDL_GetCurrentDisplayOrientation(id); const UINT32 rdp_orientation = sdl::utils::orientaion_to_rdp(orientation); - /* windows uses 96 dpi as 'default' and the scale factors are in percent. */ - const auto factor = dpi / 96.0f * 100.0f; monitor.orig_screen = id; monitor.x = rect.x; monitor.y = rect.y; - monitor.width = rect.w; - monitor.height = rect.h; + monitor.width = roundf(rect.w * factor); + monitor.height = roundf(rect.h * factor); monitor.is_primary = isPrimary; - monitor.attributes.desktopScaleFactor = static_cast(factor); + monitor.attributes.desktopScaleFactor = static_cast(dpi); monitor.attributes.deviceScaleFactor = 100; monitor.attributes.orientation = rdp_orientation; - monitor.attributes.physicalWidth = scale(WINPR_ASSERTING_INT_CAST(uint32_t, rect.w), hdpi); - monitor.attributes.physicalHeight = scale(WINPR_ASSERTING_INT_CAST(uint32_t, rect.h), vdpi); + monitor.attributes.physicalWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rect.w); + monitor.attributes.physicalHeight = WINPR_ASSERTING_INT_CAST(uint32_t, rect.h); return TRUE; } diff --git a/client/SDL/SDL3/sdl_window.cpp b/client/SDL/SDL3/sdl_window.cpp index 0bed3e3fe..2f1e09ef3 100644 --- a/client/SDL/SDL3/sdl_window.cpp +++ b/client/SDL/SDL3/sdl_window.cpp @@ -19,10 +19,13 @@ */ #include #include +#include #include "sdl_window.hpp" #include "sdl_utils.hpp" +#include + SdlWindow::SdlWindow(SDL_DisplayID id, const std::string& title, const SDL_Rect& rect, [[maybe_unused]] Uint32 flags) : _displayID(id) @@ -83,13 +86,7 @@ SDL_DisplayID SdlWindow::displayIndex() const SDL_Rect SdlWindow::rect() const { - SDL_Rect rect = {}; - if (_window) - { - SDL_GetWindowPosition(_window, &rect.x, &rect.y); - SDL_GetWindowSizeInPixels(_window, &rect.w, &rect.h); - } - return rect; + return rect(_window); } SDL_Rect SdlWindow::bounds() const @@ -97,8 +94,10 @@ SDL_Rect SdlWindow::bounds() const SDL_Rect rect = {}; if (_window) { - SDL_GetWindowPosition(_window, &rect.x, &rect.y); - SDL_GetWindowSize(_window, &rect.w, &rect.h); + if (!SDL_GetWindowPosition(_window, &rect.x, &rect.y)) + return {}; + if (!SDL_GetWindowSize(_window, &rect.w, &rect.h)) + return {}; } return rect; } @@ -130,42 +129,7 @@ Sint32 SdlWindow::offsetY() const rdpMonitor SdlWindow::monitor(bool isPrimary) const { - rdpMonitor mon{}; - - const auto factor = scale(); - const auto dsf = static_cast(100 * factor); - mon.attributes.desktopScaleFactor = dsf; - mon.attributes.deviceScaleFactor = 100; - - const auto r = rect(); - mon.width = r.w; - mon.height = r.h; - - mon.attributes.physicalWidth = WINPR_ASSERTING_INT_CAST(uint32_t, r.w); - mon.attributes.physicalHeight = WINPR_ASSERTING_INT_CAST(uint32_t, r.h); - - SDL_Rect rect = {}; - auto did = SDL_GetDisplayForWindow(_window); - auto rc = SDL_GetDisplayBounds(did, &rect); - - if (rc) - { - mon.x = rect.x; - mon.y = rect.y; - } - - const auto orient = orientation(); - mon.attributes.orientation = sdl::utils::orientaion_to_rdp(orient); - - auto primary = SDL_GetPrimaryDisplay(); - mon.is_primary = isPrimary || (SDL_GetWindowID(_window) == primary); - mon.orig_screen = did; - if (mon.is_primary) - { - mon.x = 0; - mon.y = 0; - } - return mon; + return query(_window, displayIndex(), isPrimary); } float SdlWindow::scale() const @@ -291,14 +255,79 @@ bool SdlWindow::drawScaledRects(SDL_Surface* surface, const SDL_FPoint& scale, bool SdlWindow::fill(Uint8 r, Uint8 g, Uint8 b, Uint8 a) { - auto surface = SDL_GetWindowSurface(_window); + return fill(_window, r, g, b, a); +} + +bool SdlWindow::fill(SDL_Window* window, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + auto surface = SDL_GetWindowSurface(window); if (!surface) return false; SDL_Rect rect = { 0, 0, surface->w, surface->h }; auto color = SDL_MapSurfaceRGBA(surface, r, g, b, a); - SDL_FillSurfaceRect(surface, &rect, color); - return true; + return SDL_FillSurfaceRect(surface, &rect, color); +} + +rdpMonitor SdlWindow::query(SDL_Window* window, SDL_DisplayID id, bool forceAsPrimary) +{ + if (!window) + return {}; + + const auto& r = rect(window); + const float factor = SDL_GetWindowDisplayScale(window); + const float dpi = std::roundf(factor * 100.0f); + + WINPR_ASSERT(r.w > 0); + WINPR_ASSERT(r.h > 0); + + bool highDpi = dpi > 100; + + const auto primary = SDL_GetPrimaryDisplay(); + const auto orientation = SDL_GetCurrentDisplayOrientation(id); + const auto rdp_orientation = sdl::utils::orientaion_to_rdp(orientation); + + rdpMonitor monitor{}; + monitor.orig_screen = id; + monitor.x = forceAsPrimary ? 0 : r.x; + monitor.y = forceAsPrimary ? 0 : r.y; + monitor.width = r.w; + monitor.height = r.h; + monitor.is_primary = forceAsPrimary || (id == primary); + monitor.attributes.desktopScaleFactor = static_cast(dpi); + monitor.attributes.deviceScaleFactor = 100; + monitor.attributes.orientation = rdp_orientation; + monitor.attributes.physicalWidth = WINPR_ASSERTING_INT_CAST(uint32_t, r.w); + monitor.attributes.physicalHeight = WINPR_ASSERTING_INT_CAST(uint32_t, r.h); + + SDL_Log("monitor.orig_screen %" PRIu32, monitor.orig_screen); + SDL_Log("monitor.x %" PRId32, monitor.x); + SDL_Log("monitor.y %" PRId32, monitor.y); + SDL_Log("monitor.width %" PRId32, monitor.width); + SDL_Log("monitor.height %" PRId32, monitor.height); + SDL_Log("monitor.is_primary %" PRIu32, monitor.is_primary); + SDL_Log("monitor.attributes.desktopScaleFactor %" PRIu32, + monitor.attributes.desktopScaleFactor); + SDL_Log("monitor.attributes.deviceScaleFactor %" PRIu32, monitor.attributes.deviceScaleFactor); + SDL_Log("monitor.attributes.orientation %s", + freerdp_desktop_rotation_flags_to_string(monitor.attributes.orientation)); + SDL_Log("monitor.attributes.physicalWidth %" PRIu32, monitor.attributes.physicalWidth); + SDL_Log("monitor.attributes.physicalHeight %" PRIu32, monitor.attributes.physicalHeight); + return monitor; +} + +SDL_Rect SdlWindow::rect(SDL_Window* window) +{ + SDL_Rect rect = {}; + if (!window) + return {}; + + if (!SDL_GetWindowPosition(window, &rect.x, &rect.y)) + return {}; + if (!SDL_GetWindowSizeInPixels(window, &rect.w, &rect.h)) + return {}; + + return rect; } bool SdlWindow::blit(SDL_Surface* surface, const SDL_Rect& srcRect, SDL_Rect& dstRect) @@ -347,3 +376,48 @@ SdlWindow SdlWindow::create(SDL_DisplayID id, const std::string& title, Uint32 f return window; } + +static SDL_Window* createDummy(SDL_DisplayID id) +{ + const auto x = SDL_WINDOWPOS_CENTERED_DISPLAY(id); + const auto y = SDL_WINDOWPOS_CENTERED_DISPLAY(id); + const int w = 64; + const int h = 64; + + auto props = SDL_CreateProperties(); + std::stringstream ss; + ss << "SdlWindow::query(" << id << ")"; + SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, ss.str().c_str()); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, x); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, y); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, w); + SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, h); + + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, true); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN, false); + + auto window = SDL_CreateWindowWithProperties(props); + SDL_DestroyProperties(props); + return window; +} + +rdpMonitor SdlWindow::query(SDL_DisplayID id, bool forceAsPrimary) +{ + std::unique_ptr window(createDummy(id), SDL_DestroyWindow); + if (!window) + return {}; + + std::unique_ptr renderer( + SDL_CreateRenderer(window.get(), nullptr), SDL_DestroyRenderer); + + if (!SDL_SyncWindow(window.get())) + return {}; + + SDL_Event event{}; + while (SDL_PollEvent(&event)) + ; + + return query(window.get(), id, forceAsPrimary); +} diff --git a/client/SDL/SDL3/sdl_window.hpp b/client/SDL/SDL3/sdl_window.hpp index 303e2a9b3..9a69d4618 100644 --- a/client/SDL/SDL3/sdl_window.hpp +++ b/client/SDL/SDL3/sdl_window.hpp @@ -31,6 +31,7 @@ class SdlWindow public: [[nodiscard]] static SdlWindow create(SDL_DisplayID id, const std::string& title, Uint32 flags, Uint32 width = 0, Uint32 height = 0); + [[nodiscard]] static rdpMonitor query(SDL_DisplayID id, bool forceAsPrimary = false); SdlWindow(SdlWindow&& other) noexcept; SdlWindow(const SdlWindow& other) = delete; @@ -82,6 +83,12 @@ class SdlWindow protected: SdlWindow(SDL_DisplayID id, const std::string& title, const SDL_Rect& rect, Uint32 flags); + [[nodiscard]] static bool fill(SDL_Window* window, Uint8 r = 0x00, Uint8 g = 0x00, + Uint8 b = 0x00, Uint8 a = 0xff); + [[nodiscard]] static rdpMonitor query(SDL_Window* window, SDL_DisplayID id, + bool forceAsPrimary = false); + [[nodiscard]] static SDL_Rect rect(SDL_Window* window); + private: SDL_Window* _window = nullptr; SDL_DisplayID _displayID = 0;