From 2661d8c245d89a1a492f6abf3899f0b8f1e9b1a8 Mon Sep 17 00:00:00 2001
From: Chloe Fontenot <foley2431@gmail.com>
Date: Sat, 29 Nov 2025 00:27:22 -0600
Subject: [PATCH] Ignore some additional errors

---
 CMakeLists.txt     |  11 +++++
 README.md          |   1 +
 src/CMakeLists.txt |   3 ++
 src/platform.c     |   6 +--
 src/wl_init.c      |  12 +++++
 src/wl_platform.h  |   9 +++-
 src/wl_window.c    | 107 ++++++++++++++++++++++++++++++++++-----------
 7 files changed, 120 insertions(+), 29 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8b51ae96..b9f36c9d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -169,3 +169,14 @@ if (GLFW_INSTALL)
     endif()
 endif()
 
+
+message(STATUS "<<< Gentoo configuration >>>
+Build type      ${CMAKE_BUILD_TYPE}
+Install path    ${CMAKE_INSTALL_PREFIX}
+Compiler flags:
+C               ${CMAKE_C_FLAGS}
+C++             ${CMAKE_CXX_FLAGS}
+Linker flags:
+Executable      ${CMAKE_EXE_LINKER_FLAGS}
+Module          ${CMAKE_MODULE_LINKER_FLAGS}
+Shared          ${CMAKE_SHARED_LINKER_FLAGS}\n")
diff --git a/README.md b/README.md
index e3d18ec8..d484ce53 100644
--- a/README.md
+++ b/README.md
@@ -319,6 +319,7 @@ information on what to include when reporting a bug.
  - [Wayland] Disabled alpha channel for opaque windows on systems lacking
    `EGL_EXT_present_opaque` (#1895)
  - [Wayland] Removed support for `wl_shell` (#1443)
+ - [Wayland] Prefer Wayland over X11 if both are available (#2035)
  - [Wayland] Bugfix: The `GLFW_HAND_CURSOR` shape used the wrong image (#1432)
  - [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled
  - [Wayland] Bugfix: Repeated keys could be reported with `NULL` window (#1704)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 01f191c9..9596eff1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -113,6 +113,9 @@ if (GLFW_BUILD_WAYLAND)
     wayland_generate(
         "${WAYLAND_PROTOCOLS_BASE}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
         "${GLFW_BINARY_DIR}/src/wayland-idle-inhibit-unstable-v1-client-protocol")
+    wayland_generate(
+        "${WAYLAND_PROTOCOLS_BASE}/staging/fractional-scale/fractional-scale-v1.xml"
+        "${GLFW_BINARY_DIR}/src/wayland-fractional-scale-v1-client-protocol")
 endif()
 
 if (WIN32 AND GLFW_BUILD_SHARED_LIBRARY)
diff --git a/src/platform.c b/src/platform.c
index c5966ae7..3e7442f9 100644
--- a/src/platform.c
+++ b/src/platform.c
@@ -49,12 +49,12 @@ static const struct
 #if defined(_GLFW_COCOA)
     { GLFW_PLATFORM_COCOA, _glfwConnectCocoa },
 #endif
-#if defined(_GLFW_X11)
-    { GLFW_PLATFORM_X11, _glfwConnectX11 },
-#endif
 #if defined(_GLFW_WAYLAND)
     { GLFW_PLATFORM_WAYLAND, _glfwConnectWayland },
 #endif
+#if defined(_GLFW_X11)
+    { GLFW_PLATFORM_X11, _glfwConnectX11 },
+#endif
 };
 
 GLFWbool _glfwSelectPlatform(int desiredID, _GLFWplatform* platform)
diff --git a/src/wl_init.c b/src/wl_init.c
index 66d77dca..370d6d4f 100644
--- a/src/wl_init.c
+++ b/src/wl_init.c
@@ -48,6 +48,7 @@
 #include "wayland-relative-pointer-unstable-v1-client-protocol.h"
 #include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
 #include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
+#include "wayland-fractional-scale-v1-client-protocol.h"
 
 // NOTE: Versions of wayland-scanner prior to 1.17.91 named every global array of
 //       wl_interface pointers 'types', making it impossible to combine several unmodified
@@ -82,6 +83,10 @@
 #include "wayland-idle-inhibit-unstable-v1-client-protocol-code.h"
 #undef types
 
+#define types _glfw_fractional_scale_manager_types
+#include "wayland-fractional-scale-v1-client-protocol-code.h"
+#undef types
+
 static void wmBaseHandlePing(void* userData,
                              struct xdg_wm_base* wmBase,
                              uint32_t serial)
@@ -178,6 +183,13 @@ static void registryHandleGlobal(void* userData,
                              &zwp_idle_inhibit_manager_v1_interface,
                              1);
     }
+    else if (strcmp(interface, "wp_fractional_scale_manager_v1") == 0)
+    {
+        _glfw.wl.fractionalScaleManager =
+            wl_registry_bind(registry, name,
+                             &wp_fractional_scale_manager_v1_interface,
+                             1);
+    }
 }
 
 static void registryHandleGlobalRemove(void* userData,
diff --git a/src/wl_platform.h b/src/wl_platform.h
index e9dd0b4a..cd1f227f 100644
--- a/src/wl_platform.h
+++ b/src/wl_platform.h
@@ -363,6 +363,7 @@ typedef struct _GLFWwindowWayland
     GLFWbool                    transparent;
     struct wl_surface*          surface;
     struct wl_callback*         callback;
+    struct wp_viewport*         viewport;
 
     struct {
         struct wl_egl_window*   window;
@@ -396,16 +397,21 @@ typedef struct _GLFWwindowWayland
 
     // We need to track the monitors the window spans on to calculate the
     // optimal scaling factor.
-    int                         contentScale;
+    float                       contentScale;
     _GLFWscaleWayland*          scales;
     int                         scaleCount;
     int                         scaleSize;
+    int                         compositorPreferredScale;
+
+    double                      askedCursorPosX, askedCursorPosY;
+    GLFWbool                    didAskForSetCursorPos;
 
     struct zwp_relative_pointer_v1* relativePointer;
     struct zwp_locked_pointer_v1*   lockedPointer;
     struct zwp_confined_pointer_v1* confinedPointer;
 
     struct zwp_idle_inhibitor_v1*          idleInhibitor;
+    struct wp_fractional_scale_v1*         fractionalScale;
 
     struct {
         struct wl_buffer*                  buffer;
@@ -434,6 +440,7 @@ typedef struct _GLFWlibraryWayland
     struct zwp_relative_pointer_manager_v1* relativePointerManager;
     struct zwp_pointer_constraints_v1*      pointerConstraints;
     struct zwp_idle_inhibit_manager_v1*     idleInhibitManager;
+    struct wp_fractional_scale_manager_v1*  fractionalScaleManager;
 
     _GLFWofferWayland*          offers;
     unsigned int                offerCount;
diff --git a/src/wl_window.c b/src/wl_window.c
index 7b9e3d0d..0c3f8f9d 100644
--- a/src/wl_window.c
+++ b/src/wl_window.c
@@ -50,6 +50,7 @@
 #include "wayland-relative-pointer-unstable-v1-client-protocol.h"
 #include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
 #include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
+#include "wayland-fractional-scale-v1-client-protocol.h"
 
 #define GLFW_BORDER_SIZE    4
 #define GLFW_CAPTION_HEIGHT 24
@@ -309,7 +310,7 @@ static void setContentAreaOpaque(_GLFWwindow* window)
 
 static void resizeWindow(_GLFWwindow* window)
 {
-    int scale = window->wl.contentScale;
+    float scale = window->wl.contentScale;
     int scaledWidth = window->wl.width * scale;
     int scaledHeight = window->wl.height * scale;
 
@@ -319,6 +320,9 @@ static void resizeWindow(_GLFWwindow* window)
         setContentAreaOpaque(window);
     _glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
 
+    if (window->wl.viewport)
+        wp_viewport_set_destination(window->wl.viewport, window->wl.width, window->wl.height);
+
     if (!window->wl.decorations.top.surface)
         return;
 
@@ -346,22 +350,32 @@ static void resizeWindow(_GLFWwindow* window)
 void _glfwUpdateContentScaleWayland(_GLFWwindow* window)
 {
     if (wl_compositor_get_version(_glfw.wl.compositor) <
-        WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION)
+        WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION && !window->wl.viewport)
     {
         return;
     }
 
-    // Get the scale factor from the highest scale monitor.
-    int maxScale = 1;
-
-    for (int i = 0; i < window->wl.scaleCount; i++)
-        maxScale = _glfw_max(window->wl.scales[i].factor, maxScale);
+    float maxScale = 1;
+    if (window->wl.compositorPreferredScale != 0)
+    {
+        maxScale = window->wl.compositorPreferredScale / 120.;
+    }
+    else
+    {
+        // Get the scale factor from the highest scale monitor.
+        for (int i = 0; i < window->wl.scaleCount; i++)
+            maxScale = _glfw_max(window->wl.scales[i].factor, maxScale);
+    }
 
     // Only change the framebuffer size if the scale changed.
     if (window->wl.contentScale != maxScale)
     {
+        if (!window->wl.viewport)
+        {
+            maxScale = ceilf(maxScale);
+            wl_surface_set_buffer_scale(window->wl.surface, ceilf(maxScale));
+        }
         window->wl.contentScale = maxScale;
-        wl_surface_set_buffer_scale(window->wl.surface, maxScale);
         _glfwInputWindowContentScale(window, maxScale, maxScale);
         resizeWindow(window);
 
@@ -619,6 +633,20 @@ static const struct xdg_surface_listener xdgSurfaceListener =
     xdgSurfaceHandleConfigure
 };
 
+static void fractionalScaleHandlePreferredScale(void *userData,
+                                                struct wp_fractional_scale_v1* fractional_scale,
+                                                uint32_t scale)
+{
+    _GLFWwindow* window = userData;
+    window->wl.compositorPreferredScale = scale;
+    _glfwUpdateContentScaleWayland(window);
+}
+
+static const struct wp_fractional_scale_v1_listener fractionalScaleListener =
+{
+    fractionalScaleHandlePreferredScale
+};
+
 void libdecorFrameHandleConfigure(struct libdecor_frame* frame,
                                   struct libdecor_configuration* config,
                                   void* userData)
@@ -901,8 +929,24 @@ static GLFWbool createXdgShellObjects(_GLFWwindow* window)
     return GLFW_TRUE;
 }
 
-static GLFWbool createShellObjects(_GLFWwindow* window)
+static GLFWbool setupVisibleWindow(_GLFWwindow* window)
 {
+    if (_glfw.wl.fractionalScaleManager)
+    {
+        window->wl.fractionalScale =
+            wp_fractional_scale_manager_v1_get_fractional_scale(_glfw.wl.fractionalScaleManager,
+                                                                window->wl.surface);
+        if (!window->wl.fractionalScale)
+            return GLFW_FALSE;
+        wp_fractional_scale_v1_add_listener(window->wl.fractionalScale,
+                                            &fractionalScaleListener,
+                                            window);
+
+        window->wl.viewport = wp_viewporter_get_viewport(_glfw.wl.viewporter, window->wl.surface);
+        if (window->wl.viewport)
+            wp_viewport_set_destination(window->wl.viewport, window->wl.width, window->wl.height);
+    }
+
     if (_glfw.wl.libdecor.context)
     {
         if (createLibdecorFrame(window))
@@ -912,7 +956,7 @@ static GLFWbool createShellObjects(_GLFWwindow* window)
     return createXdgShellObjects(window);
 }
 
-static void destroyShellObjects(_GLFWwindow* window)
+static void tearDownVisibleWindow(_GLFWwindow* window)
 {
     destroyFallbackDecorations(window);
 
@@ -925,6 +969,12 @@ static void destroyShellObjects(_GLFWwindow* window)
     if (window->wl.xdg.toplevel)
         xdg_toplevel_destroy(window->wl.xdg.toplevel);
 
+    if (window->wl.fractionalScale)
+        wp_fractional_scale_v1_destroy(window->wl.fractionalScale);
+
+    if (window->wl.viewport)
+        wp_viewport_destroy(window->wl.viewport);
+
     if (window->wl.xdg.surface)
         xdg_surface_destroy(window->wl.xdg.surface);
 
@@ -932,6 +982,8 @@ static void destroyShellObjects(_GLFWwindow* window)
     window->wl.xdg.decoration = NULL;
     window->wl.xdg.decorationMode = 0;
     window->wl.xdg.toplevel = NULL;
+    window->wl.fractionalScale = NULL;
+    window->wl.viewport = NULL;
     window->wl.xdg.surface = NULL;
 }
 
@@ -2048,7 +2100,7 @@ GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window,
 
     if (window->monitor || wndconfig->visible)
     {
-        if (!createShellObjects(window))
+        if (!setupVisibleWindow(window))
             return GLFW_FALSE;
     }
 
@@ -2078,7 +2130,7 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window)
     if (window->context.destroy)
         window->context.destroy(window);
 
-    destroyShellObjects(window);
+    tearDownVisibleWindow(window);
 
     if (window->wl.decorations.buffer)
         wl_buffer_destroy(window->wl.decorations.buffer);
@@ -2109,8 +2161,7 @@ void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title)
 void _glfwSetWindowIconWayland(_GLFWwindow* window,
                                int count, const GLFWimage* images)
 {
-    _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
-                    "Wayland: The platform does not support setting the window icon");
+    fprintf(stderr, "!!! Ignoring Error: Wayland: Setting window icon not supported\n");
 }
 
 void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos)
@@ -2118,16 +2169,13 @@ void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos)
     // A Wayland client is not aware of its position, so just warn and leave it
     // as (0, 0)
 
-    _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
-                    "Wayland: The platform does not provide the window position");
+    fprintf(stderr, "!!! Ignoring Error: Wayland: The platform does not provide the window position\n");
 }
 
 void _glfwSetWindowPosWayland(_GLFWwindow* window, int xpos, int ypos)
 {
     // A Wayland client can not set its position, so just warn
-
-    _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
-                    "Wayland: The platform does not support setting the window position");
+    fprintf(stderr, "!! Ignoring Error: Wayland: The platform does not support setting the window position");
 }
 
 void _glfwGetWindowSizeWayland(_GLFWwindow* window, int* width, int* height)
