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

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

Merged
merged 13 commits into from
Nov 29, 2022
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre

# Unreleased

- On Windows and MacOS, add API to enable/disable window buttons (close, minimize, ...etc).
- On Windows and macOS, add `Window::title` to query the current window title.
- On Windows, fix focusing menubar when pressing `Alt`.
- On MacOS, made `accepts_first_mouse` configurable.
Expand Down
8 changes: 7 additions & 1 deletion src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
error,
event::{self, VirtualKeyCode},
event_loop::{self, ControlFlow},
window::{self, CursorGrabMode, Theme},
window::{self, CursorGrabMode, Theme, WindowButtons},
};

static CONFIG: Lazy<RwLock<Configuration>> = Lazy::new(|| {
Expand Down Expand Up @@ -771,6 +771,12 @@ impl Window {
false
}

pub fn set_enabled_buttons(&self, _buttons: WindowButtons) {}

pub fn enabled_buttons(&self) -> WindowButtons {
WindowButtons::all()
}

pub fn set_minimized(&self, _minimized: bool) {}

pub fn set_maximized(&self, _maximized: bool) {}
Expand Down
13 changes: 12 additions & 1 deletion src/platform_impl/ios/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
monitor, view, EventLoopWindowTarget, Fullscreen, MonitorHandle,
},
window::{
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes,
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes, WindowButtons,
WindowId as RootWindowId,
},
};
Expand Down Expand Up @@ -172,6 +172,17 @@ impl Inner {
false
}

#[inline]
pub fn set_enabled_buttons(&self, _buttons: WindowButtons) {
warn!("`Window::set_enabled_buttons` is ignored on iOS");
}

#[inline]
pub fn enabled_buttons(&self) -> WindowButtons {
warn!("`Window::enabled_buttons` is ignored on iOS");
WindowButtons::all()
}

pub fn scale_factor(&self) -> f64 {
unsafe {
let hidpi: CGFloat = msg_send![self.view, contentScaleFactor];
Expand Down
14 changes: 13 additions & 1 deletion src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ use crate::{
ControlFlow, DeviceEventFilter, EventLoopClosed, EventLoopWindowTarget as RootELW,
},
icon::Icon,
window::{CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes},
window::{
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes, WindowButtons,
},
};

pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
Expand Down Expand Up @@ -405,6 +407,16 @@ impl Window {
x11_or_wayland!(match self; Window(w) => w.is_resizable())
}

#[inline]
pub fn set_enabled_buttons(&self, buttons: WindowButtons) {
x11_or_wayland!(match self; Window(w) => w.set_enabled_buttons(buttons))
}

#[inline]
pub fn enabled_buttons(&self) -> WindowButtons {
x11_or_wayland!(match self; Window(w) => w.enabled_buttons())
}

#[inline]
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
x11_or_wayland!(match self; Window(w) => w.set_cursor_icon(cursor))
Expand Down
12 changes: 11 additions & 1 deletion src/platform_impl/linux/wayland/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ use crate::platform_impl::{
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError,
PlatformSpecificWindowBuilderAttributes as PlatformAttributes,
};
use crate::window::{CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes};
use crate::window::{
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes, WindowButtons,
};

use super::env::WindowingFeatures;
use super::event_loop::WinitState;
Expand Down Expand Up @@ -421,6 +423,14 @@ impl Window {
self.resizeable.load(Ordering::Relaxed)
}

#[inline]
pub fn set_enabled_buttons(&self, _buttons: WindowButtons) {}

#[inline]
pub fn enabled_buttons(&self) -> WindowButtons {
WindowButtons::all()
}

#[inline]
pub fn scale_factor(&self) -> u32 {
// The scale factor from `get_surface_scale_factor` is always greater than zero, so
Expand Down
12 changes: 11 additions & 1 deletion src/platform_impl/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ use crate::{
Fullscreen, MonitorHandle as PlatformMonitorHandle, OsError,
PlatformSpecificWindowBuilderAttributes, VideoMode as PlatformVideoMode,
},
window::{CursorGrabMode, CursorIcon, Icon, Theme, UserAttentionType, WindowAttributes},
window::{
CursorGrabMode, CursorIcon, Icon, Theme, UserAttentionType, WindowAttributes, WindowButtons,
},
};

use super::{
Expand Down Expand Up @@ -1258,6 +1260,14 @@ impl UnownedWindow {
self.shared_state_lock().is_resizable
}

#[inline]
pub fn set_enabled_buttons(&self, _buttons: WindowButtons) {}

#[inline]
pub fn enabled_buttons(&self) -> WindowButtons {
WindowButtons::all()
}

#[inline]
pub fn xlib_display(&self) -> *mut c_void {
self.xconn.display as _
Expand Down
12 changes: 11 additions & 1 deletion src/platform_impl/macos/appkit/control.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use objc2::foundation::NSObject;
use objc2::{extern_class, ClassType};
use objc2::{extern_class, extern_methods, ClassType};

use super::{NSResponder, NSView};

Expand All @@ -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;
}
);
6 changes: 6 additions & 0 deletions src/platform_impl/macos/appkit/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,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;

Expand Down
58 changes: 57 additions & 1 deletion src/platform_impl/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::{
Fullscreen, OsError,
},
window::{
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes,
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes, WindowButtons,
WindowId as RootWindowId,
},
};
Expand Down Expand Up @@ -267,6 +267,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;
}
Expand Down Expand Up @@ -331,6 +339,12 @@ impl WinitWindow {
this.setLevel(NSWindowLevel::Floating);
}

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);
Expand Down Expand Up @@ -620,6 +634,48 @@ 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;
}

