From 49dc431045d7d4f1a0f5bf16c62ec59dc999e9c9 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 23 Aug 2024 13:08:55 +0200 Subject: [PATCH] [client,sdl] add support for /monitors argument --- client/SDL/SDL2/sdl_freerdp.cpp | 7 ++- client/SDL/SDL2/sdl_monitor.cpp | 72 +++++++++++++++++++++++++++-- client/SDL/SDL2/sdl_monitor.hpp | 1 + client/SDL/SDL3/sdl_freerdp.cpp | 8 +++- client/SDL/SDL3/sdl_monitor.cpp | 81 ++++++++++++++++++++++++++++----- client/SDL/SDL3/sdl_monitor.hpp | 1 + 6 files changed, 149 insertions(+), 21 deletions(-) diff --git a/client/SDL/SDL2/sdl_freerdp.cpp b/client/SDL/SDL2/sdl_freerdp.cpp index 20e4abee3..8880f68ca 100644 --- a/client/SDL/SDL2/sdl_freerdp.cpp +++ b/client/SDL/SDL2/sdl_freerdp.cpp @@ -705,6 +705,9 @@ static BOOL sdl_create_windows(SdlContext* sdl) for (UINT32 x = 0; x < windowCount; x++) { + auto id = sdl_monitor_id_for_index(sdl, x); + if (id < 0) + return FALSE; auto monitor = static_cast( freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, x)); @@ -718,8 +721,8 @@ static BOOL sdl_create_windows(SdlContext* sdl) } Uint32 flags = SDL_WINDOW_SHOWN; - Uint32 startupX = SDL_WINDOWPOS_CENTERED_DISPLAY(x); - Uint32 startupY = SDL_WINDOWPOS_CENTERED_DISPLAY(x); + Uint32 startupX = SDL_WINDOWPOS_CENTERED_DISPLAY(id); + Uint32 startupY = SDL_WINDOWPOS_CENTERED_DISPLAY(id); if (monitor->attributes.desktopScaleFactor > 100) { diff --git a/client/SDL/SDL2/sdl_monitor.cpp b/client/SDL/SDL2/sdl_monitor.cpp index c8570289b..35c00ef45 100644 --- a/client/SDL/SDL2/sdl_monitor.cpp +++ b/client/SDL/SDL2/sdl_monitor.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -324,13 +325,56 @@ BOOL sdl_detect_monitors(SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight) WINPR_ASSERT(settings); const int numDisplays = SDL_GetNumVideoDisplays(); - if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, nullptr, numDisplays)) - return FALSE; - - for (size_t x = 0; x < numDisplays; x++) + auto nr = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds); + if (nr == 0) { - if (!freerdp_settings_set_pointer_array(settings, FreeRDP_MonitorIds, x, &x)) + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, nullptr, numDisplays)) return FALSE; + for (size_t x = 0; x < numDisplays; x++) + { + if (!freerdp_settings_set_pointer_array(settings, FreeRDP_MonitorIds, x, &x)) + return FALSE; + } + } + else + { + + /* There were more IDs supplied than there are monitors */ + if (nr > numDisplays) + { + WLog_ERR(TAG, + "Found %" PRIu32 " monitor IDs, but only have %" PRIu32 " monitors connected", + nr, numDisplays); + return FALSE; + } + + std::vector used; + for (size_t x = 0; x < nr; x++) + { + auto cur = static_cast( + freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, x)); + WINPR_ASSERT(cur); + + auto id = *cur; + + /* the ID is no valid monitor index */ + if (id >= nr) + { + WLog_ERR(TAG, + "Supplied monitor ID[%" PRIuz "]=%" PRIu32 " is invalid, only [0-%" PRIu32 + "] are allowed", + x, id, nr - 1); + return FALSE; + } + + /* The ID is already taken */ + if (std::find(used.begin(), used.end(), id) != used.end()) + { + WLog_ERR(TAG, "Duplicate monitor ID[%" PRIuz "]=%" PRIu32 " detected", x, id); + return FALSE; + } + used.push_back(*cur); + } } if (!sdl_apply_display_properties(sdl)) @@ -338,3 +382,21 @@ BOOL sdl_detect_monitors(SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight) return sdl_detect_single_window(sdl, pMaxWidth, pMaxHeight); } + +INT64 sdl_monitor_id_for_index(SdlContext* sdl, UINT32 index) +{ + WINPR_ASSERT(sdl); + auto settings = sdl->context()->settings; + + auto nr = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds); + if (nr == 0) + return index; + + if (nr <= index) + return -1; + + auto cur = static_cast( + freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, index)); + WINPR_ASSERT(cur); + return *cur; +} diff --git a/client/SDL/SDL2/sdl_monitor.hpp b/client/SDL/SDL2/sdl_monitor.hpp index 64f9f5688..1605a82b3 100644 --- a/client/SDL/SDL2/sdl_monitor.hpp +++ b/client/SDL/SDL2/sdl_monitor.hpp @@ -26,3 +26,4 @@ int sdl_list_monitors(SdlContext* sdl); BOOL sdl_detect_monitors(SdlContext* sdl, UINT32* pWidth, UINT32* pHeight); +INT64 sdl_monitor_id_for_index(SdlContext* sdl, UINT32 index); diff --git a/client/SDL/SDL3/sdl_freerdp.cpp b/client/SDL/SDL3/sdl_freerdp.cpp index 3828bc14d..b73dc0912 100644 --- a/client/SDL/SDL3/sdl_freerdp.cpp +++ b/client/SDL/SDL3/sdl_freerdp.cpp @@ -703,6 +703,10 @@ static BOOL sdl_create_windows(SdlContext* sdl) for (UINT32 x = 0; x < windowCount; x++) { + auto id = sdl_monitor_id_for_index(sdl, x); + if (id < 0) + return FALSE; + auto monitor = static_cast( freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, x)); @@ -716,8 +720,8 @@ static BOOL sdl_create_windows(SdlContext* sdl) } Uint32 flags = 0; - Uint32 startupX = SDL_WINDOWPOS_CENTERED_DISPLAY(x); - Uint32 startupY = SDL_WINDOWPOS_CENTERED_DISPLAY(x); + Uint32 startupX = SDL_WINDOWPOS_CENTERED_DISPLAY(id); + Uint32 startupY = SDL_WINDOWPOS_CENTERED_DISPLAY(id); if (monitor->attributes.desktopScaleFactor > 100) { diff --git a/client/SDL/SDL3/sdl_monitor.cpp b/client/SDL/SDL3/sdl_monitor.cpp index 68d42cfc9..4791ccf8c 100644 --- a/client/SDL/SDL3/sdl_monitor.cpp +++ b/client/SDL/SDL3/sdl_monitor.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -318,28 +319,84 @@ BOOL sdl_detect_monitors(SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight) rdpSettings* settings = sdl->context()->settings; WINPR_ASSERT(settings); - int numDisplays = 0; - auto ids = SDL_GetDisplays(&numDisplays); - - if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, nullptr, numDisplays)) + std::vector ids; { - SDL_free(ids); - return FALSE; + int numDisplays = 0; + auto sids = SDL_GetDisplays(&numDisplays); + ids = std::vector(sids, sids + numDisplays); + SDL_free(sids); } - for (size_t x = 0; x < numDisplays; x++) + auto nr = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds); + if (nr == 0) { - auto id = ids[x]; - if (!freerdp_settings_set_pointer_array(settings, FreeRDP_MonitorIds, x, &id)) - { - SDL_free(ids); + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, nullptr, ids.size())) return FALSE; + + for (size_t x = 0; x < ids.size(); x++) + { + auto id = ids[x]; + if (!freerdp_settings_set_pointer_array(settings, FreeRDP_MonitorIds, x, &id)) + return FALSE; + } + } + else + { + /* There were more IDs supplied than there are monitors */ + if (nr > ids.size()) + { + WLog_ERR(TAG, + "Found %" PRIu32 " monitor IDs, but only have %" PRIuz " monitors connected", + nr, ids.size()); + return FALSE; + } + + std::vector used; + for (size_t x = 0; x < nr; x++) + { + auto cur = static_cast( + freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, x)); + WINPR_ASSERT(cur); + + auto id = *cur; + + /* the ID is no valid monitor index */ + if (std::find(ids.begin(), ids.end(), id) == ids.end()) + { + WLog_ERR(TAG, "Supplied monitor ID[%" PRIuz "]=%" PRIu32 " is invalid", x, id); + return FALSE; + } + + /* The ID is already taken */ + if (std::find(used.begin(), used.end(), id) != used.end()) + { + WLog_ERR(TAG, "Duplicate monitor ID[%" PRIuz "]=%" PRIu32 " detected", x, id); + return FALSE; + } + used.push_back(*cur); } } - SDL_free(ids); if (!sdl_apply_display_properties(sdl)) return FALSE; return sdl_detect_single_window(sdl, pMaxWidth, pMaxHeight); } + +INT64 sdl_monitor_id_for_index(SdlContext* sdl, UINT32 index) +{ + WINPR_ASSERT(sdl); + auto settings = sdl->context()->settings; + + auto nr = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds); + if (nr == 0) + return index; + + if (nr <= index) + return -1; + + auto cur = static_cast( + freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, index)); + WINPR_ASSERT(cur); + return *cur; +} diff --git a/client/SDL/SDL3/sdl_monitor.hpp b/client/SDL/SDL3/sdl_monitor.hpp index 64f9f5688..1605a82b3 100644 --- a/client/SDL/SDL3/sdl_monitor.hpp +++ b/client/SDL/SDL3/sdl_monitor.hpp @@ -26,3 +26,4 @@ int sdl_list_monitors(SdlContext* sdl); BOOL sdl_detect_monitors(SdlContext* sdl, UINT32* pWidth, UINT32* pHeight); +INT64 sdl_monitor_id_for_index(SdlContext* sdl, UINT32 index);