Add exclusive fullscreen mode (#925)

* Add exclusive fullscreen mode

* Add `WindowExtMacOS::set_fullscreen_presentation_options`

* Capture display for exclusive fullscreen on macOS

* Fix applying video mode on macOS after a fullscreen cycle

* Fix compilation on iOS

* Set monitor appropriately for fullscreen on macOS

* Fix exclusive to borderless fullscreen transitions on macOS

* Fix borderless to exclusive fullscreen transition on macOS

* Sort video modes on Windows

* Fix fullscreen issues on Windows

* Fix video mode changes during exclusive fullscreen on Windows

* Add video mode sorting for macOS and iOS

* Fix monitor `ns_screen` returning `None` after video mode change

* Fix "multithreaded" example on macOS

* Restore video mode upon closing an exclusive fullscreen window

* Fix "multithreaded" example closing multiple windows at once

* Fix compilation on Linux

* Update FEATURES.md

* Don't care about logical monitor groups on X11

* Add exclusive fullscreen for X11

* Update FEATURES.md

* Fix transitions between exclusive and borderless fullscreen on X11

* Update CHANGELOG.md

* Document that Wayland doesn't support exclusive fullscreen

* Replace core-graphics display mode bindings on macOS

* Use `panic!()` instead of `unreachable!()` in "fullscreen" example

* Fix fullscreen "always on top" flag on Windows

* Track current monitor for fullscreen in "multithreaded" example

* Fix exclusive fullscreen sometimes not positioning window properly

* Format

* More formatting and fix CI issues

* Fix formatting

* Fix changelog formatting
This commit is contained in:
Aleksi Juvani 2019-07-29 21:16:14 +03:00 committed by Osspial
parent 131e67ddc1
commit 5bc3cf18d9
31 changed files with 1452 additions and 605 deletions

View file

@ -1,8 +1,7 @@
use crate::{
dpi::LogicalSize,
monitor::MonitorHandle,
platform_impl::platform::{event_loop, icon::WinIcon, util},
window::{CursorIcon, WindowAttributes},
window::{CursorIcon, Fullscreen, WindowAttributes},
};
use parking_lot::MutexGuard;
use std::{io, ptr};
@ -29,7 +28,7 @@ pub struct WindowState {
pub saved_window: Option<SavedWindow>,
pub dpi_factor: f64,
pub fullscreen: Option<MonitorHandle>,
pub fullscreen: Option<Fullscreen>,
/// Used to supress duplicate redraw attempts when calling `request_redraw` multiple
/// times in `EventsCleared`.
pub queued_out_of_band_redraw: bool,
@ -84,6 +83,7 @@ bitflags! {
WindowFlags::RESIZABLE.bits |
WindowFlags::MAXIMIZED.bits
);
const FULLSCREEN_OR_MASK = WindowFlags::ALWAYS_ON_TOP.bits;
const NO_DECORATIONS_AND_MASK = !WindowFlags::RESIZABLE.bits;
const INVISIBLE_AND_MASK = !WindowFlags::MAXIMIZED.bits;
}
@ -122,32 +122,16 @@ impl WindowState {
self.window_flags
}
pub fn set_window_flags<F>(
mut this: MutexGuard<'_, Self>,
window: HWND,
set_client_rect: Option<RECT>,
f: F,
) where
pub fn set_window_flags<F>(mut this: MutexGuard<'_, Self>, window: HWND, f: F)
where
F: FnOnce(&mut WindowFlags),
{
let old_flags = this.window_flags;
f(&mut this.window_flags);
let is_fullscreen = this.fullscreen.is_some();
this.window_flags
.set(WindowFlags::MARKER_FULLSCREEN, is_fullscreen);
let new_flags = this.window_flags;
drop(this);
old_flags.apply_diff(window, new_flags, set_client_rect);
}
pub fn refresh_window_state(
this: MutexGuard<'_, Self>,
window: HWND,
set_client_rect: Option<RECT>,
) {
Self::set_window_flags(this, window, set_client_rect, |_| ());
old_flags.apply_diff(window, new_flags);
}
pub fn set_window_flags_in_place<F>(&mut self, f: F)
@ -185,6 +169,7 @@ impl WindowFlags {
fn mask(mut self) -> WindowFlags {
if self.contains(WindowFlags::MARKER_FULLSCREEN) {
self &= WindowFlags::FULLSCREEN_AND_MASK;
self |= WindowFlags::FULLSCREEN_OR_MASK;
}
if !self.contains(WindowFlags::VISIBLE) {
self &= WindowFlags::INVISIBLE_AND_MASK;
@ -236,7 +221,7 @@ impl WindowFlags {
}
/// Adjust the window client rectangle to the return value, if present.
fn apply_diff(mut self, window: HWND, mut new: WindowFlags, set_client_rect: Option<RECT>) {
fn apply_diff(mut self, window: HWND, mut new: WindowFlags) {
self = self.mask();
new = new.mask();
@ -295,45 +280,20 @@ impl WindowFlags {
winuser::SetWindowLongW(window, winuser::GWL_STYLE, style as _);
winuser::SetWindowLongW(window, winuser::GWL_EXSTYLE, style_ex as _);
match set_client_rect
.and_then(|r| util::adjust_window_rect_with_styles(window, style, style_ex, r))
{
Some(client_rect) => {
let (x, y, w, h) = (
client_rect.left,
client_rect.top,
client_rect.right - client_rect.left,
client_rect.bottom - client_rect.top,
);
winuser::SetWindowPos(
window,
ptr::null_mut(),
x,
y,
w,
h,
winuser::SWP_NOZORDER
| winuser::SWP_FRAMECHANGED
| winuser::SWP_NOACTIVATE,
);
}
None => {
// Refresh the window frame.
winuser::SetWindowPos(
window,
ptr::null_mut(),
0,
0,
0,
0,
winuser::SWP_NOZORDER
| winuser::SWP_NOMOVE
| winuser::SWP_NOSIZE
| winuser::SWP_FRAMECHANGED
| winuser::SWP_NOACTIVATE,
);
}
let mut flags = winuser::SWP_NOZORDER
| winuser::SWP_NOMOVE
| winuser::SWP_NOSIZE
| winuser::SWP_FRAMECHANGED;
// We generally don't want style changes here to affect window
// focus, but for fullscreen windows they must be activated
// (i.e. focused) so that they appear on top of the taskbar
if !new.contains(WindowFlags::MARKER_FULLSCREEN) {
flags |= winuser::SWP_NOACTIVATE;
}
// Refresh the window frame
winuser::SetWindowPos(window, ptr::null_mut(), 0, 0, 0, 0, flags);
winuser::SendMessageW(window, *event_loop::SET_RETAIN_STATE_ON_SIZE_MSG_ID, 0, 0);
}
}