diff --git a/client/SDL/SDL3/sdl_context.cpp b/client/SDL/SDL3/sdl_context.cpp index 80aeeb895..a1714b3b4 100644 --- a/client/SDL/SDL3/sdl_context.cpp +++ b/client/SDL/SDL3/sdl_context.cpp @@ -295,7 +295,8 @@ BOOL SdlContext::postConnect(freerdp* instance) if (!sdl->setResizeable(false)) return FALSE; if (!sdl->setFullscreen(freerdp_settings_get_bool(context->settings, FreeRDP_Fullscreen) || - freerdp_settings_get_bool(context->settings, FreeRDP_UseMultimon))) + freerdp_settings_get_bool(context->settings, FreeRDP_UseMultimon), + true)) return FALSE; sdl->setConnected(true); return TRUE; @@ -1379,11 +1380,12 @@ std::vector SdlContext::pop() return val; } -bool SdlContext::setFullscreen(bool enter) +bool SdlContext::setFullscreen(bool enter, bool forceOriginalDisplay) { for (const auto& window : _windows) { - if (!sdl_push_user_event(SDL_EVENT_USER_WINDOW_FULLSCREEN, &window.second, enter)) + if (!sdl_push_user_event(SDL_EVENT_USER_WINDOW_FULLSCREEN, &window.second, enter, + forceOriginalDisplay)) return false; } _fullscreen = enter; diff --git a/client/SDL/SDL3/sdl_context.hpp b/client/SDL/SDL3/sdl_context.hpp index ef6b59fb7..25f82e60e 100644 --- a/client/SDL/SDL3/sdl_context.hpp +++ b/client/SDL/SDL3/sdl_context.hpp @@ -70,7 +70,7 @@ class SdlContext [[nodiscard]] bool fullscreen() const; [[nodiscard]] bool toggleFullscreen(); - [[nodiscard]] bool setFullscreen(bool enter); + [[nodiscard]] bool setFullscreen(bool enter, bool forceOriginalDisplay = false); [[nodiscard]] bool setMinimized(); diff --git a/client/SDL/SDL3/sdl_freerdp.cpp b/client/SDL/SDL3/sdl_freerdp.cpp index e92dc1093..ef761324a 100644 --- a/client/SDL/SDL3/sdl_freerdp.cpp +++ b/client/SDL/SDL3/sdl_freerdp.cpp @@ -134,126 +134,127 @@ static void sdl_term_handler([[maybe_unused]] int signum, [[maybe_unused]] const } #if defined(WITH_DEBUG_SDL_EVENTS) - SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "got event %s [0x%08" PRIx32 "]", - sdl::utils::toString(windowEvent.type).c_str(), windowEvent.type); + SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "got event %s [0x%08" PRIx32 "]", + sdl::utils::toString(windowEvent.type).c_str(), windowEvent.type); #endif - if (sdl->shallAbort(true)) - continue; + if (sdl->shallAbort(true)) + continue; - if (sdl->getDialog().handleEvent(windowEvent)) - continue; + if (sdl->getDialog().handleEvent(windowEvent)) + continue; - if (!sdl->handleEvent(windowEvent)) - throw ErrorMsg{ -1, windowEvent.type, "sdl->handleEvent" }; + if (!sdl->handleEvent(windowEvent)) + throw ErrorMsg{ -1, windowEvent.type, "sdl->handleEvent" }; - switch (windowEvent.type) - { - case SDL_EVENT_QUIT: - std::ignore = freerdp_abort_connect_context(sdl->context()); - break; - case SDL_EVENT_USER_CERT_DIALOG: + switch (windowEvent.type) { - SDLConnectionDialogHider hider(sdl); - auto title = static_cast(windowEvent.user.data1); - auto msg = static_cast(windowEvent.user.data2); - if (!sdl_cert_dialog_show(title, msg)) - throw ErrorMsg{ -1, windowEvent.type, "sdl_cert_dialog_show" }; - } - break; - case SDL_EVENT_USER_SHOW_DIALOG: - { - SDLConnectionDialogHider hider(sdl); - auto title = static_cast(windowEvent.user.data1); - auto msg = static_cast(windowEvent.user.data2); - if (!sdl_message_dialog_show(title, msg, windowEvent.user.code)) - throw ErrorMsg{ -1, windowEvent.type, "sdl_message_dialog_show" }; - } - break; - case SDL_EVENT_USER_SCARD_DIALOG: - { - SDLConnectionDialogHider hider(sdl); - auto title = static_cast(windowEvent.user.data1); - auto msg = static_cast(windowEvent.user.data2); - if (!sdl_scard_dialog_show(title, windowEvent.user.code, msg)) - throw ErrorMsg{ -1, windowEvent.type, "sdl_scard_dialog_show" }; - } - break; - case SDL_EVENT_USER_AUTH_DIALOG: - { - SDLConnectionDialogHider hider(sdl); - if (!sdl_auth_dialog_show( - reinterpret_cast(windowEvent.padding))) - throw ErrorMsg{ -1, windowEvent.type, "sdl_auth_dialog_show" }; - } - break; - case SDL_EVENT_USER_UPDATE: - { - std::vector rectangles; - do + case SDL_EVENT_QUIT: + std::ignore = freerdp_abort_connect_context(sdl->context()); + break; + case SDL_EVENT_USER_CERT_DIALOG: { - rectangles = sdl->pop(); - if (!sdl->drawToWindows(rectangles)) - throw ErrorMsg{ -1, windowEvent.type, "sdl->drawToWindows" }; - } while (!rectangles.empty()); - } - break; - case SDL_EVENT_USER_CREATE_WINDOWS: - { - auto ctx = static_cast(windowEvent.user.data1); - if (!ctx->createWindows()) - throw ErrorMsg{ -1, windowEvent.type, "sdl->createWindows" }; - } - break; - case SDL_EVENT_USER_WINDOW_RESIZEABLE: - { - auto window = static_cast(windowEvent.user.data1); - const bool use = windowEvent.user.code != 0; - if (window) - window->resizeable(use); - } - break; - case SDL_EVENT_USER_WINDOW_FULLSCREEN: - { - auto window = static_cast(windowEvent.user.data1); - const bool enter = windowEvent.user.code != 0; - if (window) - window->fullscreen(enter); - } - break; - case SDL_EVENT_USER_WINDOW_MINIMIZE: - if (!sdl->minimizeAllWindows()) - throw ErrorMsg{ -1, windowEvent.type, "sdl->minimizeAllWindows" }; + SDLConnectionDialogHider hider(sdl); + auto title = static_cast(windowEvent.user.data1); + auto msg = static_cast(windowEvent.user.data2); + if (!sdl_cert_dialog_show(title, msg)) + throw ErrorMsg{ -1, windowEvent.type, "sdl_cert_dialog_show" }; + } break; - case SDL_EVENT_USER_POINTER_NULL: - if (!sdl->setCursor(SdlContext::CURSOR_NULL)) - throw ErrorMsg{ -1, windowEvent.type, "sdl->setCursor" }; + case SDL_EVENT_USER_SHOW_DIALOG: + { + SDLConnectionDialogHider hider(sdl); + auto title = static_cast(windowEvent.user.data1); + auto msg = static_cast(windowEvent.user.data2); + if (!sdl_message_dialog_show(title, msg, windowEvent.user.code)) + throw ErrorMsg{ -1, windowEvent.type, "sdl_message_dialog_show" }; + } break; - case SDL_EVENT_USER_POINTER_DEFAULT: - if (!sdl->setCursor(SdlContext::CURSOR_DEFAULT)) - throw ErrorMsg{ -1, windowEvent.type, "sdl->setCursor" }; + case SDL_EVENT_USER_SCARD_DIALOG: + { + SDLConnectionDialogHider hider(sdl); + auto title = static_cast(windowEvent.user.data1); + auto msg = static_cast(windowEvent.user.data2); + if (!sdl_scard_dialog_show(title, windowEvent.user.code, msg)) + throw ErrorMsg{ -1, windowEvent.type, "sdl_scard_dialog_show" }; + } break; - case SDL_EVENT_USER_POINTER_POSITION: - { - const auto x = - static_cast(reinterpret_cast(windowEvent.user.data1)); - const auto y = - static_cast(reinterpret_cast(windowEvent.user.data2)); - if (!sdl->moveMouseTo( - { static_cast(x) * 1.0f, static_cast(y) * 1.0f })) - throw ErrorMsg{ -1, windowEvent.type, "sdl->moveMouseTo" }; + case SDL_EVENT_USER_AUTH_DIALOG: + { + SDLConnectionDialogHider hider(sdl); + if (!sdl_auth_dialog_show( + reinterpret_cast(windowEvent.padding))) + throw ErrorMsg{ -1, windowEvent.type, "sdl_auth_dialog_show" }; + } + break; + case SDL_EVENT_USER_UPDATE: + { + std::vector rectangles; + do + { + rectangles = sdl->pop(); + if (!sdl->drawToWindows(rectangles)) + throw ErrorMsg{ -1, windowEvent.type, "sdl->drawToWindows" }; + } while (!rectangles.empty()); + } + break; + case SDL_EVENT_USER_CREATE_WINDOWS: + { + auto ctx = static_cast(windowEvent.user.data1); + if (!ctx->createWindows()) + throw ErrorMsg{ -1, windowEvent.type, "sdl->createWindows" }; + } + break; + case SDL_EVENT_USER_WINDOW_RESIZEABLE: + { + auto window = static_cast(windowEvent.user.data1); + const bool use = windowEvent.user.code != 0; + if (window) + window->resizeable(use); + } + break; + case SDL_EVENT_USER_WINDOW_FULLSCREEN: + { + auto window = static_cast(windowEvent.user.data1); + const bool enter = windowEvent.user.code != 0; + const bool forceOriginalDisplay = windowEvent.user.data2 != nullptr; + if (window) + window->fullscreen(enter, forceOriginalDisplay); + } + break; + case SDL_EVENT_USER_WINDOW_MINIMIZE: + if (!sdl->minimizeAllWindows()) + throw ErrorMsg{ -1, windowEvent.type, "sdl->minimizeAllWindows" }; + break; + case SDL_EVENT_USER_POINTER_NULL: + if (!sdl->setCursor(SdlContext::CURSOR_NULL)) + throw ErrorMsg{ -1, windowEvent.type, "sdl->setCursor" }; + break; + case SDL_EVENT_USER_POINTER_DEFAULT: + if (!sdl->setCursor(SdlContext::CURSOR_DEFAULT)) + throw ErrorMsg{ -1, windowEvent.type, "sdl->setCursor" }; + break; + case SDL_EVENT_USER_POINTER_POSITION: + { + const auto x = + static_cast(reinterpret_cast(windowEvent.user.data1)); + const auto y = + static_cast(reinterpret_cast(windowEvent.user.data2)); + if (!sdl->moveMouseTo( + { static_cast(x) * 1.0f, static_cast(y) * 1.0f })) + throw ErrorMsg{ -1, windowEvent.type, "sdl->moveMouseTo" }; + } + break; + case SDL_EVENT_USER_POINTER_SET: + if (!sdl->setCursor(static_cast(windowEvent.user.data1))) + throw ErrorMsg{ -1, windowEvent.type, "sdl->setCursor" }; + break; + case SDL_EVENT_USER_QUIT: + default: + break; } - break; - case SDL_EVENT_USER_POINTER_SET: - if (!sdl->setCursor(static_cast(windowEvent.user.data1))) - throw ErrorMsg{ -1, windowEvent.type, "sdl->setCursor" }; - break; - case SDL_EVENT_USER_QUIT: - default: - break; - } } } - rc = 1; + rc = 1; } catch (ErrorMsg& msg) { diff --git a/client/SDL/SDL3/sdl_utils.cpp b/client/SDL/SDL3/sdl_utils.cpp index 5210d7bae..436033106 100644 --- a/client/SDL/SDL3/sdl_utils.cpp +++ b/client/SDL/SDL3/sdl_utils.cpp @@ -128,6 +128,10 @@ bool sdl_push_user_event(Uint32 type, ...) event->data1 = va_arg(ap, void*); break; case SDL_EVENT_USER_WINDOW_FULLSCREEN: + event->data1 = va_arg(ap, void*); + event->code = va_arg(ap, int); + event->data2 = reinterpret_cast(static_cast(va_arg(ap, int))); + break; case SDL_EVENT_USER_WINDOW_RESIZEABLE: event->data1 = va_arg(ap, void*); event->code = va_arg(ap, int); diff --git a/client/SDL/SDL3/sdl_window.cpp b/client/SDL/SDL3/sdl_window.cpp index 0a1aa0fcf..0bed3e3fe 100644 --- a/client/SDL/SDL3/sdl_window.cpp +++ b/client/SDL/SDL3/sdl_window.cpp @@ -23,7 +23,9 @@ #include "sdl_window.hpp" #include "sdl_utils.hpp" -SdlWindow::SdlWindow(const std::string& title, const SDL_Rect& rect, [[maybe_unused]] Uint32 flags) +SdlWindow::SdlWindow(SDL_DisplayID id, const std::string& title, const SDL_Rect& rect, + [[maybe_unused]] Uint32 flags) + : _displayID(id) { auto props = SDL_CreateProperties(); SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, title.c_str()); @@ -54,7 +56,8 @@ SdlWindow::SdlWindow(const std::string& title, const SDL_Rect& rect, [[maybe_unu } SdlWindow::SdlWindow(SdlWindow&& other) noexcept - : _window(other._window), _offset_x(other._offset_x), _offset_y(other._offset_y) + : _window(other._window), _displayID(other._displayID), _offset_x(other._offset_x), + _offset_y(other._offset_y) { other._window = nullptr; } @@ -211,8 +214,18 @@ void SdlWindow::resizeable(bool use) std::ignore = SDL_SyncWindow(_window); } -void SdlWindow::fullscreen(bool enter) +void SdlWindow::fullscreen(bool enter, bool forceOriginalDisplay) { + if (enter && forceOriginalDisplay && _displayID != 0) + { + /* Move the window to the desired display. We should not wait + * for the window to be moved, because some backends can refuse + * the move. The intent of moving the window is enough for SDL + * to decide which display will be used for fullscreen. */ + SDL_Rect rect = {}; + std::ignore = SDL_GetDisplayBounds(_displayID, &rect); + std::ignore = SDL_SetWindowPosition(_window, rect.x, rect.y); + } std::ignore = SDL_SetWindowFullscreen(_window, enter); std::ignore = SDL_SyncWindow(_window); } @@ -324,7 +337,7 @@ SdlWindow SdlWindow::create(SDL_DisplayID id, const std::string& title, Uint32 f std::ignore = SDL_GetDisplayBounds(id, &rect); } - SdlWindow window{ title, rect, flags }; + SdlWindow window{ id, title, rect, flags }; if ((flags & (SDL_WINDOW_FULLSCREEN)) != 0) { diff --git a/client/SDL/SDL3/sdl_window.hpp b/client/SDL/SDL3/sdl_window.hpp index ae6a72486..303e2a9b3 100644 --- a/client/SDL/SDL3/sdl_window.hpp +++ b/client/SDL/SDL3/sdl_window.hpp @@ -61,7 +61,7 @@ class SdlWindow void setBordered(bool bordered); void raise(); void resizeable(bool use); - void fullscreen(bool enter); + void fullscreen(bool enter, bool forceOriginalDisplay); void minimize(); [[nodiscard]] bool resize(const SDL_Point& size); @@ -80,10 +80,11 @@ class SdlWindow void updateSurface(); protected: - SdlWindow(const std::string& title, const SDL_Rect& rect, Uint32 flags); + SdlWindow(SDL_DisplayID id, const std::string& title, const SDL_Rect& rect, Uint32 flags); private: SDL_Window* _window = nullptr; + SDL_DisplayID _displayID = 0; Sint32 _offset_x = 0; Sint32 _offset_y = 0; };