Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
985fe0d
Add exclusive fullscreen mode
aleksijuvani Jun 15, 2019
3dd7184
Add `WindowExtMacOS::set_fullscreen_presentation_options`
aleksijuvani Jun 17, 2019
bbd88af
Capture display for exclusive fullscreen on macOS
aleksijuvani Jun 17, 2019
cfed2f3
Fix applying video mode on macOS after a fullscreen cycle
aleksijuvani Jun 17, 2019
047c017
Fix compilation on iOS
aleksijuvani Jun 18, 2019
e293bd7
Set monitor appropriately for fullscreen on macOS
aleksijuvani Jun 18, 2019
372056e
Fix exclusive to borderless fullscreen transitions on macOS
aleksijuvani Jun 18, 2019
0f136ef
Fix borderless to exclusive fullscreen transition on macOS
aleksijuvani Jun 19, 2019
ba7a653
Sort video modes on Windows
aleksijuvani Jun 21, 2019
f00b10f
Fix fullscreen issues on Windows
aleksijuvani Jun 21, 2019
471e14b
Fix video mode changes during exclusive fullscreen on Windows
aleksijuvani Jun 22, 2019
6007e14
Add video mode sorting for macOS and iOS
aleksijuvani Jun 22, 2019
809e4ea
Fix monitor `ns_screen` returning `None` after video mode change
aleksijuvani Jun 22, 2019
f419c6d
Fix "multithreaded" example on macOS
aleksijuvani Jun 22, 2019
e4ee11c
Restore video mode upon closing an exclusive fullscreen window
aleksijuvani Jun 22, 2019
68b7258
Fix "multithreaded" example closing multiple windows at once
aleksijuvani Jun 22, 2019
dcfc9f0
Fix compilation on Linux
aleksijuvani Jun 23, 2019
5be964e
Update FEATURES.md
aleksijuvani Jun 23, 2019
f3e4624
Don't care about logical monitor groups on X11
aleksijuvani Jun 25, 2019
d1e13ee
Add exclusive fullscreen for X11
aleksijuvani Jun 25, 2019
890643c
Update FEATURES.md
aleksijuvani Jun 25, 2019
7930620
Fix transitions between exclusive and borderless fullscreen on X11
aleksijuvani Jun 25, 2019
f956199
Update CHANGELOG.md
aleksijuvani Jun 25, 2019
8b8a045
Document that Wayland doesn't support exclusive fullscreen
aleksijuvani Jun 25, 2019
b6eb841
Replace core-graphics display mode bindings on macOS
aleksijuvani Jun 26, 2019
9492f65
Use `panic!()` instead of `unreachable!()` in "fullscreen" example
aleksijuvani Jun 28, 2019
796cd07
Fix fullscreen "always on top" flag on Windows
aleksijuvani Jun 28, 2019
a7db552
Track current monitor for fullscreen in "multithreaded" example
aleksijuvani Jun 28, 2019
81bbd31
Fix exclusive fullscreen sometimes not positioning window properly
Osspial Jul 22, 2019
de8bfdc
Merge branch 'master' into exclusive-fullscreen
Osspial Jul 22, 2019
b597634
Format
Osspial Jul 22, 2019
cd61cc0
More formatting and fix CI issues
Osspial Jul 23, 2019
28f7315
Fix formatting
aleksijuvani Jul 26, 2019
d739fb9
Merge branch 'master' into exclusive-fullscreen
Osspial Jul 29, 2019
3737228
Merge branch 'exclusive-fullscreen' of https://github.com/aleksijuvan…
Osspial Jul 29, 2019
f17b74c
Fix changelog formatting
Osspial Jul 29, 2019
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# Unreleased

- On macOS, drop the run closure on exit.
- On Windows, location of `WindowEvent::Touch` are window client coordinates instead of screen coordinates.
- On X11, fix delayed events after window redraw.
- On macOS, add `WindowBuilderExt::with_disallow_hidpi` to have the option to turn off best resolution openGL surface.
- On Windows, screen saver won't start if the window is in fullscreen mode.
- Change all occurrences of the `new_user_event` method to `with_user_event`.
- On macOS, the dock and the menu bar are now hidden in fullscreen mode.
- `Window::set_fullscreen` now takes `Option<Fullscreen>` where `Fullscreen`
consists of `Fullscreen::Exclusive(VideoMode)` and
`Fullscreen::Borderless(MonitorHandle)` variants.
- Adds support for exclusive fullscreen mode.

# 0.20.0 Alpha 2 (2019-07-09)

