From 144b1a1f833c1d049cc1e8d82ee9bc9872c486ee Mon Sep 17 00:00:00 2001 From: Sylvain <67423638+Le-Syl21@users.noreply.github.com> Date: Tue, 25 Aug 2026 14:07:33 +0200 Subject: [PATCH] eframe: apply ViewportBuilder::with_monitor on the glow backend (#8302) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem `ViewportBuilder::with_monitor(idx)` is a **no-op on the glow backend**. A window built with `.with_monitor(...)` opens on the default monitor, not fullscreen — while the exact same code works on wgpu. The monitor → `Fullscreen::Borderless(Some(monitor))` resolution only lives in `egui_winit::create_window`, which the **wgpu** backend uses. The **glow** backend builds its windows straight from `egui_winit::create_winit_window_attributes` at two sites in `glow_integration.rs` — the initial window and per-viewport deferred windows — so the monitor is never applied there. ## Repro A multi-viewport app on the glow renderer with any viewport built via `ViewportBuilder::default().with_monitor(1)` opens that window on monitor 0, un-fullscreen. Switching to the wgpu renderer places it correctly. Seen on a 3-monitor GNOME/Wayland setup where the main window and secondary viewports all need to land borderless-fullscreen on specific outputs. ## Fix Extract the resolution into a public `apply_monitor_to_window_attributes` in `egui-winit` and call it from `create_window` (unchanged behaviour) plus both glow window-creation sites, so `with_monitor` behaves the same on glow and wgpu. No public API change beyond the new helper; no behaviour change on wgpu. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- crates/eframe/src/native/glow_integration.rs | 17 +++++---- crates/egui-winit/src/lib.rs | 36 +++++++++++++++----- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/crates/eframe/src/native/glow_integration.rs b/crates/eframe/src/native/glow_integration.rs index 28a1ee681..82a150aad 100644 --- a/crates/eframe/src/native/glow_integration.rs +++ b/crates/eframe/src/native/glow_integration.rs @@ -1094,9 +1094,10 @@ impl GlutinWindowContext { // // The justification for FallbackEgl over PreferEgl is at https://github.com/emilk/egui/pull/2526#issuecomment-1400229576 . .with_preference(glutin_winit::ApiPreference::FallbackEgl) - .with_window_attributes(Some(egui_winit::create_winit_window_attributes( - egui_ctx, - viewport_builder.clone(), + .with_window_attributes(Some(egui_winit::apply_monitor_to_window_attributes( + egui_winit::create_winit_window_attributes(egui_ctx, viewport_builder.clone()), + &viewport_builder, + event_loop, ))); let (window, gl_config) = { @@ -1262,9 +1263,13 @@ impl GlutinWindowContext { window } else { log::debug!("Creating a window for viewport {viewport_id:?}"); - let window_attributes = egui_winit::create_winit_window_attributes( - &self.egui_ctx, - viewport.builder.clone(), + let window_attributes = egui_winit::apply_monitor_to_window_attributes( + egui_winit::create_winit_window_attributes( + &self.egui_ctx, + viewport.builder.clone(), + ), + &viewport.builder, + event_loop, ); if window_attributes.transparent() && self.gl_config.supports_transparency() == Some(false) diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index 0029a47b7..70d1fda78 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -1971,12 +1971,33 @@ pub fn create_window( ) -> Result { profiling::function_scope!(); - let mut window_attributes = create_winit_window_attributes(egui_ctx, viewport_builder.clone()); + let window_attributes = apply_monitor_to_window_attributes( + create_winit_window_attributes(egui_ctx, viewport_builder.clone()), + viewport_builder, + event_loop, + ); - // Resolve target monitor index → MonitorHandle, so the window is created - // directly in borderless fullscreen on the requested output. This is the - // only reliable way to target a specific monitor under Wayland, and also - // avoids the Mutter race where OuterPosition is ignored pre-mapping. + let window = event_loop.create_window(window_attributes)?; + apply_viewport_builder_to_window(egui_ctx, &window, viewport_builder); + Ok(window) +} + +/// Apply [`ViewportBuilder::with_monitor`] to freshly-built [`winit::window::WindowAttributes`]. +/// +/// Resolve the target monitor index → `MonitorHandle` and request borderless +/// fullscreen on that output, so the window is created directly on the right +/// monitor. This is the only reliable way to target a specific monitor under +/// Wayland, and also avoids the Mutter race where `OuterPosition` is ignored +/// pre-mapping. +/// +/// Must be called by every backend that builds its own window from +/// [`create_winit_window_attributes`] (the glow backend and per-viewport window +/// creation do this) — otherwise `with_monitor` silently does nothing there. +pub fn apply_monitor_to_window_attributes( + mut window_attributes: winit::window::WindowAttributes, + viewport_builder: &ViewportBuilder, + event_loop: &ActiveEventLoop, +) -> winit::window::WindowAttributes { if let Some(idx) = viewport_builder.monitor { if let Some(monitor) = event_loop.available_monitors().nth(idx) { window_attributes = window_attributes @@ -1988,10 +2009,7 @@ pub fn create_window( ); } } - - let window = event_loop.create_window(window_attributes)?; - apply_viewport_builder_to_window(egui_ctx, &window, viewport_builder); - Ok(window) + window_attributes } pub fn create_winit_window_attributes(