diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
commit | a9bcc81f821d7c66f623779fa5147e728eb3c388 (patch) | |
tree | 98676963bcdd537ae5908a067a8eb110b93486a6 /client/SDL/sdl_monitor.cpp | |
parent | Initial commit. (diff) | |
download | freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip |
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'client/SDL/sdl_monitor.cpp')
-rw-r--r-- | client/SDL/sdl_monitor.cpp | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/client/SDL/sdl_monitor.cpp b/client/SDL/sdl_monitor.cpp new file mode 100644 index 0000000..e637b48 --- /dev/null +++ b/client/SDL/sdl_monitor.cpp @@ -0,0 +1,331 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * X11 Monitor Handling + * + * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * Copyright 2017 David Fort <contact@hardening-consulting.com> + * Copyright 2018 Kai Harms <kharms@rangee.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <freerdp/config.h> + +#include <cstdio> +#include <cstdlib> +#include <cstring> + +#include <SDL.h> + +#include <winpr/assert.h> +#include <winpr/crt.h> + +#include <freerdp/log.h> + +#define TAG CLIENT_TAG("sdl") + +#include "sdl_monitor.hpp" +#include "sdl_freerdp.hpp" + +typedef struct +{ + RECTANGLE_16 area; + RECTANGLE_16 workarea; + BOOL primary; +} MONITOR_INFO; + +typedef struct +{ + int nmonitors; + RECTANGLE_16 area; + RECTANGLE_16 workarea; + MONITOR_INFO* monitors; +} VIRTUAL_SCREEN; + +/* See MSDN Section on Multiple Display Monitors: http://msdn.microsoft.com/en-us/library/dd145071 + */ + +int sdl_list_monitors(SdlContext* sdl) +{ + SDL_Init(SDL_INIT_VIDEO); + const int nmonitors = SDL_GetNumVideoDisplays(); + + printf("listing %d monitors:\n", nmonitors); + for (int i = 0; i < nmonitors; i++) + { + SDL_Rect rect = {}; + const int brc = SDL_GetDisplayBounds(i, &rect); + const char* name = SDL_GetDisplayName(i); + + if (brc != 0) + continue; + printf(" %s [%d] [%s] %dx%d\t+%d+%d\n", (i == 0) ? "*" : " ", i, name, rect.w, rect.h, + rect.x, rect.y); + } + + SDL_Quit(); + return 0; +} + +static BOOL sdl_is_monitor_id_active(SdlContext* sdl, UINT32 id) +{ + const rdpSettings* settings = nullptr; + + WINPR_ASSERT(sdl); + + settings = sdl->context()->settings; + WINPR_ASSERT(settings); + + const UINT32 NumMonitorIds = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds); + if (!NumMonitorIds) + return TRUE; + + for (UINT32 index = 0; index < NumMonitorIds; index++) + { + auto cur = static_cast<const UINT32*>( + freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, index)); + if (cur && (*cur == id)) + return TRUE; + } + + return FALSE; +} + +static BOOL sdl_apply_max_size(SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight) +{ + WINPR_ASSERT(sdl); + WINPR_ASSERT(pMaxWidth); + WINPR_ASSERT(pMaxHeight); + + auto settings = sdl->context()->settings; + WINPR_ASSERT(settings); + + *pMaxWidth = 0; + *pMaxHeight = 0; + + for (size_t x = 0; x < freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount); x++) + { + auto monitor = static_cast<const rdpMonitor*>( + freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x)); + + if (freerdp_settings_get_bool(settings, FreeRDP_Fullscreen)) + { + *pMaxWidth = monitor->width; + *pMaxHeight = monitor->height; + } + else if (freerdp_settings_get_bool(settings, FreeRDP_Workarea)) + { + SDL_Rect rect = {}; + SDL_GetDisplayUsableBounds(monitor->orig_screen, &rect); + *pMaxWidth = rect.w; + *pMaxHeight = rect.h; + } + else if (freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen) > 0) + { + SDL_Rect rect = {}; + SDL_GetDisplayUsableBounds(monitor->orig_screen, &rect); + + *pMaxWidth = rect.w; + *pMaxHeight = rect.h; + + if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseWidth)) + *pMaxWidth = + (rect.w * freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) / 100; + + if (freerdp_settings_get_bool(settings, FreeRDP_PercentScreenUseHeight)) + *pMaxHeight = + (rect.h * freerdp_settings_get_uint32(settings, FreeRDP_PercentScreen)) / 100; + } + else if (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) && + freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight)) + { + *pMaxWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth); + *pMaxHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight); + } + } + return TRUE; +} + +#if SDL_VERSION_ATLEAST(2, 0, 10) +static UINT32 sdl_orientaion_to_rdp(SDL_DisplayOrientation orientation) +{ + switch (orientation) + { + case SDL_ORIENTATION_LANDSCAPE: + return ORIENTATION_LANDSCAPE; + case SDL_ORIENTATION_LANDSCAPE_FLIPPED: + return ORIENTATION_LANDSCAPE_FLIPPED; + case SDL_ORIENTATION_PORTRAIT_FLIPPED: + return ORIENTATION_PORTRAIT_FLIPPED; + case SDL_ORIENTATION_PORTRAIT: + default: + return ORIENTATION_PORTRAIT; + } +} +#endif + +static BOOL sdl_apply_display_properties(SdlContext* sdl) +{ + WINPR_ASSERT(sdl); + + rdpSettings* settings = sdl->context()->settings; + WINPR_ASSERT(settings); + + const UINT32 numIds = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds); + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorDefArray, nullptr, numIds)) + return FALSE; + if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorCount, numIds)) + return FALSE; + + for (UINT32 x = 0; x < numIds; x++) + { + auto id = static_cast<const UINT32*>( + freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, x)); + WINPR_ASSERT(id); + + float ddpi = 1.0f; + float hdpi = 1.0f; + float vdpi = 1.0f; + SDL_Rect rect = {}; + + SDL_GetDisplayBounds(*id, &rect); + SDL_GetDisplayDPI(*id, &ddpi, &hdpi, &vdpi); + + bool highDpi = hdpi > 100; + + if (highDpi) + { + // HighDPI is problematic with SDL: We can only get native resolution by creating a + // window. Work around this by checking the supported resolutions (and keep maximum) + // Also scale the DPI + const SDL_Rect scaleRect = rect; + for (int i = 0; i < SDL_GetNumDisplayModes(*id); i++) + { + SDL_DisplayMode mode = {}; + SDL_GetDisplayMode(x, i, &mode); + + if (mode.w > rect.w) + { + rect.w = mode.w; + rect.h = mode.h; + } + else if (mode.w == rect.w) + { + if (mode.h > rect.h) + { + rect.w = mode.w; + rect.h = mode.h; + } + } + } + + const float dw = 1.0f * rect.w / scaleRect.w; + const float dh = 1.0f * rect.h / scaleRect.h; + hdpi /= dw; + vdpi /= dh; + } + +#if SDL_VERSION_ATLEAST(2, 0, 10) + const SDL_DisplayOrientation orientation = SDL_GetDisplayOrientation(*id); + const UINT32 rdp_orientation = sdl_orientaion_to_rdp(orientation); +#else + const UINT32 rdp_orientation = ORIENTATION_LANDSCAPE; +#endif + + auto monitor = static_cast<rdpMonitor*>( + freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, x)); + WINPR_ASSERT(monitor); + + /* windows uses 96 dpi as 'default' and the scale factors are in percent. */ + const auto factor = ddpi / 96.0f * 100.0f; + monitor->orig_screen = x; + monitor->x = rect.x; + monitor->y = rect.y; + monitor->width = rect.w; + monitor->height = rect.h; + monitor->is_primary = x == 0; + monitor->attributes.desktopScaleFactor = factor; + monitor->attributes.deviceScaleFactor = 100; + monitor->attributes.orientation = rdp_orientation; + monitor->attributes.physicalWidth = rect.w / hdpi; + monitor->attributes.physicalHeight = rect.h / vdpi; + } + return TRUE; +} + +static BOOL sdl_detect_single_window(SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight) +{ + WINPR_ASSERT(sdl); + WINPR_ASSERT(pMaxWidth); + WINPR_ASSERT(pMaxHeight); + + rdpSettings* settings = sdl->context()->settings; + WINPR_ASSERT(settings); + + if ((!freerdp_settings_get_bool(settings, FreeRDP_UseMultimon) && + !freerdp_settings_get_bool(settings, FreeRDP_SpanMonitors)) || + (freerdp_settings_get_bool(settings, FreeRDP_Workarea) && + !freerdp_settings_get_bool(settings, FreeRDP_RemoteApplicationMode))) + { + /* If no monitors were specified on the command-line then set the current monitor as active + */ + if (freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds) == 0) + { + const size_t id = + (sdl->windows.size() > 0) ? sdl->windows.begin()->second.displayIndex() : 0; + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, &id, 1)) + return FALSE; + } + else + { + + /* Always sets number of monitors from command-line to just 1. + * If the monitor is invalid then we will default back to current monitor + * later as a fallback. So, there is no need to validate command-line entry here. + */ + if (!freerdp_settings_set_uint32(settings, FreeRDP_NumMonitorIds, 1)) + return FALSE; + } + + // TODO: Fill monitor struct + if (!sdl_apply_display_properties(sdl)) + return FALSE; + return sdl_apply_max_size(sdl, pMaxWidth, pMaxHeight); + } + return TRUE; +} + +BOOL sdl_detect_monitors(SdlContext* sdl, UINT32* pMaxWidth, UINT32* pMaxHeight) +{ + WINPR_ASSERT(sdl); + WINPR_ASSERT(pMaxWidth); + WINPR_ASSERT(pMaxHeight); + + rdpSettings* settings = sdl->context()->settings; + 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++) + { + if (!freerdp_settings_set_pointer_array(settings, FreeRDP_MonitorIds, x, &x)) + return FALSE; + } + + if (!sdl_apply_display_properties(sdl)) + return FALSE; + + return sdl_detect_single_window(sdl, pMaxWidth, pMaxHeight); +} |