mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
[client,sdl] fix multimon/fullscreen on wayland
Help SDL identify the display to use for fullscreen even when compositors interfere with window positions. SDL respects the intent of a window if it is moved to the appropriate display just before it is made fullscreen.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user