mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-14 00:14:11 +09:00
[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.
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@@ -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<void*>(modes));
|
||||
|
||||
const float dw = 1.0f * static_cast<float>(rect.w) / static_cast<float>(scaleRect.w);
|
||||
const float dh = 1.0f * static_cast<float>(rect.h) / static_cast<float>(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<UINT32>(factor);
|
||||
monitor.attributes.desktopScaleFactor = static_cast<UINT32>(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,10 +19,13 @@
|
||||
*/
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
|
||||
#include "sdl_window.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
|
||||
#include <freerdp/utils/string.h>
|
||||
|
||||
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<UINT32>(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<UINT32>(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<SDL_Window, void (*)(SDL_Window*)> window(createDummy(id), SDL_DestroyWindow);
|
||||
if (!window)
|
||||
return {};
|
||||
|
||||
std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer*)> 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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user