From ff8cfc2aa029b73d400a406f11f6923040da07e6 Mon Sep 17 00:00:00 2001 From: lopo <59609929+lopo12123@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:44:21 +0800 Subject: [PATCH] Allow users to create viewports larger than monitor on Windows & macOS (#4337) Added clamp_size_to_monitor_size field on ViewportBuilder, which means whether clamp the window's size to monitor's size. (default to `true`) * Closes https://github.com/emilk/egui/issues/3389 ### simple example ```rust pub struct MyApp {} impl MyApp { pub fn new() -> MyApp { MyApp {} } } impl eframe::App for MyApp { fn update(&mut self, ctx: &Context, frame: &mut eframe::Frame) { egui::CentralPanel::default() .frame(Frame::none().fill(Color32::DARK_GRAY)) .show(ctx, |ui| { if ctx.input(|i| i.key_pressed(Key::Escape)) { ctx.send_viewport_cmd(ViewportCommand::Close); } }); } } pub fn main() { let option = eframe::NativeOptions { viewport: ViewportBuilder::default() .with_position([10.0, 10.0]) .with_inner_size([3000.0, 2000.0]) .with_clamp_size_to_monitor_size(false), ..Default::default() }; eframe::run_native( "a large window app", option, Box::new(|ctx| Box::new(MyApp::new())), ).unwrap(); } ``` It works on my windows (with 3 monitors), but I don't have a test environment for macos --------- Co-authored-by: Emil Ernerfeldt --- crates/eframe/src/native/epi_integration.rs | 23 +++++++++++++++------ crates/egui-winit/src/lib.rs | 1 + crates/egui/src/viewport.rs | 22 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/crates/eframe/src/native/epi_integration.rs b/crates/eframe/src/native/epi_integration.rs index fbf7b6dc078..b09f0f0e0c7 100644 --- a/crates/eframe/src/native/epi_integration.rs +++ b/crates/eframe/src/native/epi_integration.rs @@ -20,14 +20,23 @@ pub fn viewport_builder( let mut viewport_builder = native_options.viewport.clone(); + let clamp_size_to_monitor_size = viewport_builder.clamp_size_to_monitor_size.unwrap_or( + // On some Linux systems, a window size larger than the monitor causes crashes + cfg!(target_os = "linux"), + ); + // Always use the default window size / position on iOS. Trying to restore the previous position // causes the window to be shown too small. #[cfg(not(target_os = "ios"))] let inner_size_points = if let Some(mut window_settings) = window_settings { // Restore pos/size from previous session - window_settings - .clamp_size_to_sane_values(largest_monitor_point_size(egui_zoom_factor, event_loop)); + if clamp_size_to_monitor_size { + window_settings.clamp_size_to_sane_values(largest_monitor_point_size( + egui_zoom_factor, + event_loop, + )); + } window_settings.clamp_position_to_monitors(egui_zoom_factor, event_loop); viewport_builder = window_settings.initialize_viewport_builder(viewport_builder); @@ -37,10 +46,12 @@ pub fn viewport_builder( viewport_builder = viewport_builder.with_position(pos); } - if let Some(initial_window_size) = viewport_builder.inner_size { - let initial_window_size = initial_window_size - .at_most(largest_monitor_point_size(egui_zoom_factor, event_loop)); - viewport_builder = viewport_builder.with_inner_size(initial_window_size); + if clamp_size_to_monitor_size { + if let Some(initial_window_size) = viewport_builder.inner_size { + let initial_window_size = initial_window_size + .at_most(largest_monitor_point_size(egui_zoom_factor, event_loop)); + viewport_builder = viewport_builder.with_inner_size(initial_window_size); + } } viewport_builder.inner_size diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index 81840e951a7..313cc58906b 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -1598,6 +1598,7 @@ pub fn create_winit_window_builder( window_type: _window_type, mouse_passthrough: _, // handled in `apply_viewport_builder_to_window` + clamp_size_to_monitor_size: _, // Handled in `viewport_builder` in `epi_integration.rs` } = viewport_builder; let mut window_builder = winit::window::WindowBuilder::new() diff --git a/crates/egui/src/viewport.rs b/crates/egui/src/viewport.rs index ad7332877c0..090e93b3fe5 100644 --- a/crates/egui/src/viewport.rs +++ b/crates/egui/src/viewport.rs @@ -275,6 +275,11 @@ pub struct ViewportBuilder { pub min_inner_size: Option, pub max_inner_size: Option, + /// Whether clamp the window's size to monitor's size. The default is `true` on linux, otherwise it is `false`. + /// + /// Note: On some Linux systems, a window size larger than the monitor causes crashes + pub clamp_size_to_monitor_size: Option, + pub fullscreen: Option, pub maximized: Option, pub resizable: Option, @@ -493,6 +498,15 @@ impl ViewportBuilder { self } + /// Sets whether clamp the window's size to monitor's size. The default is `true` on linux, otherwise it is `false`. + /// + /// Note: On some Linux systems, a window size larger than the monitor causes crashes + #[inline] + pub fn with_clamp_size_to_monitor_size(mut self, value: bool) -> Self { + self.clamp_size_to_monitor_size = Some(value); + self + } + /// Does not work on X11. #[inline] pub fn with_close_button(mut self, value: bool) -> Self { @@ -606,6 +620,7 @@ impl ViewportBuilder { inner_size: new_inner_size, min_inner_size: new_min_inner_size, max_inner_size: new_max_inner_size, + clamp_size_to_monitor_size: new_clamp_size_to_monitor_size, fullscreen: new_fullscreen, maximized: new_maximized, resizable: new_resizable, @@ -740,6 +755,13 @@ impl ViewportBuilder { let mut recreate_window = false; + if new_clamp_size_to_monitor_size.is_some() + && self.clamp_size_to_monitor_size != new_clamp_size_to_monitor_size + { + self.clamp_size_to_monitor_size = new_clamp_size_to_monitor_size; + recreate_window = true; + } + if new_active.is_some() && self.active != new_active { self.active = new_active; recreate_window = true;