rcore_desktop_glfw.c - Wayland compatibility

Because Wayland does not let know or set the position of a window, it broke some basic Raylib's features and functions. I tried to find a balance between crossplatform compatibilities, and the Wayland way of doing things. So, on Wayland, `SetWindowMonitor()` won't move a windowed window from a monitor to another, but can be used to select on which monitor the user wants the hardware fullscreen mode.
This commit is contained in:
SuperUserNameMan 2024-07-21 16:01:58 +02:00 committed by GitHub
parent 310e4d72a8
commit 9fb406ac1a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -621,6 +621,9 @@ void SetWindowPosition(int x, int y)
}
// Set monitor for the current window
// NOTE : As of current version of Wayland and GLFW, it is not possible to set the position of a windowed
// window by code, so this fonction will not move it from a display to another. Instead, it will
// associate a monitor index to the window for fullscreen mode.
void SetWindowMonitor(int monitor)
{
int monitorCount = 0;
@ -628,6 +631,8 @@ void SetWindowMonitor(int monitor)
if ((monitor >= 0) && (monitor < monitorCount))
{
CORE.Window.lastAssociatedMonitorIndex = monitor;
if ((CORE.Window.fullscreen) || IsWindowState(FLAG_BORDERLESS_WINDOWED_MODE))
{
TRACELOG(LOG_INFO, "GLFW: Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor]));
@ -658,6 +663,11 @@ void SetWindowMonitor(int monitor)
// GLFW 3.4 may trigger an error if platform like Wayland don't support setting or getting the position of the window
glfwGetError(NULL); // So we must clear this error
// NOTE : As of current version of Wayland and GLFW, it is not possible to set the position of a windowed
// window by code, so this fonction will not move it from a display to another. Instead, it will
// associate a monitor index to the window for fullscreen mode.
}
}
else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
@ -772,13 +782,35 @@ int GetCurrentMonitor(void)
}
}
else
if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND)
{
// The algorithm bellow, which relies on the window position, won't work with current version of Wayland
// and GLFW, because Wayland does not allow to know the window position.
// NOTE : this is not a bug in Wayland or GLFW, it is a "feature design" of current version of Wayland.
// So intead of computing on which monitor is mostly displayed the window, we return the index of the monitor
// to which the user wanted to associate the window to using `SetWindowMonitor()` :
index = CORE.Window.lastAssociatedMonitorIndex;
if ((index < 0) || (index >= monitorCount))
{
index = monitorCount - 1;
// A monitor was probably unplugged.
// TODO : add a TRACELOG ?
CORE.Window.lastAssociatedMonitorIndex = index;
}
}
else
{
// In case the window is between two monitors, we use below logic
// to try to detect the "current monitor" for that window, note that
// this is probably an overengineered solution for a very side case
// trying to match SDL behaviour
// NOTE : this won't work with Wayland because it does not allow to know the window position
// NOTE : this algorithm won't work with Wayland because it does not allow to know the window position.
int closestDist = 0x7FFFFFFF;
@ -1486,18 +1518,34 @@ int InitPlatform(void)
// NOTE : we can't use glfwGetWindowMonitor() directly because it only works if the window is
// already in hardware fullscreen mode, otherwise it returns NULL. So we use `GetCurrentMonitor()`.
if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND)
{
// On current version of Wayland and GLFW it is not possible to know on which monitor the window
// is mostly visible onto. On some distro, the window will just open on the monitor with the mouse cursor.
// Unfortunately, the mouse coordinates returned by GLFW are always relative to the top left corner of the
// window frameBuffer. It is thus impossible to guess on which monitor the window was opened.
// So we pretend it was on the main monitor, because it is the most common scenario.
// It is thus possible to associate an other monitor to the window afterward using `SetWindowMonitor()`.
// However, this association will only have an effect when toggling the window to hardware fullscreen mode.
CORE.Window.lastAssociatedMonitorIndex = 0;
}
else
{
CORE.Window.lastAssociatedMonitorIndex = GetCurrentMonitor();
}
int monitorCount = 0;
int monitorIndex = GetCurrentMonitor();
GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
if (monitorIndex >= monitorCount)
if (CORE.Window.lastAssociatedMonitorIndex >= monitorCount)
{
TRACELOG(LOG_WARNING, "GLFW: Failed to determine Monitor to center Window");
glfwTerminate();
return -1;
}
GLFWmonitor *monitor = monitors[monitorIndex];
GLFWmonitor *monitor = monitors[CORE.Window.lastAssociatedMonitorIndex];
// We got the monitor, now let's get its current video mode :
@ -1741,7 +1789,7 @@ int InitPlatform(void)
// We don't use `ToggleFullscreen()` directly because `CORE.Window.fullscreen` is already set to `true`,
// and `ToggleFullscreen()` would think it is already in fullscreen mode.
bool _result = _ActivateHardwareFullscreenMode(monitorIndex, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
bool _result = _ActivateHardwareFullscreenMode(CORE.Window.lastAssociatedMonitorIndex, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
if ( _result == false )
{
TRACELOG(LOG_WARNING,"DISPLAY: failed to activate fullscreen mode.");
@ -2195,7 +2243,7 @@ static void _DeactivateHardwareFullscreenMode()
glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y, CORE.Window.previousScreen.width, CORE.Window.previousScreen.height, GLFW_DONT_CARE);
// As we're leaving we must restore soem metrics :
// As we're leaving we must restore some metrics :
int monitorIndex = GetCurrentMonitor();