22#include <freerdp/config.h>
31#include <winpr/assert.h>
34#include <freerdp/log.h>
36#define TAG CLIENT_TAG("sdl")
38#include "sdl_monitor.hpp"
39#include "sdl_freerdp.hpp"
41using MONITOR_INFO =
struct
48using VIRTUAL_SCREEN =
struct
53 MONITOR_INFO* monitors;
59int sdl_list_monitors([[maybe_unused]]
SdlContext* sdl)
61 SDL_Init(SDL_INIT_VIDEO);
62 const int nmonitors = SDL_GetNumVideoDisplays();
64 printf(
"listing %d monitors:\n", nmonitors);
65 for (
int i = 0; i < nmonitors; i++)
68 const int brc = SDL_GetDisplayBounds(i, &rect);
69 const char* name = SDL_GetDisplayName(i);
73 printf(
" %s [%d] [%s] %dx%d\t+%d+%d\n", (i == 0) ?
"*" :
" ", i, name, rect.w, rect.h,
81static BOOL sdl_apply_max_size(
SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
84 WINPR_ASSERT(pMaxWidth);
85 WINPR_ASSERT(pMaxHeight);
87 auto settings = sdl->context()->settings;
88 WINPR_ASSERT(settings);
96 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x));
100 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->width);
101 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->height);
106 SDL_GetDisplayUsableBounds(WINPR_ASSERTING_INT_CAST(
int, monitor->orig_screen), &rect);
107 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rect.w);
108 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, rect.h);
113 SDL_GetDisplayUsableBounds(WINPR_ASSERTING_INT_CAST(
int, monitor->orig_screen), &rect);
115 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rect.w);
116 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, rect.h);
119 *pMaxWidth = (WINPR_ASSERTING_INT_CAST(uint32_t, rect.w) *
124 *pMaxHeight = (WINPR_ASSERTING_INT_CAST(uint32_t, rect.h) *
138#if SDL_VERSION_ATLEAST(2, 0, 10)
139static UINT32 sdl_orientaion_to_rdp(SDL_DisplayOrientation orientation)
143 case SDL_ORIENTATION_LANDSCAPE:
144 return ORIENTATION_LANDSCAPE;
145 case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
146 return ORIENTATION_LANDSCAPE_FLIPPED;
147 case SDL_ORIENTATION_PORTRAIT_FLIPPED:
148 return ORIENTATION_PORTRAIT_FLIPPED;
149 case SDL_ORIENTATION_PORTRAIT:
151 return ORIENTATION_PORTRAIT;
156static Uint32 scale(Uint32 val,
float scale)
158 const auto dval =
static_cast<float>(val);
159 const auto sval = dval / scale;
160 return static_cast<Uint32
>(sval);
163static BOOL sdl_apply_display_properties(
SdlContext* sdl)
167 rdpSettings* settings = sdl->context()->settings;
168 WINPR_ASSERT(settings);
175 std::vector<rdpMonitor> monitors;
177 for (UINT32 x = 0; x < numIds; x++)
179 auto id =
static_cast<const int*
>(
180 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, x));
188 if (SDL_GetDisplayBounds(*
id, &rect) < 0)
191 if (SDL_GetDisplayDPI(*
id, &ddpi, &hdpi, &vdpi) < 0)
194 WINPR_ASSERT(rect.w > 0);
195 WINPR_ASSERT(rect.h > 0);
196 WINPR_ASSERT(ddpi > 0);
197 WINPR_ASSERT(hdpi > 0);
198 WINPR_ASSERT(vdpi > 0);
200 bool highDpi = hdpi > 100;
207 const SDL_Rect scaleRect = rect;
208 for (
int i = 0; i < SDL_GetNumDisplayModes(*
id); i++)
210 SDL_DisplayMode mode = {};
211 SDL_GetDisplayMode(WINPR_ASSERTING_INT_CAST(
int, x), i, &mode);
218 else if (mode.w == rect.w)
228 const float dw = 1.0f *
static_cast<float>(rect.w) /
static_cast<float>(scaleRect.w);
229 const float dh = 1.0f *
static_cast<float>(rect.h) /
static_cast<float>(scaleRect.h);
234#if SDL_VERSION_ATLEAST(2, 0, 10)
235 const SDL_DisplayOrientation orientation = SDL_GetDisplayOrientation(*
id);
236 const UINT32 rdp_orientation = sdl_orientaion_to_rdp(orientation);
238 const UINT32 rdp_orientation = ORIENTATION_LANDSCAPE;
244 const auto factor = ddpi / 96.0f * 100.0f;
245 monitor.orig_screen = x;
248 monitor.width = rect.w;
249 monitor.height = rect.h;
250 monitor.is_primary = x == 0;
251 monitor.attributes.desktopScaleFactor =
static_cast<UINT32
>(factor);
252 monitor.attributes.deviceScaleFactor = 100;
253 monitor.attributes.orientation = rdp_orientation;
254 monitor.attributes.physicalWidth = scale(WINPR_ASSERTING_INT_CAST(uint32_t, rect.w), hdpi);
255 monitor.attributes.physicalHeight = scale(WINPR_ASSERTING_INT_CAST(uint32_t, rect.h), vdpi);
256 monitors.emplace_back(monitor);
262static BOOL sdl_detect_single_window(
SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
265 WINPR_ASSERT(pMaxWidth);
266 WINPR_ASSERT(pMaxHeight);
268 rdpSettings* settings = sdl->context()->settings;
269 WINPR_ASSERT(settings);
280 const size_t id = (!sdl->windows.empty())
281 ? WINPR_ASSERTING_INT_CAST(
282 uint32_t, sdl->windows.begin()->second.displayIndex())
299 if (!sdl_apply_display_properties(sdl))
301 return sdl_apply_max_size(sdl, pMaxWidth, pMaxHeight);
306BOOL sdl_detect_monitors(
SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
309 WINPR_ASSERT(pMaxWidth);
310 WINPR_ASSERT(pMaxHeight);
312 rdpSettings* settings = sdl->context()->settings;
313 WINPR_ASSERT(settings);
315 const int numDisplays = SDL_GetNumVideoDisplays();
323 static_cast<size_t>(numDisplays)))
325 for (
size_t x = 0; x < static_cast<size_t>(numDisplays); x++)
327 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_MonitorIds, x, &x))
335 if (nr >
static_cast<UINT32
>(numDisplays))
338 "Found %" PRIu32
" monitor IDs, but only have %" PRIu32
" monitors connected",
343 std::vector<UINT32> used;
344 for (
size_t x = 0; x < nr; x++)
346 auto cur =
static_cast<const UINT32*
>(
347 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, x));
356 "Supplied monitor ID[%" PRIuz
"]=%" PRIu32
" is invalid, only [0-%" PRIu32
363 if (std::find(used.begin(), used.end(),
id) != used.end())
365 WLog_ERR(TAG,
"Duplicate monitor ID[%" PRIuz
"]=%" PRIu32
" detected", x,
id);
368 used.push_back(*cur);
372 if (!sdl_apply_display_properties(sdl))
375 return sdl_detect_single_window(sdl, pMaxWidth, pMaxHeight);
378INT64 sdl_monitor_id_for_index(
SdlContext* sdl, UINT32 index)
381 auto settings = sdl->context()->settings;
390 auto cur =
static_cast<const UINT32*
>(
391 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, index));
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
FREERDP_API BOOL freerdp_settings_set_monitor_def_array_sorted(rdpSettings *settings, const rdpMonitor *monitors, size_t count)
Sort monitor array according to:
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.