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"
53 MONITOR_INFO* monitors;
59int sdl_list_monitors([[maybe_unused]]
SdlContext* sdl)
61 SDL_Init(SDL_INIT_VIDEO);
64 auto ids = SDL_GetDisplays(&nmonitors);
66 printf(
"listing %d monitors:\n", nmonitors);
67 for (
int i = 0; i < nmonitors; i++)
71 const auto brc = SDL_GetDisplayBounds(
id, &rect);
72 const char* name = SDL_GetDisplayName(
id);
76 printf(
" %s [%u] [%s] %dx%d\t+%d+%d\n", (i == 0) ?
"*" :
" ", id, name, rect.w, rect.h,
84static BOOL sdl_apply_mon_max_size(
SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
91 WINPR_ASSERT(pMaxWidth);
92 WINPR_ASSERT(pMaxHeight);
94 auto settings = sdl->context()->settings;
95 WINPR_ASSERT(settings);
100 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x));
102 left = std::min(monitor->x, left);
103 top = std::min(monitor->y, top);
104 right = std::max(monitor->x + monitor->width, right);
105 bottom = std::max(monitor->y + monitor->height, bottom);
108 const int32_t w = right - left;
109 const int32_t h = bottom - top;
111 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, w);
112 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, h);
116static BOOL sdl_apply_max_size(
SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
119 WINPR_ASSERT(pMaxWidth);
120 WINPR_ASSERT(pMaxHeight);
122 auto settings = sdl->context()->settings;
123 WINPR_ASSERT(settings);
130 auto monitor =
static_cast<const rdpMonitor*
>(
131 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x));
135 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->width);
136 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->height);
141 SDL_GetDisplayUsableBounds(monitor->orig_screen, &rect);
142 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rect.w);
143 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, rect.h);
148 SDL_GetDisplayUsableBounds(monitor->orig_screen, &rect);
150 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rect.w);
151 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, rect.h);
154 *pMaxWidth = (WINPR_ASSERTING_INT_CAST(uint32_t, rect.w) *
159 *pMaxHeight = (WINPR_ASSERTING_INT_CAST(uint32_t, rect.h) *
173static Uint32 scale(Uint32 val,
float scale)
175 const auto dval =
static_cast<float>(val);
176 const auto sval = dval / scale;
177 return static_cast<Uint32
>(sval);
180static BOOL sdl_apply_monitor_properties(
rdpMonitor& monitor, SDL_DisplayID
id,
bool isPrimary)
183 float dpi = SDL_GetDisplayContentScale(
id);
188 if (!SDL_GetDisplayBounds(
id, &rect))
191 WINPR_ASSERT(rect.w > 0);
192 WINPR_ASSERT(rect.h > 0);
194 bool highDpi = dpi > 100;
201 const SDL_Rect scaleRect = rect;
203 auto modes = SDL_GetFullscreenDisplayModes(
id, &count);
204 for (
int i = 0; i < count; i++)
206 auto mode = modes[i];
210 if (mode->w > rect.w)
215 else if (mode->w == rect.w)
217 if (mode->h > rect.h)
224 SDL_free(
static_cast<void*
>(modes));
226 const float dw = 1.0f *
static_cast<float>(rect.w) /
static_cast<float>(scaleRect.w);
227 const float dh = 1.0f *
static_cast<float>(rect.h) /
static_cast<float>(scaleRect.h);
232 const SDL_DisplayOrientation orientation = SDL_GetCurrentDisplayOrientation(
id);
233 const UINT32 rdp_orientation = sdl::utils::orientaion_to_rdp(orientation);
236 const auto factor = dpi / 96.0f * 100.0f;
237 monitor.orig_screen = id;
240 monitor.width = rect.w;
241 monitor.height = rect.h;
242 monitor.is_primary = isPrimary;
243 monitor.attributes.desktopScaleFactor =
static_cast<UINT32
>(factor);
244 monitor.attributes.deviceScaleFactor = 100;
245 monitor.attributes.orientation = rdp_orientation;
246 monitor.attributes.physicalWidth = scale(WINPR_ASSERTING_INT_CAST(uint32_t, rect.w), hdpi);
247 monitor.attributes.physicalHeight = scale(WINPR_ASSERTING_INT_CAST(uint32_t, rect.h), vdpi);
251static BOOL sdl_apply_display_properties(
SdlContext* sdl)
255 rdpSettings* settings = sdl->context()->settings;
256 WINPR_ASSERT(settings);
258 std::vector<rdpMonitor> monitors;
264 if (sdl->monitorIds().empty())
266 const auto id = sdl->monitorIds().front();
268 if (!sdl_apply_monitor_properties(monitor,
id, TRUE))
270 monitors.emplace_back(monitor);
276 for (
const auto&
id : sdl->monitorIds())
279 const auto primary = SDL_GetPrimaryDisplay();
280 if (!sdl_apply_monitor_properties(monitor,
id,
id == primary))
282 monitors.emplace_back(monitor);
288static BOOL sdl_detect_single_window(
SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
291 WINPR_ASSERT(pMaxWidth);
292 WINPR_ASSERT(pMaxHeight);
294 rdpSettings* settings = sdl->context()->settings;
295 WINPR_ASSERT(settings);
306 SDL_DisplayID
id = 0;
307 const auto& ids = sdl->monitorIds();
312 sdl->setMonitorIds({
id });
316 if (!sdl_apply_display_properties(sdl))
318 return sdl_apply_max_size(sdl, pMaxWidth, pMaxHeight);
320 return sdl_apply_mon_max_size(sdl, pMaxWidth, pMaxHeight);
323BOOL sdl_detect_monitors(
SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
326 WINPR_ASSERT(pMaxWidth);
327 WINPR_ASSERT(pMaxHeight);
329 rdpSettings* settings = sdl->context()->settings;
330 WINPR_ASSERT(settings);
332 std::vector<SDL_DisplayID> ids;
335 auto sids = SDL_GetDisplays(&numDisplays);
336 if (sids && (numDisplays > 0))
337 ids = std::vector<SDL_DisplayID>(sids, sids + numDisplays);
347 sdl->setMonitorIds(ids);
350 sdl->setMonitorIds({ ids.front() });
359 "Found %" PRIu32
" monitor IDs, but only have %" PRIuz
" monitors connected",
364 std::vector<SDL_DisplayID> used;
365 for (
size_t x = 0; x < nr; x++)
367 auto cur =
static_cast<const UINT32*
>(
368 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, x));
371 SDL_DisplayID
id = *cur;
374 if (std::find(ids.begin(), ids.end(),
id) == ids.end())
376 WLog_ERR(TAG,
"Supplied monitor ID[%" PRIuz
"]=%" PRIu32
" is invalid", x,
id);
381 if (std::find(used.begin(), used.end(),
id) != used.end())
383 WLog_ERR(TAG,
"Duplicate monitor ID[%" PRIuz
"]=%" PRIu32
" detected", x,
id);
388 sdl->setMonitorIds(used);
391 if (!sdl_apply_display_properties(sdl))
394 auto size =
static_cast<uint32_t
>(sdl->monitorIds().size());
398 return sdl_detect_single_window(sdl, pMaxWidth, pMaxHeight);
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_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.