From 9fb406ac1aff264a3f4e129a0a14b207c94a3c17 Mon Sep 17 00:00:00 2001 From: SuperUserNameMan <9801802+SuperUserNameMan@users.noreply.github.com> Date: Sun, 21 Jul 2024 16:01:58 +0200 Subject: [PATCH] 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. --- src/platforms/rcore_desktop_glfw.c | 60 +++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index affa3a0f3..ae6970ed0 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -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();