On Windows and macOS, add API to enable/disable window controls (#2537)

* On Windows and macOS, add API to enable/disable window controls

* fix build

* missing import

* use `WindowButtons` flags

* rename to `[set_]enabled_buttons`

* add example, fix windows impl for minimize

* macOS: Fix button enabling close/minimize while disabling maximized

* Update src/platform_impl/windows/window.rs

Co-authored-by: Kirill Chibisov <contact@kchibisov.com>

* compose the flags on a sep line, use `bool::then`

Co-authored-by: Mads Marquart <mads@marquart.dk>
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
This commit is contained in:
Amr Bashir 2022-11-29 12:03:51 +02:00 committed by GitHub
parent 28e34c2e1b
commit 94688a62f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 343 additions and 36 deletions

View file

@ -1,5 +1,5 @@
use objc2::foundation::NSObject;
use objc2::{extern_class, ClassType};
use objc2::{extern_class, extern_methods, ClassType};
use super::{NSResponder, NSView};
@ -12,3 +12,13 @@ extern_class!(
type Super = NSView;
}
);
extern_methods!(
unsafe impl NSControl {
#[sel(setEnabled:)]
pub fn setEnabled(&self, enabled: bool);
#[sel(isEnabled)]
pub fn isEnabled(&self) -> bool;
}
);

View file

@ -180,6 +180,12 @@ extern_methods!(
#[sel(isResizable)]
pub fn isResizable(&self) -> bool;
#[sel(isMiniaturizable)]
pub fn isMiniaturizable(&self) -> bool;
#[sel(hasCloseBox)]
pub fn hasCloseBox(&self) -> bool;
#[sel(isMiniaturized)]
pub fn isMiniaturized(&self) -> bool;

View file

@ -29,7 +29,7 @@ use crate::{
Fullscreen, OsError,
},
window::{
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes,
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes, WindowButtons,
WindowId as RootWindowId, WindowLevel,
},
};
@ -269,6 +269,14 @@ impl WinitWindow {
masks &= !NSWindowStyleMask::NSResizableWindowMask;
}
if !attrs.enabled_buttons.contains(WindowButtons::MINIMIZE) {
masks &= !NSWindowStyleMask::NSMiniaturizableWindowMask;
}
if !attrs.enabled_buttons.contains(WindowButtons::CLOSE) {
masks &= !NSWindowStyleMask::NSClosableWindowMask;
}
if pl_attrs.fullsize_content_view {
masks |= NSWindowStyleMask::NSFullSizeContentViewWindowMask;
}
@ -333,6 +341,12 @@ impl WinitWindow {
this.setMovableByWindowBackground(true);
}
if !attrs.enabled_buttons.contains(WindowButtons::MAXIMIZE) {
if let Some(button) = this.standardWindowButton(NSWindowButton::Zoom) {
button.setEnabled(false);
}
}
if let Some(increments) = attrs.resize_increments {
let increments = increments.to_logical(this.scale_factor());
let (w, h) = (increments.width, increments.height);
@ -624,6 +638,53 @@ impl WinitWindow {
self.isResizable()
}
#[inline]
pub fn set_enabled_buttons(&self, buttons: WindowButtons) {
let mut mask = self.styleMask();
if buttons.contains(WindowButtons::CLOSE) {
mask |= NSWindowStyleMask::NSClosableWindowMask;
} else {
mask &= !NSWindowStyleMask::NSClosableWindowMask;
}
if buttons.contains(WindowButtons::MINIMIZE) {
mask |= NSWindowStyleMask::NSMiniaturizableWindowMask;
} else {
mask &= !NSWindowStyleMask::NSMiniaturizableWindowMask;
}
// This must happen before the button's "enabled" status has been set,
// hence we do it synchronously.
self.set_style_mask_sync(mask);
// We edit the button directly instead of using `NSResizableWindowMask`,
// since that mask also affect the resizability of the window (which is
// controllable by other means in `winit`).
if let Some(button) = self.standardWindowButton(NSWindowButton::Zoom) {
button.setEnabled(buttons.contains(WindowButtons::MAXIMIZE));
}
}
#[inline]
pub fn enabled_buttons(&self) -> WindowButtons {
let mut buttons = WindowButtons::empty();
if self.isMiniaturizable() {
buttons |= WindowButtons::MINIMIZE;
}
if self
.standardWindowButton(NSWindowButton::Zoom)
.map(|b| b.isEnabled())
.unwrap_or(true)
{
buttons |= WindowButtons::MAXIMIZE;
}
if self.hasCloseBox() {
buttons |= WindowButtons::CLOSE;
}
buttons
}
pub fn set_cursor_icon(&self, icon: CursorIcon) {
let view = self.view();
let mut cursor_state = view.state.cursor_state.lock().unwrap();