22#include <freerdp/config.h>
32#include <winpr/assert.h>
35#include <freerdp/log.h>
37#define TAG CLIENT_TAG("sdl")
39#include "sdl_monitor.hpp"
40#include "sdl_freerdp.hpp"
42using MONITOR_INFO =
struct
49using VIRTUAL_SCREEN =
struct
54 MONITOR_INFO* monitors;
62 SDL_Init(SDL_INIT_VIDEO);
63 const int nmonitors = SDL_GetNumVideoDisplays();
65 printf(
"listing %d monitors:\n", nmonitors);
66 for (
int i = 0; i < nmonitors; i++)
69 const int brc = SDL_GetDisplayBounds(i, &rect);
70 const char* name = SDL_GetDisplayName(i);
74 printf(
" %s [%d] [%s] %dx%d\t+%d+%d\n", (i == 0) ?
"*" :
" ", i, name, rect.w, rect.h,
82static BOOL sdl_apply_max_size(
SdlContext*
sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
85 WINPR_ASSERT(pMaxWidth);
86 WINPR_ASSERT(pMaxHeight);
88 auto settings =
sdl->context()->settings;
89 WINPR_ASSERT(settings);
97 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x));
101 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->width);
102 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->height);
107 SDL_GetDisplayUsableBounds(WINPR_ASSERTING_INT_CAST(
int, monitor->orig_screen), &rect);
108 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rect.w);
109 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, rect.h);
114 SDL_GetDisplayUsableBounds(WINPR_ASSERTING_INT_CAST(
int, monitor->orig_screen), &rect);
116 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rect.w);
117 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, rect.h);
120 *pMaxWidth = (WINPR_ASSERTING_INT_CAST(uint32_t, rect.w) *
125 *pMaxHeight = (WINPR_ASSERTING_INT_CAST(uint32_t, rect.h) *
139#if SDL_VERSION_ATLEAST(2, 0, 10)
140static UINT32 sdl_orientaion_to_rdp(SDL_DisplayOrientation orientation)
144 case SDL_ORIENTATION_LANDSCAPE:
145 return ORIENTATION_LANDSCAPE;
146 case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
147 return ORIENTATION_LANDSCAPE_FLIPPED;
148 case SDL_ORIENTATION_PORTRAIT_FLIPPED:
149 return ORIENTATION_PORTRAIT_FLIPPED;
150 case SDL_ORIENTATION_PORTRAIT:
152 return ORIENTATION_PORTRAIT;
158static Uint32 to_mm(Uint32 pixels,
float dpi)
160 const auto inches =
static_cast<float>(pixels) / dpi;
161 return static_cast<Uint32
>(std::lround(inches * 25.4f));
168 rdpSettings* settings =
sdl->context()->settings;
169 WINPR_ASSERT(settings);
176 std::vector<rdpMonitor> monitors;
178 for (UINT32 x = 0; x < numIds; x++)
180 auto id =
static_cast<const int*
>(
181 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, x));
189 if (SDL_GetDisplayBounds(*
id, &rect) < 0)
192 if (SDL_GetDisplayDPI(*
id, &ddpi, &hdpi, &vdpi) < 0)
195 WINPR_ASSERT(rect.w > 0);
196 WINPR_ASSERT(rect.h > 0);
197 WINPR_ASSERT(ddpi > 0);
198 WINPR_ASSERT(hdpi > 0);
199 WINPR_ASSERT(vdpi > 0);
201 bool highDpi = hdpi > 100;
208 const SDL_Rect scaleRect = rect;
209 for (
int i = 0; i < SDL_GetNumDisplayModes(*
id); i++)
211 SDL_DisplayMode mode = {};
212 SDL_GetDisplayMode(WINPR_ASSERTING_INT_CAST(
int, x), i, &mode);
219 else if (mode.w == rect.w)
229 const float dw = 1.0f *
static_cast<float>(rect.w) /
static_cast<float>(scaleRect.w);
230 const float dh = 1.0f *
static_cast<float>(rect.h) /
static_cast<float>(scaleRect.h);
235#if SDL_VERSION_ATLEAST(2, 0, 10)
236 const SDL_DisplayOrientation orientation = SDL_GetDisplayOrientation(*
id);
237 const UINT32 rdp_orientation = sdl_orientaion_to_rdp(orientation);
239 const UINT32 rdp_orientation = ORIENTATION_LANDSCAPE;
245 const auto factor = ddpi / 96.0f * 100.0f;
246 monitor.orig_screen = x;
249 monitor.width = rect.w;
250 monitor.height = rect.h;
251 monitor.is_primary = x == 0;
252 monitor.attributes.desktopScaleFactor =
static_cast<UINT32
>(factor);
253 monitor.attributes.deviceScaleFactor = 100;
254 monitor.attributes.orientation = rdp_orientation;
255 monitor.attributes.physicalWidth = to_mm(WINPR_ASSERTING_INT_CAST(uint32_t, rect.w), hdpi);
256 monitor.attributes.physicalHeight = to_mm(WINPR_ASSERTING_INT_CAST(uint32_t, rect.h), vdpi);
257 monitors.emplace_back(monitor);
263static BOOL sdl_detect_single_window(
SdlContext*
sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
266 WINPR_ASSERT(pMaxWidth);
267 WINPR_ASSERT(pMaxHeight);
269 rdpSettings* settings =
sdl->context()->settings;
270 WINPR_ASSERT(settings);
281 const size_t id = (!
sdl->windows.empty())
282 ? WINPR_ASSERTING_INT_CAST(
283 uint32_t,
sdl->windows.begin()->second.displayIndex())
300 if (!sdl_apply_display_properties(
sdl))
302 return sdl_apply_max_size(
sdl, pMaxWidth, pMaxHeight);
307BOOL sdl_detect_monitors(
SdlContext*
sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
310 WINPR_ASSERT(pMaxWidth);
311 WINPR_ASSERT(pMaxHeight);
313 rdpSettings* settings =
sdl->context()->settings;
314 WINPR_ASSERT(settings);
316 const int numDisplays = SDL_GetNumVideoDisplays();
324 static_cast<size_t>(numDisplays)))
326 for (
size_t x = 0; x < static_cast<size_t>(numDisplays); x++)
328 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_MonitorIds, x, &x))
336 if (nr >
static_cast<UINT32
>(numDisplays))
338 WLog_ERR(TAG,
"Found %" PRIu32
" monitor IDs, but only have %d monitors connected", nr,
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);
381 auto settings =
sdl->context()->settings;
390 auto cur =
static_cast<const UINT32*
>(
391 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, index));
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD 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.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_monitor_def_array_sorted(rdpSettings *settings, const rdpMonitor *monitors, size_t count)
Sort monitor array according to:
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.