self.set_style_mask_async(mask);

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();
Expand Down
11 changes: 10 additions & 1 deletion src/platform_impl/web/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use crate::error::{ExternalError, NotSupportedError, OsError as RootOE};
use crate::event;
use crate::icon::Icon;
use crate::window::{
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes, WindowId as RootWI,
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes, WindowButtons,
WindowId as RootWI,
};

use raw_window_handle::{RawDisplayHandle, RawWindowHandle, WebDisplayHandle, WebWindowHandle};
Expand Down Expand Up @@ -171,6 +172,14 @@ impl Window {
true
}

#[inline]
pub fn set_enabled_buttons(&self, _buttons: WindowButtons) {}

#[inline]
pub fn enabled_buttons(&self) -> WindowButtons {
WindowButtons::all()
}

#[inline]
pub fn scale_factor(&self) -> f64 {
super::backend::scale_factor()
Expand Down
47 changes: 46 additions & 1 deletion src/platform_impl/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ use crate::{
window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState},
Fullscreen, Parent, PlatformSpecificWindowBuilderAttributes, WindowId,
},
window::{CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes},
window::{
CursorGrabMode, CursorIcon, Theme, UserAttentionType, WindowAttributes, WindowButtons,
},
};

/// The Win32 implementation of the main `Window` object.
Expand Down Expand Up @@ -262,6 +264,44 @@ impl Window {
window_state.window_flags.contains(WindowFlags::RESIZABLE)
}

#[inline]
pub fn set_enabled_buttons(&self, buttons: WindowButtons) {
let window = self.window.clone();
let window_state = Arc::clone(&self.window_state);

self.thread_executor.execute_in_thread(move || {
let _ = &window;
WindowState::set_window_flags(window_state.lock().unwrap(), window.0, |f| {
f.set(
WindowFlags::MINIMIZABLE,
buttons.contains(WindowButtons::MINIMIZE),
);
f.set(
WindowFlags::MAXIMIZABLE,
buttons.contains(WindowButtons::MAXIMIZE),
);
f.set(
WindowFlags::CLOSABLE,
buttons.contains(WindowButtons::CLOSE),
)
});
});
}

pub fn enabled_buttons(&self) -> WindowButtons {
let mut buttons = WindowButtons::empty();
let window_state = self.window_state_lock();
if window_state.window_flags.contains(WindowFlags::MINIMIZABLE) {
buttons |= WindowButtons::MINIMIZE;
}
if window_state.window_flags.contains(WindowFlags::MAXIMIZABLE) {
buttons |= WindowButtons::MAXIMIZE;
}
if window_state.window_flags.contains(WindowFlags::CLOSABLE) {
buttons |= WindowButtons::CLOSE;
}
buttons
}
/// Returns the `hwnd` of this window.
#[inline]
pub fn hwnd(&self) -> HWND {
Expand Down Expand Up @@ -911,6 +951,8 @@ impl<'a, T: 'static> InitData<'a, T> {
// attribute is correctly applied.
win.set_visible(attributes.visible);

win.set_enabled_buttons(attributes.enabled_buttons);

if attributes.fullscreen.is_some() {
win.set_fullscreen(attributes.fullscreen);
force_window_active(win.window.0);
Expand Down Expand Up @@ -973,6 +1015,9 @@ where
window_flags.set(WindowFlags::TRANSPARENT, attributes.transparent);
// WindowFlags::VISIBLE and MAXIMIZED are set down below after the window has been configured.
window_flags.set(WindowFlags::RESIZABLE, attributes.resizable);
// Will be changed later using `window.set_enabled_buttons` but we need to set a default here
// so the diffing later can work
window_flags.set(WindowFlags::CLOSABLE, true);

let parent = match pl_attribs.parent {
Parent::ChildOf(parent) => {
Expand Down
Loading