Merge pull request #12248 from motor-dev/master

[client,sdl] fix multimon/fullscreen on wayland
This commit is contained in:
akallabeth
2026-02-09 08:54:27 +01:00
committed by GitHub
6 changed files with 139 additions and 118 deletions

View File

@@ -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<SDL_Rect> 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;

View File

@@ -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();

View File

@@ -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<const char*>(windowEvent.user.data1);
auto msg = static_cast<const char*>(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<const char*>(windowEvent.user.data1);
auto msg = static_cast<const char*>(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<const char*>(windowEvent.user.data1);
auto msg = static_cast<const char**>(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<const SDL_UserAuthArg*>(windowEvent.padding)))
throw ErrorMsg{ -1, windowEvent.type, "sdl_auth_dialog_show" };
}
break;
case SDL_EVENT_USER_UPDATE:
{
std::vector<SDL_Rect> 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<SdlContext*>(windowEvent.user.data1);
if (!ctx->createWindows())
throw ErrorMsg{ -1, windowEvent.type, "sdl->createWindows" };
}
break;
case SDL_EVENT_USER_WINDOW_RESIZEABLE:
{
auto window = static_cast<SdlWindow*>(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<SdlWindow*>(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<const char*>(windowEvent.user.data1);
auto msg = static_cast<const char*>(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<const char*>(windowEvent.user.data1);
auto msg = static_cast<const char*>(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<const char*>(windowEvent.user.data1);
auto msg = static_cast<const char**>(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<INT32>(reinterpret_cast<uintptr_t>(windowEvent.user.data1));
const auto y =
static_cast<INT32>(reinterpret_cast<uintptr_t>(windowEvent.user.data2));
if (!sdl->moveMouseTo(
{ static_cast<float>(x) * 1.0f, static_cast<float>(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<const SDL_UserAuthArg*>(windowEvent.padding)))
throw ErrorMsg{ -1, windowEvent.type, "sdl_auth_dialog_show" };
}
break;
case SDL_EVENT_USER_UPDATE:
{
std::vector<SDL_Rect> 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<SdlContext*>(windowEvent.user.data1);
if (!ctx->createWindows())
throw ErrorMsg{ -1, windowEvent.type, "sdl->createWindows" };
}
break;
case SDL_EVENT_USER_WINDOW_RESIZEABLE:
{
auto window = static_cast<SdlWindow*>(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<SdlWindow*>(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<INT32>(reinterpret_cast<uintptr_t>(windowEvent.user.data1));
const auto y =
static_cast<INT32>(reinterpret_cast<uintptr_t>(windowEvent.user.data2));
if (!sdl->moveMouseTo(
{ static_cast<float>(x) * 1.0f, static_cast<float>(y) * 1.0f }))
throw ErrorMsg{ -1, windowEvent.type, "sdl->moveMouseTo" };
}
break;
case SDL_EVENT_USER_POINTER_SET:
if (!sdl->setCursor(static_cast<rdpPointer*>(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<rdpPointer*>(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)
{

View File

@@ -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<void*>(static_cast<uintptr_t>(va_arg(ap, int)));
break;
case SDL_EVENT_USER_WINDOW_RESIZEABLE:
event->data1 = va_arg(ap, void*);
event->code = va_arg(ap, int);

View File

@@ -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)
{

View File

@@ -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;
};