Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
etorresh opened this issue Feb 13, 2025 · 0 comments
Labels
A-Windowing Platform-agnostic interface layer to run your app in C-Bug An unexpected or incorrect behavior S-Ready-For-Implementation This issue is ready for an implementation PR. Go for it!

Comments

@etorresh
Copy link

etorresh commented Feb 13, 2025

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>())
       }
   }
}
@etorresh etorresh added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Feb 13, 2025
@TimJentzsch TimJentzsch added A-Windowing Platform-agnostic interface layer to run your app in S-Ready-For-Implementation This issue is ready for an implementation PR. Go for it! and removed S-Needs-Triage This issue needs to be labelled labels Feb 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Windowing Platform-agnostic interface layer to run your app in C-Bug An unexpected or incorrect behavior S-Ready-For-Implementation This issue is ready for an implementation PR. Go for it!
Projects
None yet
Development

No branches or pull requests

2 participants