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_context.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,
84[[nodiscard]]
static BOOL sdl_apply_mon_max_size(
SdlContext* sdl, UINT32* pMaxWidth,
92 WINPR_ASSERT(pMaxWidth);
93 WINPR_ASSERT(pMaxHeight);
95 auto settings = sdl->context()->settings;
96 WINPR_ASSERT(settings);
100 auto monitor =
static_cast<const rdpMonitor*
>(
101 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x));
103 left = std::min(monitor->x, left);
104 top = std::min(monitor->y, top);
105 right = std::max(monitor->x + monitor->width, right);
106 bottom = std::max(monitor->y + monitor->height, bottom);
109 const int32_t w = right - left;
110 const int32_t h = bottom - top;
112 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, w);
113 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, h);
117[[nodiscard]]
static BOOL sdl_apply_max_size(
SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
120 WINPR_ASSERT(pMaxWidth);
121 WINPR_ASSERT(pMaxHeight);
123 auto settings = sdl->context()->settings;
124 WINPR_ASSERT(settings);
131 auto monitor =
static_cast<const rdpMonitor*
>(
132 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x));
136 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->width);
137 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, monitor->height);
142 SDL_GetDisplayUsableBounds(monitor->orig_screen, &rect);
143 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rect.w);
144 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, rect.h);
149 SDL_GetDisplayUsableBounds(monitor->orig_screen, &rect);
151 *pMaxWidth = WINPR_ASSERTING_INT_CAST(uint32_t, rect.w);
152 *pMaxHeight = WINPR_ASSERTING_INT_CAST(uint32_t, rect.h);
155 *pMaxWidth = (WINPR_ASSERTING_INT_CAST(uint32_t, rect.w) *
160 *pMaxHeight = (WINPR_ASSERTING_INT_CAST(uint32_t, rect.h) *
174[[nodiscard]]
static Uint32 scale(Uint32 val,
float scale)
176 const auto dval =
static_cast<float>(val);
177 const auto sval = dval / scale;
178 return static_cast<Uint32
>(sval);
181[[nodiscard]]
static BOOL sdl_apply_monitor_properties(
rdpMonitor& monitor, SDL_DisplayID
id,
185 float dpi = SDL_GetDisplayContentScale(
id);
190 if (!SDL_GetDisplayBounds(
id, &rect))
193 WINPR_ASSERT(rect.w > 0);
194 WINPR_ASSERT(rect.h > 0);
196 bool highDpi = dpi > 100;
203 const SDL_Rect scaleRect = rect;
205 auto modes = SDL_GetFullscreenDisplayModes(
id, &count);
206 for (
int i = 0; i < count; i++)
208 auto mode = modes[i];
212 if (mode->w > rect.w)
217 else if (mode->w == rect.w)
219 if (mode->h > rect.h)
226 SDL_free(
static_cast<void*
>(modes));
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 const SDL_DisplayOrientation orientation = SDL_GetCurrentDisplayOrientation(
id);
235 const UINT32 rdp_orientation = sdl::utils::orientaion_to_rdp(orientation);
238 const auto factor = dpi / 96.0f * 100.0f;
239 monitor.orig_screen = id;
242 monitor.width = rect.w;
243 monitor.height = rect.h;
244 monitor.is_primary = isPrimary;
245 monitor.attributes.desktopScaleFactor =
static_cast<UINT32
>(factor);
246 monitor.attributes.deviceScaleFactor = 100;
247 monitor.attributes.orientation = rdp_orientation;
248 monitor.attributes.physicalWidth = scale(WINPR_ASSERTING_INT_CAST(uint32_t, rect.w), hdpi);
249 monitor.attributes.physicalHeight = scale(WINPR_ASSERTING_INT_CAST(uint32_t, rect.h), vdpi);
253[[nodiscard]]
static BOOL sdl_apply_display_properties(
SdlContext* sdl)
257 rdpSettings* settings = sdl->context()->settings;
258 WINPR_ASSERT(settings);
260 std::vector<rdpMonitor> monitors;
266 if (sdl->monitorIds().empty())
268 const auto id = sdl->monitorIds().front();
270 if (!sdl_apply_monitor_properties(monitor,
id, TRUE))
272 monitors.emplace_back(monitor);
278 for (
const auto&
id : sdl->monitorIds())
281 const auto primary = SDL_GetPrimaryDisplay();
282 if (!sdl_apply_monitor_properties(monitor,
id,
id == primary))
284 monitors.emplace_back(monitor);
290[[nodiscard]]
static BOOL sdl_detect_single_window(
SdlContext* sdl, UINT32* pMaxWidth,
294 WINPR_ASSERT(pMaxWidth);
295 WINPR_ASSERT(pMaxHeight);
297 rdpSettings* settings = sdl->context()->settings;
298 WINPR_ASSERT(settings);
309 SDL_DisplayID
id = 0;
310 const auto& ids = sdl->monitorIds();
315 sdl->setMonitorIds({
id });
319 if (!sdl_apply_display_properties(sdl))
321 return sdl_apply_max_size(sdl, pMaxWidth, pMaxHeight);
323 return sdl_apply_mon_max_size(sdl, pMaxWidth, pMaxHeight);
326BOOL sdl_detect_monitors(
SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight)
329 WINPR_ASSERT(pMaxWidth);
330 WINPR_ASSERT(pMaxHeight);
332 rdpSettings* settings = sdl->context()->settings;
333 WINPR_ASSERT(settings);
335 std::vector<SDL_DisplayID> ids;
338 auto sids = SDL_GetDisplays(&numDisplays);
339 if (sids && (numDisplays > 0))
340 ids = std::vector<SDL_DisplayID>(sids, sids + numDisplays);
350 sdl->setMonitorIds(ids);
353 sdl->setMonitorIds({ ids.front() });
362 "Found %" PRIu32
" monitor IDs, but only have %" PRIuz
" monitors connected",
367 std::vector<SDL_DisplayID> used;
368 for (
size_t x = 0; x < nr; x++)
370 auto cur =
static_cast<const UINT32*
>(
371 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, x));
374 SDL_DisplayID
id = *cur;
377 if (std::find(ids.begin(), ids.end(),
id) == ids.end())
379 WLog_ERR(TAG,
"Supplied monitor ID[%" PRIuz
"]=%" PRIu32
" is invalid", x,
id);
384 if (std::find(used.begin(), used.end(),
id) != used.end())
386 WLog_ERR(TAG,
"Duplicate monitor ID[%" PRIuz
"]=%" PRIu32
" detected", x,
id);
391 sdl->setMonitorIds(used);
394 if (!sdl_apply_display_properties(sdl))
397 auto size =
static_cast<uint32_t
>(sdl->monitorIds().size());
401 return sdl_detect_single_window(sdl, pMaxWidth, pMaxHeight);
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:
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.