From 17d510365286a509b01060471b794a98ccbe0409 Mon Sep 17 00:00:00 2001 From: Dan Egnor Date: Thu, 23 Jul 2026 12:34:19 -0700 Subject: [PATCH] Wayland: guess the origin (0,0) output for a fresh window's fractional scale When there is no focused or recently-focused window to key off of (the typical first-window-at-startup case), glfwGetWaylandCurrentMonitorFractionalScale fell back to the registry-first output (monitors[0]). Registry/connector order is semi-arbitrary and uncorrelated with where a compositor actually places a new window, so on a multi-monitor setup with mixed fractional scales the first window could be born at the wrong size. Prefer the output at the logical origin (0, 0) instead: the compositor's top-left/primary output is a better guess for initial placement than registry order. Fall back to monitors[0] when no output reports (0, 0). Since xdg_output geometry (including position) arrives asynchronously and x/y read zero until it does, wait for every monitor's logical geometry before trusting the reported positions, so an as-yet-unpositioned output cannot spuriously match (0, 0). Discussed in #10268. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01VjwP6hQjA6GMuiM7Mf9VAx --- glfw/wl_monitor.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/glfw/wl_monitor.c b/glfw/wl_monitor.c index cbd45b10a..d05f13455 100644 --- a/glfw/wl_monitor.c +++ b/glfw/wl_monitor.c @@ -351,8 +351,31 @@ GLFWAPI double glfwGetWaylandCurrentMonitorFractionalScale(void) if (window && window->wl.monitorsCount > 0) monitor = window->wl.monitors[0]; } - if (!monitor) - monitor = _glfw.monitors[0]; + if (!monitor) { + // No focused window to key off of (typically the first window at + // startup). Prefer the output at the logical origin (0, 0): the + // compositor's top-left/primary output is a better guess for where a + // new window will be placed than registry order. Fall back to the + // first output if no output reports position (0, 0). + // + // xdg_output geometry arrives asynchronously and x/y remain zero until + // it does, so wait for every monitor's logical geometry before trusting + // the reported positions (otherwise an as-yet-unpositioned output would + // spuriously match (0, 0)). + for (int i = 0; i < _glfw.monitorCount; i++) { + _GLFWmonitor *m = _glfw.monitors[i]; + while (m->wl.xdg_output && m->wl.xdg_logical_width <= 0) { + if (wl_display_roundtrip(_glfw.wl.display) < 0) break; + } + } + for (int i = 0; i < _glfw.monitorCount; i++) { + _GLFWmonitor *m = _glfw.monitors[i]; + if (m->wl.xdg_output && m->wl.xdg_logical_width > 0 && + m->wl.x == 0 && m->wl.y == 0) { monitor = m; break; } + } + if (!monitor) + monitor = _glfw.monitors[0]; + } if (!monitor->wl.xdg_output) return monitor->wl.scale > 0 ? (double)monitor->wl.scale : 1.0;