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

[Merged by Bors] - Support monitor selection for all window modes. #5878

Closed
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion crates/bevy_window/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ pub mod prelude {
#[doc(hidden)]
pub use crate::{
CursorEntered, CursorIcon, CursorLeft, CursorMoved, FileDragAndDrop, MonitorSelection,
ReceivedCharacter, Window, WindowDescriptor, WindowMoved, WindowPosition, Windows,
ReceivedCharacter, Window, WindowDescriptor, WindowMode, WindowMoved, WindowPosition,
Windows,
};
}

Expand Down
23 changes: 15 additions & 8 deletions crates/bevy_window/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -747,27 +747,27 @@ impl Window {
/// Defines where window should be placed at on creation.
#[derive(Debug, Clone, Copy)]
pub enum WindowPosition {
/// Position will be set by the window manager
/// The position will be set by the window manager.
Automatic,
/// Window will be centered on the selected monitor
/// Window will be centered on the selected monitor.
tim-blackbird marked this conversation as resolved.
Show resolved Hide resolved
Centered,
/// The window's top-left corner will be placed at the specified position (in pixels).
///
/// Note that this does not account for window decorations.
Centered(MonitorSelection),
/// The window's top-left corner will be placed at the specified position (in pixels)
///
/// (0,0) represents top-left corner of screen space.
/// (0,0) represents top-left corner of the selected monitor.
Copy link
Member

@mockersf mockersf Sep 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these two lines feels a lot redundant (and miss how to specify the selected monitor)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

window's top-left corner and top-left corner of the monitor are not redundant.

At(Vec2),
}

/// Defines which monitor to use.
#[derive(Debug, Clone, Copy)]
pub enum MonitorSelection {
/// Uses current monitor of the window.
///
/// Will fall back to the system default if the window has not yet been created.
Current,
/// Uses primary monitor of the system.
Primary,
/// Uses monitor with the specified index.
Number(usize),
Index(usize),
}

/// Describes the information needed for creating a window.
Expand All @@ -789,7 +789,13 @@ pub struct WindowDescriptor {
/// May vary from the physical height due to different pixel density on different monitors.
pub height: f32,
/// The position on the screen that the window will be placed at.
///
/// Ignored if `mode` is set to something other than [`WindowMode::Windowed`]
///
/// `WindowPosition::Automatic` will be overridden with `WindowPosition::At(Vec2::ZERO)` if a specific `monitor` is selected.
pub position: WindowPosition,
/// The monitor to place the window on.
pub monitor: MonitorSelection,
/// Sets minimum and maximum resize limits.
pub resize_constraints: WindowResizeConstraints,
/// Overrides the window's ratio of physical pixels to logical pixels.
Expand Down Expand Up @@ -854,6 +860,7 @@ impl Default for WindowDescriptor {
width: 1280.,
height: 720.,
position: WindowPosition::Automatic,
monitor: MonitorSelection::Current,
resize_constraints: WindowResizeConstraints::default(),
scale_factor_override: None,
present_mode: PresentMode::Fifo,
Expand Down
32 changes: 16 additions & 16 deletions crates/bevy_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use bevy_input::{
mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel},
touch::TouchInput,
};
use bevy_math::{ivec2, DVec2, UVec2, Vec2};
use bevy_math::{ivec2, DVec2, IVec2, UVec2, Vec2};
use bevy_utils::{
tracing::{error, info, trace, warn},
Instant,
Expand All @@ -31,7 +31,7 @@ use bevy_window::{
};

use winit::{
dpi::{LogicalSize, PhysicalPosition},
dpi::{LogicalPosition, LogicalSize, PhysicalPosition},
event::{self, DeviceEvent, Event, StartCause, WindowEvent},
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
};
Expand Down Expand Up @@ -149,7 +149,7 @@ fn change_window(
let window = winit_windows.get_window(id).unwrap();
let inner_size = window.inner_size().to_logical::<f32>(window.scale_factor());
window
.set_cursor_position(winit::dpi::LogicalPosition::new(
.set_cursor_position(LogicalPosition::new(
position.x,
inner_size.height - position.y,
))
Expand All @@ -163,12 +163,11 @@ fn change_window(
let window = winit_windows.get_window(id).unwrap();
window.set_minimized(minimized);
}
bevy_window::WindowCommand::SetPosition { position } => {
bevy_window::WindowCommand::SetPosition {
position: IVec2 { x, y },
} => {
let window = winit_windows.get_window(id).unwrap();
window.set_outer_position(PhysicalPosition {
x: position[0],
y: position[1],
});
window.set_outer_position(PhysicalPosition { x, y });
}
bevy_window::WindowCommand::Center(monitor_selection) => {
let window = winit_windows.get_window(id).unwrap();
Expand All @@ -177,19 +176,20 @@ fn change_window(
let maybe_monitor = match monitor_selection {
Current => window.current_monitor(),
Primary => window.primary_monitor(),
Number(n) => window.available_monitors().nth(n),
Index(i) => window.available_monitors().nth(i),
};

if let Some(monitor) = maybe_monitor {
let screen_size = monitor.size();
let monitor_size = monitor.size();
let monitor_position = monitor.position().cast::<f64>();

let window_size = window.outer_size();

window.set_outer_position(PhysicalPosition {
x: screen_size.width.saturating_sub(window_size.width) as f64 / 2.
+ monitor.position().x as f64,
y: screen_size.height.saturating_sub(window_size.height) as f64 / 2.
+ monitor.position().y as f64,
x: monitor_size.width.saturating_sub(window_size.width) as f64 / 2.
+ monitor_position.x,
y: monitor_size.height.saturating_sub(window_size.height) as f64 / 2.
+ monitor_position.y,
});
} else {
warn!("Couldn't get monitor selected with: {monitor_selection:?}");
Expand Down Expand Up @@ -578,12 +578,12 @@ pub fn winit_runner_with(mut app: App) {
}
}
event::Event::DeviceEvent {
event: DeviceEvent::MouseMotion { delta },
event: DeviceEvent::MouseMotion { delta: (x, y) },
..
} => {
let mut mouse_motion_events = app.world.resource_mut::<Events<MouseMotion>>();
mouse_motion_events.send(MouseMotion {
delta: Vec2::new(delta.0 as f32, delta.1 as f32),
delta: DVec2 { x, y }.as_vec2(),
});
}
event::Event::Suspended => {
Expand Down
151 changes: 77 additions & 74 deletions crates/bevy_winit/src/winit_windows.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use bevy_math::IVec2;
use bevy_utils::{tracing::warn, HashMap};
use bevy_window::{Window, WindowDescriptor, WindowId, WindowMode};
use bevy_math::{DVec2, IVec2};
use bevy_utils::HashMap;
use bevy_window::{MonitorSelection, Window, WindowDescriptor, WindowId, WindowMode};
use raw_window_handle::HasRawWindowHandle;
use winit::dpi::{LogicalPosition, LogicalSize, PhysicalPosition};
use winit::{
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize},
window::Fullscreen,
};

#[derive(Debug, Default)]
pub struct WinitWindows {
Expand All @@ -24,86 +27,43 @@ impl WinitWindows {
) -> Window {
let mut winit_window_builder = winit::window::WindowBuilder::new();

let &WindowDescriptor {
width,
height,
position,
monitor,
scale_factor_override,
..
} = window_descriptor;

let logical_size = LogicalSize::new(width, height);

let monitor = match monitor {
MonitorSelection::Current => None,
MonitorSelection::Primary => event_loop.primary_monitor(),
MonitorSelection::Index(i) => event_loop.available_monitors().nth(i),
};

let selected_or_primary_monitor = monitor.clone().or_else(|| event_loop.primary_monitor());

winit_window_builder = match window_descriptor.mode {
WindowMode::BorderlessFullscreen => winit_window_builder.with_fullscreen(Some(
winit::window::Fullscreen::Borderless(event_loop.primary_monitor()),
WindowMode::BorderlessFullscreen => winit_window_builder
.with_fullscreen(Some(Fullscreen::Borderless(selected_or_primary_monitor))),
WindowMode::Fullscreen => winit_window_builder.with_fullscreen(Some(
Fullscreen::Exclusive(get_best_videomode(&selected_or_primary_monitor.unwrap())),
)),
WindowMode::Fullscreen => {
winit_window_builder.with_fullscreen(Some(winit::window::Fullscreen::Exclusive(
get_best_videomode(&event_loop.primary_monitor().unwrap()),
)))
}
WindowMode::SizedFullscreen => winit_window_builder.with_fullscreen(Some(
winit::window::Fullscreen::Exclusive(get_fitting_videomode(
&event_loop.primary_monitor().unwrap(),
Fullscreen::Exclusive(get_fitting_videomode(
&selected_or_primary_monitor.unwrap(),
window_descriptor.width as u32,
window_descriptor.height as u32,
)),
)),
_ => {
let WindowDescriptor {
width,
height,
position,
scale_factor_override,
..
} = window_descriptor;

use bevy_window::WindowPosition::*;
match position {
Automatic => { /* Window manager will handle position */ }
Centered(monitor_selection) => {
use bevy_window::MonitorSelection::*;
let maybe_monitor = match monitor_selection {
Current => {
warn!("Can't select current monitor on window creation!");
None
}
Primary => event_loop.primary_monitor(),
Number(n) => event_loop.available_monitors().nth(*n),
};

if let Some(monitor) = maybe_monitor {
let screen_size = monitor.size();

let scale_factor = monitor.scale_factor();

// Logical to physical window size
let (width, height): (u32, u32) = LogicalSize::new(*width, *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,
};

winit_window_builder = winit_window_builder.with_position(position);
} else {
warn!("Couldn't get monitor selected with: {monitor_selection:?}");
}
}
At(position) => {
if let Some(sf) = scale_factor_override {
winit_window_builder = winit_window_builder.with_position(
LogicalPosition::new(position[0] as f64, position[1] as f64)
.to_physical::<f64>(*sf),
);
} else {
winit_window_builder = winit_window_builder.with_position(
LogicalPosition::new(position[0] as f64, position[1] as f64),
);
}
}
}

if let Some(sf) = scale_factor_override {
winit_window_builder
.with_inner_size(LogicalSize::new(*width, *height).to_physical::<f64>(*sf))
winit_window_builder.with_inner_size(logical_size.to_physical::<f64>(sf))
} else {
winit_window_builder.with_inner_size(LogicalSize::new(*width, *height))
winit_window_builder.with_inner_size(logical_size)
}
}
.with_resizable(window_descriptor.resizable)
Expand Down Expand Up @@ -155,6 +115,49 @@ impl WinitWindows {

let winit_window = winit_window_builder.build(event_loop).unwrap();

if window_descriptor.mode == WindowMode::Windowed {
use bevy_window::WindowPosition::*;
match position {
Automatic => {
if let Some(monitor) = monitor {
winit_window.set_outer_position(monitor.position());
}
}
Centered => {
if let Some(monitor) = monitor.or_else(|| winit_window.current_monitor()) {
let monitor_position = monitor.position().cast::<f64>();
let size = monitor.size();

// Logical to physical window size
let PhysicalSize::<u32> { width, height } =
logical_size.to_physical(monitor.scale_factor());

let position = PhysicalPosition {
x: size.width.saturating_sub(width) as f64 / 2. + monitor_position.x,
y: size.height.saturating_sub(height) as f64 / 2. + monitor_position.y,
};

winit_window.set_outer_position(position);
}
}
At(position) => {
if let Some(monitor) = monitor.or_else(|| winit_window.current_monitor()) {
let monitor_position = DVec2::from(<(_, _)>::from(monitor.position()));
let position = monitor_position + position.as_dvec2();

if let Some(sf) = scale_factor_override {
winit_window.set_outer_position(
LogicalPosition::new(position.x, position.y).to_physical::<f64>(sf),
);
} else {
winit_window
.set_outer_position(LogicalPosition::new(position.x, position.y));
}
}
}
}
}

if window_descriptor.cursor_locked {
match winit_window.set_cursor_grab(true) {
Ok(_) | Err(winit::error::ExternalError::NotSupported(_)) => {}
Expand Down