Skip to content

Commit

Permalink
Fix initial size of windows on multi-monitor systems
Browse files Browse the repository at this point in the history
  • Loading branch information
emilk committed Nov 30, 2023
1 parent 37244e3 commit 8408acf
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 27 deletions.
4 changes: 2 additions & 2 deletions crates/eframe/src/native/glow_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,7 @@ impl GlutinWindowContext {
.map_err(|e| crate::Error::NoGlutinConfigs(config_template_builder.build(), e))?
};
if let Some(window) = &window {
apply_viewport_builder_to_new_window(window, &viewport_builder);
apply_viewport_builder_to_new_window(egui_ctx, window, &viewport_builder);
}

let gl_display = gl_config.display();
Expand Down Expand Up @@ -986,7 +986,7 @@ impl GlutinWindowContext {
create_winit_window_builder(&self.egui_ctx, event_loop, viewport.builder.clone()),
&self.gl_config,
)?;
apply_viewport_builder_to_new_window(&window, &viewport.builder);
apply_viewport_builder_to_new_window(&self.egui_ctx, &window, &viewport.builder);
viewport.info.minimized = window.is_minimized();
viewport.info.maximized = Some(window.is_maximized());
viewport.window.insert(Rc::new(window))
Expand Down
13 changes: 2 additions & 11 deletions crates/eframe/src/native/wgpu_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -779,12 +779,8 @@ impl Viewport {

let viewport_id = self.ids.this;

match create_winit_window_builder(egui_ctx, event_loop, self.builder.clone())
.build(event_loop)
{
match egui_winit::create_window(egui_ctx, event_loop, &self.builder) {
Ok(window) => {
apply_viewport_builder_to_new_window(&window, &self.builder);

windows_id.insert(window.id(), viewport_id);

if let Err(err) = pollster::block_on(painter.set_window(viewport_id, Some(&window)))
Expand Down Expand Up @@ -840,12 +836,7 @@ fn create_window(
)
.with_visible(false); // Start hidden until we render the first frame to fix white flash on startup (https://github.com/emilk/egui/pull/3631)

let window = {
crate::profile_scope!("WindowBuilder::build");
create_winit_window_builder(egui_ctx, event_loop, viewport_builder.clone())
.build(event_loop)?
};
apply_viewport_builder_to_new_window(&window, &viewport_builder);
let window = egui_winit::create_window(egui_ctx, event_loop, &viewport_builder)?;
epi_integration::apply_window_settings(&window, window_settings);
Ok((window, viewport_builder))
}
Expand Down
88 changes: 75 additions & 13 deletions crates/egui-winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,26 @@ fn process_viewport_command(
}
}

/// Build and intitlaize a window.
///
/// Wrapper around `create_winit_window_builder` and `apply_viewport_builder_to_new_window`.
pub fn create_window<T>(
egui_ctx: &egui::Context,
event_loop: &EventLoopWindowTarget<T>,
viewport_builder: &ViewportBuilder,
) -> Result<Window, winit::error::OsError> {
crate::profile_function!();

let window_builder =
create_winit_window_builder(egui_ctx, event_loop, viewport_builder.clone());
let window = {
crate::profile_scope!("WindowBuilder::build");
window_builder.build(event_loop)?
};
apply_viewport_builder_to_new_window(egui_ctx, &window, viewport_builder);
Ok(window)
}

pub fn create_winit_window_builder<T>(
egui_ctx: &egui::Context,
event_loop: &EventLoopWindowTarget<T>,
Expand All @@ -1253,6 +1273,8 @@ pub fn create_winit_window_builder<T>(

// We set sizes and positions in egui:s own ui points, which depends on the egui
// zoom_factor and the native pixels per point, so we need to know that here.
// We don't know what monitor the window will appear on though, but
// we'll try to fix that after the window is created in the vall to `apply_viewport_builder_to_new_window`.
let native_pixels_per_point = event_loop
.primary_monitor()
.or_else(|| event_loop.available_monitors().next())
Expand Down Expand Up @@ -1330,31 +1352,31 @@ pub fn create_winit_window_builder<T>(
})
.with_active(active.unwrap_or(true));

if let Some(inner_size) = inner_size {
if let Some(size) = inner_size {
window_builder = window_builder.with_inner_size(PhysicalSize::new(
pixels_per_point * inner_size.x,
pixels_per_point * inner_size.y,
pixels_per_point * size.x,
pixels_per_point * size.y,
));
}

if let Some(min_inner_size) = min_inner_size {
if let Some(size) = min_inner_size {
window_builder = window_builder.with_min_inner_size(PhysicalSize::new(
pixels_per_point * min_inner_size.x,
pixels_per_point * min_inner_size.y,
pixels_per_point * size.x,
pixels_per_point * size.y,
));
}

if let Some(max_inner_size) = max_inner_size {
if let Some(size) = max_inner_size {
window_builder = window_builder.with_max_inner_size(PhysicalSize::new(
pixels_per_point * max_inner_size.x,
pixels_per_point * max_inner_size.y,
pixels_per_point * size.x,
pixels_per_point * size.y,
));
}

if let Some(position) = position {
if let Some(pos) = position {
window_builder = window_builder.with_position(PhysicalPosition::new(
pixels_per_point * position.x,
pixels_per_point * position.y,
pixels_per_point * pos.x,
pixels_per_point * pos.y,
));
}

Expand Down Expand Up @@ -1391,12 +1413,52 @@ pub fn create_winit_window_builder<T>(
}

/// Applies what `create_winit_window_builder` couldn't
pub fn apply_viewport_builder_to_new_window(window: &Window, builder: &ViewportBuilder) {
pub fn apply_viewport_builder_to_new_window(
egui_ctx: &egui::Context,
window: &Window,
builder: &ViewportBuilder,
) {
if let Some(mouse_passthrough) = builder.mouse_passthrough {
if let Err(err) = window.set_cursor_hittest(!mouse_passthrough) {
log::warn!("set_cursor_hittest failed: {err}");
}
}

if let Some(monitor) = window.current_monitor() {
// In `create_winit_window_builder` we didn't know
// on what monitor the window would appear, so we didn't know
// how to translate egui ui point to native physical pixels.
// Now we do know:

let native_pixels_per_point = monitor.scale_factor() as f32;
let zoom_factor = egui_ctx.zoom_factor();
let pixels_per_point = zoom_factor * native_pixels_per_point;

if let Some(size) = builder.inner_size {
window.set_inner_size(PhysicalSize::new(
pixels_per_point * size.x,
pixels_per_point * size.y,
));
}
if let Some(size) = builder.min_inner_size {
window.set_min_inner_size(Some(PhysicalSize::new(
pixels_per_point * size.x,
pixels_per_point * size.y,
)));
}
if let Some(size) = builder.max_inner_size {
window.set_max_inner_size(Some(PhysicalSize::new(
pixels_per_point * size.x,
pixels_per_point * size.y,
)));
}
if let Some(pos) = builder.position {
let pos = PhysicalPosition::new(pixels_per_point * pos.x, pixels_per_point * pos.y);
window.set_outer_position(pos);
}
} else {
log::debug!("Couldn't figure out what monitor the new window is on, so the window size will likely be wrong.");
}
}

// ---------------------------------------------------------------------------
Expand Down
4 changes: 3 additions & 1 deletion crates/egui/src/viewport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ pub struct ViewportBuilder {
/// This is wayland only. See [`Self::with_app_id`].
pub app_id: Option<String>,

/// The desired outer position of the window.
pub position: Option<Pos2>,
pub inner_size: Option<Vec2>,
pub min_inner_size: Option<Vec2>,
Expand Down Expand Up @@ -506,7 +507,8 @@ impl ViewportBuilder {
self
}

/// This will probably not work as expected!
/// The initial "outer" position of the window,
/// i.e. where the top-left corner of the frame/chrome should be.
#[inline]
pub fn with_position(mut self, pos: impl Into<Pos2>) -> Self {
self.position = Some(pos.into());
Expand Down

0 comments on commit 8408acf

Please sign in to comment.