Expand Down
4 changes: 4 additions & 0 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ If your PR makes notable changes to Winit's features, please update this section
- **Fullscreen**: The windows created by winit can be put into fullscreen mode.
- **Fullscreen toggle**: The windows created by winit can be switched to and from fullscreen after
creation.
- **Exclusive fullscreen**: Winit allows changing the video mode of the monitor
for fullscreen windows, and if applicable, captures the monitor for exclusive
use by this application.
- **HiDPI support**: Winit assists developers in appropriately scaling HiDPI content.
- **Popup / modal windows**: Windows can be created relative to the client area of other windows, and parent
windows can be disabled in favor of popup windows. This feature also guarantees that popup windows
Expand Down Expand Up @@ -157,6 +160,7 @@ Legend:
|Window maximization toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A** |
|Fullscreen |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|❌ |
|Fullscreen toggle |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|❌ |
|Exclusive fullscreen |✔️ |✔️ |✔️ |**N/A** |❌ |❌ |❌ |
|HiDPI support |✔️ |✔️ |✔️ |✔️ |▢[#721]|✔️ |✔️ |
|Popup windows |❌ |❌ |❌ |❌ |❌ |❌ |❌ |

Expand Down
105 changes: 42 additions & 63 deletions examples/fullscreen.rs
Original file line number Diff line number Diff line change
@@ -1,56 +1,35 @@
use std::io::{self, Write};
use winit::{
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::{ControlFlow, EventLoop},
monitor::MonitorHandle,
window::WindowBuilder,
};
use std::io::{stdin, stdout, Write};
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::monitor::{MonitorHandle, VideoMode};
use winit::window::{Fullscreen, WindowBuilder};

fn main() {
let event_loop = EventLoop::new();

#[cfg(target_os = "macos")]
let mut macos_use_simple_fullscreen = false;

let monitor = {
// On macOS there are two fullscreen modes "native" and "simple"
#[cfg(target_os = "macos")]
{
print!("Please choose the fullscreen mode: (1) native, (2) simple: ");
io::stdout().flush().unwrap();

let mut num = String::new();
io::stdin().read_line(&mut num).unwrap();
let num = num.trim().parse().ok().expect("Please enter a number");
match num {
2 => macos_use_simple_fullscreen = true,
_ => {}
}

// Prompt for monitor when using native fullscreen
if !macos_use_simple_fullscreen {
Some(prompt_for_monitor(&event_loop))
} else {
None
}
}
print!("Please choose the fullscreen mode: (1) exclusive, (2) borderless: ");
stdout().flush().unwrap();

#[cfg(not(target_os = "macos"))]
Some(prompt_for_monitor(&event_loop))
};
let mut num = String::new();
stdin().read_line(&mut num).unwrap();
let num = num.trim().parse().ok().expect("Please enter a number");

let fullscreen = Some(match num {
Comment thread
goddessfreya marked this conversation as resolved.
1 => Fullscreen::Exclusive(prompt_for_video_mode(&prompt_for_monitor(&event_loop))),
2 => Fullscreen::Borderless(prompt_for_monitor(&event_loop)),
_ => panic!("Please enter a valid number"),
});

let mut is_fullscreen = monitor.is_some();
let mut is_maximized = false;
let mut decorations = true;

let window = WindowBuilder::new()
.with_title("Hello world!")
.with_fullscreen(monitor)
.with_fullscreen(fullscreen.clone())
.build(&event_loop)
.unwrap();

event_loop.run(move |event, _, control_flow| {
println!("{:?}", event);
*control_flow = ControlFlow::Wait;

match event {
Expand All @@ -67,35 +46,14 @@ fn main() {
} => match (virtual_code, state) {
(VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit,
(VirtualKeyCode::F, ElementState::Pressed) => {
#[cfg(target_os = "macos")]
{
if macos_use_simple_fullscreen {
use winit::platform::macos::WindowExtMacOS;
if WindowExtMacOS::set_simple_fullscreen(&window, !is_fullscreen) {
is_fullscreen = !is_fullscreen;
}
return;
}
}

is_fullscreen = !is_fullscreen;
if !is_fullscreen {
if window.fullscreen().is_some() {
Comment thread
goddessfreya marked this conversation as resolved.
window.set_fullscreen(None);
} else {
window.set_fullscreen(Some(window.current_monitor()));
window.set_fullscreen(fullscreen.clone());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This needs to be using .current_monitor() so that it fullscreens on whatever monitor the window is on.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

If we want to use the current monitor here, I think we ought to re-query the video mode from the user as well. I would prefer for this to use whatever values were input by the user on start up, so that we don't have to worry about the monitor changing here.

}
}
(VirtualKeyCode::S, ElementState::Pressed) => {
println!("window.fullscreen {:?}", window.fullscreen());

#[cfg(target_os = "macos")]
{
use winit::platform::macos::WindowExtMacOS;
println!(
"window.simple_fullscreen {:?}",
WindowExtMacOS::simple_fullscreen(&window)
);
}
}
(VirtualKeyCode::M, ElementState::Pressed) => {
is_maximized = !is_maximized;
Expand All @@ -121,10 +79,10 @@ fn prompt_for_monitor(event_loop: &EventLoop<()>) -> MonitorHandle {
}

print!("Please write the number of the monitor to use: ");
io::stdout().flush().unwrap();
stdout().flush().unwrap();

let mut num = String::new();
io::stdin().read_line(&mut num).unwrap();
stdin().read_line(&mut num).unwrap();
let num = num.trim().parse().ok().expect("Please enter a number");
let monitor = event_loop
.available_monitors()
Expand All @@ -135,3 +93,24 @@ fn prompt_for_monitor(event_loop: &EventLoop<()>) -> MonitorHandle {

monitor
}

fn prompt_for_video_mode(monitor: &MonitorHandle) -> VideoMode {
for (i, video_mode) in monitor.video_modes().enumerate() {
println!("Video mode #{}: {}", i, video_mode);
}

print!("Please write the number of the video mode to use: ");
stdout().flush().unwrap();

let mut num = String::new();
stdin().read_line(&mut num).unwrap();
let num = num.trim().parse().ok().expect("Please enter a number");
let video_mode = monitor
.video_modes()
.nth(num)
.expect("Please enter a valid ID");

println!("Using {}", video_mode);

video_mode
}
50 changes: 46 additions & 4 deletions examples/multithreaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{collections::HashMap, sync::mpsc, thread, time::Duration};
use winit::{
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{CursorIcon, WindowBuilder},
window::{CursorIcon, Fullscreen, WindowBuilder},
};

const WINDOW_COUNT: usize = 3;
Expand All @@ -19,11 +19,34 @@ fn main() {
.with_inner_size(WINDOW_SIZE.into())
.build(&event_loop)
.unwrap();

let mut video_modes: Vec<_> = window.current_monitor().video_modes().collect();
let mut video_mode_id = 0usize;

let (tx, rx) = mpsc::channel();
window_senders.insert(window.id(), tx);
thread::spawn(move || {
while let Ok(event) = rx.recv() {
match event {
WindowEvent::Moved { .. } => {
// We need to update our chosen video mode if the window
// was moved to an another monitor, so that the window
// appears on this monitor instead when we go fullscreen
let previous_video_mode = video_modes.iter().cloned().nth(video_mode_id);
video_modes = window.current_monitor().video_modes().collect();
video_mode_id = video_mode_id.min(video_modes.len());
let video_mode = video_modes.iter().nth(video_mode_id);

// Different monitors may support different video modes,
// and the index we chose previously may now point to a
// completely different video mode, so notify the user
if video_mode != previous_video_mode.as_ref() {
println!(
"Window moved to another monitor, picked video mode: {}",
video_modes.iter().nth(video_mode_id).unwrap()
);
}
}
WindowEvent::KeyboardInput {
input:
KeyboardInput {
Expand All @@ -44,9 +67,26 @@ fn main() {
false => CursorIcon::Default,
}),
D => window.set_decorations(!state),
F => window.set_fullscreen(match state {
true => Some(window.current_monitor()),
false => None,
// Cycle through video modes
Right | Left => {
video_mode_id = match key {
Left => video_mode_id.saturating_sub(1),
Right => (video_modes.len() - 1).min(video_mode_id + 1),
_ => unreachable!(),
};
println!(
"Picking video mode: {}",
video_modes.iter().nth(video_mode_id).unwrap()
);
}
F => window.set_fullscreen(match (state, modifiers.alt) {
(true, false) => {
Some(Fullscreen::Borderless(window.current_monitor()))
}
(true, true) => Some(Fullscreen::Exclusive(
video_modes.iter().nth(video_mode_id).unwrap().clone(),
)),
(false, _) => None,
}),
G => window.set_cursor_grab(state).unwrap(),
H => window.set_cursor_visible(!state),
Expand All @@ -56,6 +96,7 @@ fn main() {
println!("-> inner_position : {:?}", window.inner_position());
println!("-> outer_size : {:?}", window.outer_size());
println!("-> inner_size : {:?}", window.inner_size());
println!("-> fullscreen : {:?}", window.fullscreen());
}
L => window.set_min_inner_size(match state {
true => Some(WINDOW_SIZE.into()),
Expand Down Expand Up @@ -108,6 +149,7 @@ fn main() {
| WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Released,
virtual_keycode: Some(VirtualKeyCode::Escape),
..
},
Expand Down
2 changes: 1 addition & 1 deletion examples/video_modes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ fn main() {
println!("Listing available video modes:");

for mode in monitor.video_modes() {
println!("{:?}", mode);
println!("{}", mode);
}
}
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ extern crate log;
#[macro_use]
extern crate serde;
#[macro_use]
#[cfg(target_os = "windows")]
extern crate derivative;
#[macro_use]
#[cfg(target_os = "windows")]
Expand Down
62 changes: 54 additions & 8 deletions src/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,41 @@ impl Iterator for AvailableMonitorsIter {
/// - [`MonitorHandle::video_modes`][monitor_get].
///
/// [monitor_get]: ../monitor/struct.MonitorHandle.html#method.video_modes
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[derive(Derivative)]
#[derivative(Clone, Debug = "transparent", PartialEq, Eq, Hash)]
pub struct VideoMode {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I realize this specific feedback would've been better-placed in the original PR, but it's only occurred to me now: is it possible to add a function to Monitor to retrieve the currently-active video mode? That way, applications can launch in fullscreen with the sensible default of whatever fullscreen settings the monitor currently has, instead of having to guess which mode to use.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Shouldn't be a problem, but I'm inclined to do this in a separate pull request since I will have to implement it for all four platforms. I think the borderless mode would suffice for a sensible default in any case.

pub(crate) size: (u32, u32),
pub(crate) bit_depth: u16,
pub(crate) refresh_rate: u16,
pub(crate) video_mode: platform_impl::VideoMode,
}

impl PartialOrd for VideoMode {
fn partial_cmp(&self, other: &VideoMode) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}

impl Ord for VideoMode {
fn cmp(&self, other: &VideoMode) -> std::cmp::Ordering {
// TODO: we can impl `Ord` for `PhysicalSize` once we switch from `f32`
// to `u32` there
let size: (u32, u32) = self.size().into();
Comment thread
goddessfreya marked this conversation as resolved.
let other_size: (u32, u32) = other.size().into();
self.monitor().cmp(&other.monitor()).then(
size.cmp(&other_size)
.then(
self.refresh_rate()
.cmp(&other.refresh_rate())
.then(self.bit_depth().cmp(&other.bit_depth())),
)
.reverse(),
)
}
}

impl VideoMode {
/// Returns the resolution of this video mode.
#[inline]
pub fn size(&self) -> PhysicalSize {
self.size.into()
self.video_mode.size()
}

/// Returns the bit depth of this video mode, as in how many bits you have
Expand All @@ -73,15 +97,37 @@ impl VideoMode {
///
/// - **Wayland:** Always returns 32.
/// - **iOS:** Always returns 32.
#[inline]
pub fn bit_depth(&self) -> u16 {
self.bit_depth
self.video_mode.bit_depth()
}

/// Returns the refresh rate of this video mode. **Note**: the returned
/// refresh rate is an integer approximation, and you shouldn't rely on this
/// value to be exact.
#[inline]
pub fn refresh_rate(&self) -> u16 {
self.refresh_rate
self.video_mode.refresh_rate()
}

/// Returns the monitor that this video mode is valid for. Each monitor has
/// a separate set of valid video modes.
#[inline]
pub fn monitor(&self) -> MonitorHandle {
self.video_mode.monitor()
}
}

impl std::fmt::Display for VideoMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}x{} @ {} Hz ({} bpp)",
self.size().width,
self.size().height,
self.refresh_rate(),
self.bit_depth()
)
}
}

Expand All @@ -90,7 +136,7 @@ impl VideoMode {
/// Allows you to retrieve information about a given monitor and can be used in [`Window`] creation.
///
/// [`Window`]: ../window/struct.Window.html
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct MonitorHandle {
pub(crate) inner: platform_impl::MonitorHandle,
}
Expand Down
2 changes: 1 addition & 1 deletion src/platform_impl/ios/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ use std::fmt;

pub use self::{
event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget},
monitor::MonitorHandle,
monitor::{MonitorHandle, VideoMode},
window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId},
};

Expand Down
Loading