@@ -2328,7 +2376,7 @@ void _glfwShowWindowWayland(_GLFWwindow* window)
     {
         // NOTE: The XDG surface and role are created here so command-line applications
         //       with off-screen windows do not appear in for example the Unity dock
-        createShellObjects(window);
+        setupVisibleWindow(window);
     }
 }
 
@@ -2337,7 +2385,7 @@ void _glfwHideWindowWayland(_GLFWwindow* window)
     if (window->wl.visible)
     {
         window->wl.visible = GLFW_FALSE;
-        destroyShellObjects(window);
+        tearDownVisibleWindow(window);
 
         wl_surface_attach(window->wl.surface, NULL, 0, 0);
         wl_surface_commit(window->wl.surface);
@@ -2353,8 +2401,7 @@ void _glfwRequestWindowAttentionWayland(_GLFWwindow* window)
 
 void _glfwFocusWindowWayland(_GLFWwindow* window)
 {
-    _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
-                    "Wayland: The platform does not support setting the input focus");
+    fprintf(stderr, "!!! Ignoring Error: Wayland: Focusing a window requires user interaction\n");
 }
 
 void _glfwSetWindowMonitorWayland(_GLFWwindow* window,
@@ -2534,8 +2581,9 @@ void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos)
 
 void _glfwSetCursorPosWayland(_GLFWwindow* window, double x, double y)
 {
-    _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
-                    "Wayland: The platform does not support setting the cursor position");
+    window->wl.didAskForSetCursorPos = true;
+    window->wl.askedCursorPosX = x;
+    window->wl.askedCursorPosY = y;
 }
 
 void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode)
@@ -2767,6 +2815,15 @@ static const struct zwp_relative_pointer_v1_listener relativePointerListener =
 static void lockedPointerHandleLocked(void* userData,
                                       struct zwp_locked_pointer_v1* lockedPointer)
 {
+    _GLFWwindow* window = userData;
+
+    if (window->wl.didAskForSetCursorPos)
+    {
+        window->wl.didAskForSetCursorPos = false;
+        zwp_locked_pointer_v1_set_cursor_position_hint(window->wl.lockedPointer,
+                                                       wl_fixed_from_double(window->wl.askedCursorPosX),
+                                                       wl_fixed_from_double(window->wl.askedCursorPosY));
+    }
 }
 
 static void lockedPointerHandleUnlocked(void* userData,
-- 
2.52.0

