Skip to content

bevy_winit: Window centering is incorrect when the primary monitor's usable space differs from the intended monitor's #17838

Open
@etorresh

Description

@etorresh

Bevy version

Bevy version 0.15.1

What you did

I created a window with WindowPosition::Centered and positioned it on my secondary monitor. I noticed the window appears off-center when the primary monitor has a Gnome top bar and the secondary monitor doesn't.

DefaultPlugins.set(WindowPlugin {
    primary_window: Some(Window {
        resolution: WindowResolution::new(1600., 900.).with_scale_factor_override(1.0),
        position: WindowPosition::Centered(MonitorSelection::Index(1)),
        ..default()
    }),

My setup:

  • Primary monitor: 1920x1080 with Gnome top bar (32 pixels height), so 1920x1048 usable space
  • Secondary monitor: 1920x1080 without Gnome top bar
  • Both monitors at 100% scaling

What went wrong

Expected:
The window should be perfectly centered on the secondary monitor since it has the full 1920x1080 space available.

Actual:
The window sits too low on the screen, there's more space at the top than at the bottom. I measured the offset and it's exactly 16 pixels, which interestingly is half the height of the Gnome top bar from my primary monitor.

Additional information

I think I found where this happens in winit_windows.rs in the winit_window_position() function. Here's my theory of what's going on:

  1. I believe the window's resolution gets set based on the primary monitor's usable space (1048px height due to the Gnome bar)
  2. Then when we move to the secondary monitor, we try to center this same window in the full 1080px height
  3. This would explain why we get that 16px extra space at the top - we're using a window sized for a smaller space but centering it in a larger one

Here's the code where I think this happens (I removed the original comments and added my explanation):

pub fn winit_window_position(
   position: &WindowPosition,
   resolution: &WindowResolution,  // This comes from primary monitor (1048px height)
   monitors: &WinitMonitors,
   primary_monitor: Option<MonitorHandle>,
   current_monitor: Option<MonitorHandle>,
) -> Option<PhysicalPosition<i32>> {
   match position {
       WindowPosition::Automatic => {
           None
       }
       WindowPosition::Centered(monitor_selection) => {
           let maybe_monitor = select_monitor(
               monitors,
               primary_monitor,
               current_monitor,
               monitor_selection,
           );
           if let Some(monitor) = maybe_monitor {
               let screen_size = monitor.size();  // Gets full 1080px height for secondary
               let scale_factor = match resolution.scale_factor_override() {
                   Some(scale_factor_override) => scale_factor_override as f64,
                   None => monitor.scale_factor(),
               };
               // Using primary monitor's resolution in secondary monitor's space
               let (width, height): (u32, u32) =
                   LogicalSize::new(resolution.width(), resolution.height())
                       .to_physical::<u32>(scale_factor)
                       .into();
               let position = PhysicalPosition {
                   x: screen_size.width.saturating_sub(width) as f64 / 2.
                       + monitor.position().x as f64,
                   y: screen_size.height.saturating_sub(height) as f64 / 2.
                       + monitor.position().y as f64,
               };
               Some(position.cast::<i32>())
           } else {
               warn!("Couldn't get monitor selected with: {monitor_selection:?}");
               None
           }
       }
       WindowPosition::At(position) => {
           Some(PhysicalPosition::new(position[0] as f64, position[1] as f64).cast::<i32>())
       }
   }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-WindowingPlatform-agnostic interface layer to run your app inC-BugAn unexpected or incorrect behaviorS-Ready-For-ImplementationThis issue is ready for an implementation PR. Go for it!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions