macOS: add option to explicitly hide menu/dock in Borderless (#3882)
This commit is contained in:
parent
9419e4e1a7
commit
d37c591378
3 changed files with 52 additions and 1 deletions
|
|
@ -63,6 +63,8 @@ changelog entry.
|
||||||
and `Serialize` on many types.
|
and `Serialize` on many types.
|
||||||
- Add `MonitorHandle::current_video_mode()`.
|
- Add `MonitorHandle::current_video_mode()`.
|
||||||
- Add basic iOS IME support. The soft keyboard can now be shown using `Window::set_ime_allowed`.
|
- Add basic iOS IME support. The soft keyboard can now be shown using `Window::set_ime_allowed`.
|
||||||
|
- On macOS, add `WindowExtMacOS::set_borderless_game` and `WindowAttributesExtMacOS::with_borderless_game`
|
||||||
|
to fully disable the menu bar and dock in Borderless Fullscreen as commonly done in games.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,12 @@ pub trait WindowExtMacOS {
|
||||||
|
|
||||||
/// Getter for the [`WindowExtMacOS::set_option_as_alt`].
|
/// Getter for the [`WindowExtMacOS::set_option_as_alt`].
|
||||||
fn option_as_alt(&self) -> OptionAsAlt;
|
fn option_as_alt(&self) -> OptionAsAlt;
|
||||||
|
|
||||||
|
/// Disable the Menu Bar and Dock in Borderless Fullscreen mode. Useful for games.
|
||||||
|
fn set_borderless_game(&self, borderless_game: bool);
|
||||||
|
|
||||||
|
/// Getter for the [`WindowExtMacOS::set_borderless_game`].
|
||||||
|
fn is_borderless_game(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowExtMacOS for dyn Window + '_ {
|
impl WindowExtMacOS for dyn Window + '_ {
|
||||||
|
|
@ -236,6 +242,18 @@ impl WindowExtMacOS for dyn Window + '_ {
|
||||||
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap();
|
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap();
|
||||||
window.maybe_wait_on_main(|w| w.option_as_alt())
|
window.maybe_wait_on_main(|w| w.option_as_alt())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_borderless_game(&self, borderless_game: bool) {
|
||||||
|
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap();
|
||||||
|
window.maybe_wait_on_main(|w| w.set_borderless_game(borderless_game))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_borderless_game(&self) -> bool {
|
||||||
|
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap();
|
||||||
|
window.maybe_wait_on_main(|w| w.is_borderless_game())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Corresponds to `NSApplicationActivationPolicy`.
|
/// Corresponds to `NSApplicationActivationPolicy`.
|
||||||
|
|
@ -287,6 +305,8 @@ pub trait WindowAttributesExtMacOS {
|
||||||
///
|
///
|
||||||
/// See [`WindowExtMacOS::set_option_as_alt`] for details on what this means if set.
|
/// See [`WindowExtMacOS::set_option_as_alt`] for details on what this means if set.
|
||||||
fn with_option_as_alt(self, option_as_alt: OptionAsAlt) -> Self;
|
fn with_option_as_alt(self, option_as_alt: OptionAsAlt) -> Self;
|
||||||
|
/// See [`WindowExtMacOS::set_borderless_game`] for details on what this means if set.
|
||||||
|
fn with_borderless_game(self, borderless_game: bool) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowAttributesExtMacOS for WindowAttributes {
|
impl WindowAttributesExtMacOS for WindowAttributes {
|
||||||
|
|
@ -355,6 +375,12 @@ impl WindowAttributesExtMacOS for WindowAttributes {
|
||||||
self.platform_specific.option_as_alt = option_as_alt;
|
self.platform_specific.option_as_alt = option_as_alt;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn with_borderless_game(mut self, borderless_game: bool) -> Self {
|
||||||
|
self.platform_specific.borderless_game = borderless_game;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait EventLoopBuilderExtMacOS {
|
pub trait EventLoopBuilderExtMacOS {
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ pub struct PlatformSpecificWindowAttributes {
|
||||||
pub accepts_first_mouse: bool,
|
pub accepts_first_mouse: bool,
|
||||||
pub tabbing_identifier: Option<String>,
|
pub tabbing_identifier: Option<String>,
|
||||||
pub option_as_alt: OptionAsAlt,
|
pub option_as_alt: OptionAsAlt,
|
||||||
|
pub borderless_game: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PlatformSpecificWindowAttributes {
|
impl Default for PlatformSpecificWindowAttributes {
|
||||||
|
|
@ -73,6 +74,7 @@ impl Default for PlatformSpecificWindowAttributes {
|
||||||
accepts_first_mouse: true,
|
accepts_first_mouse: true,
|
||||||
tabbing_identifier: None,
|
tabbing_identifier: None,
|
||||||
option_as_alt: Default::default(),
|
option_as_alt: Default::default(),
|
||||||
|
borderless_game: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -121,6 +123,7 @@ pub(crate) struct State {
|
||||||
standard_frame: Cell<Option<NSRect>>,
|
standard_frame: Cell<Option<NSRect>>,
|
||||||
is_simple_fullscreen: Cell<bool>,
|
is_simple_fullscreen: Cell<bool>,
|
||||||
saved_style: Cell<Option<NSWindowStyleMask>>,
|
saved_style: Cell<Option<NSWindowStyleMask>>,
|
||||||
|
is_borderless_game: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_class!(
|
declare_class!(
|
||||||
|
|
@ -731,6 +734,7 @@ impl WindowDelegate {
|
||||||
standard_frame: Cell::new(None),
|
standard_frame: Cell::new(None),
|
||||||
is_simple_fullscreen: Cell::new(false),
|
is_simple_fullscreen: Cell::new(false),
|
||||||
saved_style: Cell::new(None),
|
saved_style: Cell::new(None),
|
||||||
|
is_borderless_game: Cell::new(attrs.platform_specific.borderless_game),
|
||||||
});
|
});
|
||||||
let delegate: Retained<WindowDelegate> = unsafe { msg_send_id![super(delegate), init] };
|
let delegate: Retained<WindowDelegate> = unsafe { msg_send_id![super(delegate), init] };
|
||||||
|
|
||||||
|
|
@ -1417,7 +1421,7 @@ impl WindowDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
match (old_fullscreen, fullscreen) {
|
match (old_fullscreen, fullscreen) {
|
||||||
(None, Some(_)) => {
|
(None, Some(fullscreen)) => {
|
||||||
// `toggleFullScreen` doesn't work if the `StyleMask` is none, so we
|
// `toggleFullScreen` doesn't work if the `StyleMask` is none, so we
|
||||||
// set a normal style temporarily. The previous state will be
|
// set a normal style temporarily. The previous state will be
|
||||||
// restored in `WindowDelegate::window_did_exit_fullscreen`.
|
// restored in `WindowDelegate::window_did_exit_fullscreen`.
|
||||||
|
|
@ -1427,6 +1431,17 @@ impl WindowDelegate {
|
||||||
self.set_style_mask(required);
|
self.set_style_mask(required);
|
||||||
self.ivars().saved_style.set(Some(curr_mask));
|
self.ivars().saved_style.set(Some(curr_mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In borderless games, we want to disable the dock and menu bar
|
||||||
|
// by setting the presentation options. We do this here rather than in
|
||||||
|
// `window:willUseFullScreenPresentationOptions` because for some reason
|
||||||
|
// the menu bar remains interactable despite being hidden.
|
||||||
|
if self.is_borderless_game() && matches!(fullscreen, Fullscreen::Borderless(_)) {
|
||||||
|
let presentation_options = NSApplicationPresentationOptions::NSApplicationPresentationHideDock
|
||||||
|
| NSApplicationPresentationOptions::NSApplicationPresentationHideMenuBar;
|
||||||
|
app.setPresentationOptions(presentation_options);
|
||||||
|
}
|
||||||
|
|
||||||
toggle_fullscreen(self.window());
|
toggle_fullscreen(self.window());
|
||||||
},
|
},
|
||||||
(Some(Fullscreen::Borderless(_)), None) => {
|
(Some(Fullscreen::Borderless(_)), None) => {
|
||||||
|
|
@ -1813,6 +1828,14 @@ impl WindowExtMacOS for WindowDelegate {
|
||||||
fn option_as_alt(&self) -> OptionAsAlt {
|
fn option_as_alt(&self) -> OptionAsAlt {
|
||||||
self.view().option_as_alt()
|
self.view().option_as_alt()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_borderless_game(&self, borderless_game: bool) {
|
||||||
|
self.ivars().is_borderless_game.set(borderless_game);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_borderless_game(&self) -> bool {
|
||||||
|
self.ivars().is_borderless_game.get()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_STANDARD_FRAME: NSRect =
|
const DEFAULT_STANDARD_FRAME: NSRect =
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue