Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ jobs:
- { name: 'Redox OS', target: x86_64-unknown-redox, os: ubuntu-latest, }
- { name: 'macOS x86_64', target: x86_64-apple-darwin, os: macos-latest, }
- { name: 'macOS Aarch64', target: aarch64-apple-darwin, os: macos-latest, }
- { name: 'macOS Private APIs', target: aarch64-apple-darwin, os: macos-latest, options: '--package winit --features=private-apple-apis' }
- { name: 'iOS x86_64', target: x86_64-apple-ios, os: macos-latest, }
- { name: 'iOS Aarch64', target: aarch64-apple-ios, os: macos-latest, }
- { name: 'Web', target: wasm32-unknown-unknown, os: ubuntu-latest, }
Expand Down
3 changes: 2 additions & 1 deletion winit-appkit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ objc2-app-kit = { workspace = true, features = [
"NSTrackingArea",
"NSToolbar",
"NSView",
"NSVisualEffectView",
"NSWindow",
"NSWindowScripting",
"NSWindowTabGroup",
Expand Down Expand Up @@ -117,5 +118,5 @@ winit-common = { workspace = true, features = ["core-foundation", "event-handler
winit.workspace = true

[package.metadata.docs.rs]
all-features = true
features = ["serde"]
targets = ["aarch64-apple-darwin", "x86_64-apple-darwin"]
1 change: 1 addition & 0 deletions winit-appkit/src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ define_class!(
#[unsafe(super(NSView, NSResponder, NSObject))]
#[ivars = ViewState]
#[name = "WinitView"]
#[derive(Debug)]
pub(super) struct WinitView;

/// This documentation attribute makes rustfmt work for some reason?
Expand Down
91 changes: 73 additions & 18 deletions winit-appkit/src/window_delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,19 @@ use objc2::{
};
use objc2_app_kit::{
NSAppKitVersionNumber, NSAppKitVersionNumber10_12, NSAppearance, NSAppearanceCustomization,
NSAppearanceNameAqua, NSApplication, NSApplicationPresentationOptions, NSBackingStoreType,
NSColor, NSDragOperation, NSDraggingContext, NSDraggingDestination, NSDraggingInfo,
NSDraggingSession, NSDraggingSource, NSPasteboardTypeFileURL, NSPasteboardTypeHTML,
NSPasteboardTypePNG, NSPasteboardTypeSound, NSPasteboardTypeString, NSPasteboardTypeTIFF,
NSRequestUserAttentionType, NSScreen, NSToolbar, NSView, NSViewFrameDidChangeNotification,
NSWindow, NSWindowButton, NSWindowCollectionBehavior, NSWindowDelegate, NSWindowLevel,
NSWindowOcclusionState, NSWindowOrderingMode, NSWindowSharingType, NSWindowStyleMask,
NSWindowTabbingMode, NSWindowTitleVisibility, NSWindowToolbarStyle,
NSAppearanceNameAqua, NSApplication, NSApplicationPresentationOptions,
NSAutoresizingMaskOptions, NSBackingStoreType, NSColor, NSDragOperation, NSDraggingContext,
NSDraggingDestination, NSDraggingInfo, NSDraggingSession, NSDraggingSource,
NSPasteboardTypeFileURL, NSPasteboardTypeHTML, NSPasteboardTypePNG, NSPasteboardTypeSound,
NSPasteboardTypeString, NSPasteboardTypeTIFF, NSRequestUserAttentionType, NSScreen, NSToolbar,
NSView, NSViewFrameDidChangeNotification, NSWindow, NSWindowButton, NSWindowCollectionBehavior,
NSWindowDelegate, NSWindowLevel, NSWindowOcclusionState, NSWindowOrderingMode,
NSWindowSharingType, NSWindowStyleMask, NSWindowTabbingMode, NSWindowTitleVisibility,
NSWindowToolbarStyle,
};
#[cfg(not(feature = "private-apple-apis"))]
use objc2_app_kit::{
NSVisualEffectBlendingMode, NSVisualEffectMaterial, NSVisualEffectState, NSVisualEffectView,
};
use objc2_core_foundation::{CGFloat, CGPoint};
use objc2_core_graphics::{
Expand Down Expand Up @@ -74,6 +79,11 @@ pub(crate) struct State {

window: Retained<NSWindow>,

view: Retained<WinitView>,

#[cfg(not(feature = "private-apple-apis"))]
blur_view: RefCell<Option<Retained<NSVisualEffectView>>>,

// During `windowDidResize`, we use this to only send Moved if the position changed.
//
// This is expressed in desktop coordinates, and flipped to match Winit's coordinate system.
Expand Down Expand Up @@ -659,7 +669,7 @@ fn new_window(
macos_attrs: &WindowAttributesMacOS,
is_popup: bool,
mtm: MainThreadMarker,
) -> Option<Retained<NSWindow>> {
) -> Option<(Retained<NSWindow>, Retained<WinitView>)> {
autoreleasepool(|_| {
let screen = match attrs.fullscreen.clone() {
Some(Fullscreen::Borderless(Some(monitor)))
Expand Down Expand Up @@ -861,13 +871,22 @@ fn new_window(
view.setWantsLayer(true);
}

let content_view = NSView::new(mtm);
window.setContentView(Some(&content_view));

view.setFrame(content_view.bounds());
view.setAutoresizingMask(
NSAutoresizingMaskOptions::ViewWidthSizable
| NSAutoresizingMaskOptions::ViewHeightSizable,
);
content_view.addSubview(&view);

// Configure the new view as the "key view" for the window
window.setContentView(Some(&view));
window.setInitialFirstResponder(Some(&view));

// Configure the view to send notifications whenever its frame rectangle changes.
//
// We explicitly do this _after_ setting the view as the content view of the window, to
// We explicitly do this _after_ adding the view to the window, to
// avoid a resize event when creating the window.
view.setPostsFrameChangedNotifications(true);
// `setPostsFrameChangedNotifications` posts the notification immediately, so register the
Expand All @@ -888,7 +907,7 @@ fn new_window(
window.setBackgroundColor(Some(&NSColor::clearColor()));
}

Some(window)
Some((window, view))
})
}

Expand Down Expand Up @@ -918,7 +937,7 @@ impl WindowDelegate {
}
}

let window = new_window(app_state, &attrs, &macos_attrs, is_popup, mtm)
let (window, view) = new_window(app_state, &attrs, &macos_attrs, is_popup, mtm)
.ok_or_else(|| os_error!("couldn't create `NSWindow`"))?;

match attrs.parent_window() {
Expand Down Expand Up @@ -964,6 +983,9 @@ impl WindowDelegate {
let delegate = mtm.alloc().set_ivars(State {
app_state: Rc::clone(app_state),
window: window.retain(),
view,
#[cfg(not(feature = "private-apple-apis"))]
blur_view: RefCell::new(None),
previous_position: Cell::new(flip_window_screen_coordinates(window.frame())),
previous_scale_factor: Cell::new(scale_factor),
surface_resize_increments: Cell::new(surface_resize_increments),
Expand Down Expand Up @@ -1058,10 +1080,8 @@ impl WindowDelegate {
Ok(delegate)
}

#[track_caller]
pub(super) fn view(&self) -> Retained<WinitView> {
// The view inside WinitWindow should always be set and be `WinitView`.
self.window().contentView().unwrap().downcast().unwrap()
self.ivars().view.clone()
}

#[track_caller]
Expand Down Expand Up @@ -1164,8 +1184,43 @@ impl WindowDelegate {
};
}

// TODO: Implement blur using public methods somehow?
let _ = blur;
#[cfg(not(feature = "private-apple-apis"))]
{
if !blur {
let installed = self.ivars().blur_view.borrow_mut().take();
if let Some(installed) = installed {
installed.removeFromSuperview();
}
return;
}

if self.ivars().blur_view.borrow().is_some() {
return;
}

let mtm = MainThreadMarker::from(self);
let content_view =
self.window().contentView().expect("window always has a content view");

let new_blur_view = NSVisualEffectView::new(mtm);
new_blur_view.setBlendingMode(NSVisualEffectBlendingMode::BehindWindow);
new_blur_view.setState(NSVisualEffectState::Active);
if available!(macos = 10.14) {
new_blur_view.setMaterial(NSVisualEffectMaterial::WindowBackground);
}
new_blur_view.setFrame(content_view.bounds());
new_blur_view.setAutoresizingMask(
NSAutoresizingMaskOptions::ViewWidthSizable
| NSAutoresizingMaskOptions::ViewHeightSizable,
);
content_view.addSubview_positioned_relativeTo(
&new_blur_view,
NSWindowOrderingMode::Below,
Some(&self.view()),
);

*self.ivars().blur_view.borrow_mut() = Some(new_blur_view);
}
}

pub fn set_visible(&self, visible: bool) {
Expand Down
9 changes: 8 additions & 1 deletion winit-core/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,14 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug {
///
/// ## Platform-specific
///
/// - **macOS**: Must enable the `private-apple-apis` Cargo feature.
/// - **macOS:** Renders the system window background material behind the window's contents,
/// which is tinted and follows the window's appearance, rather than a blur of a specific
/// radius. The window's `contentView` is a container holding the view returned by
/// `raw-window-handle`, and the material is a sibling behind it. With the
/// `private-apple-apis` Cargo feature enabled, a private API is used instead to apply an
/// untinted backdrop blur of a fixed radius; this can cause App Store rejection. On macOS
/// 10.12 and older, enabling blur makes the window's views layer-backed, which may break the
/// association with an attached `NSOpenGLContext`.
/// - **Android / iOS / X11 / Web / Windows:** Unsupported.
/// - **Wayland:** Only works with `org_kde_kwin_blur_manager` or
/// `ext_background_effect_manager_v1` protocol.
Expand Down
4 changes: 4 additions & 0 deletions winit/src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ changelog entry.
- Updated `windows-sys` to `v0.61`.
- On older macOS versions (tested up to 12.7.6), applications now receive mouse movement events for unfocused windows, matching the behavior on other platforms.
- On macOS, using the private API `CGSSetWindowBackgroundBlurRadius` for `Window::set_blur` is now disabled by default. It can be re-enabled using the Cargo feature `private-apple-apis`.
- On macOS, `Window::set_blur` is now implemented with the public `NSVisualEffectView` when `private-apple-apis` is disabled, so binaries no longer link `_CGSSetWindowBackgroundBlurRadius`, which the Mac App Store rejects under Guideline 2.5.1.
- On macOS, blurred windows now render the system window background material rather than an untinted backdrop blur at a fixed radius of 80, and the radius is no longer configurable; enable the `private-apple-apis` Cargo feature to keep the previous implementation, which `--all-features` also enables.
- On macOS, the window's `contentView` is now a plain container `NSView` holding winit's view, rather than being winit's view itself; the handle returned by `raw-window-handle` is unchanged.
- On macOS 10.12 and older, enabling blur now makes the window's views layer-backed, which may break the association with an attached `NSOpenGLContext`.

### Removed

Expand Down
5 changes: 3 additions & 2 deletions winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,9 @@
//! * `serde`: Enables serialization/deserialization of certain types with [Serde](https://crates.io/crates/serde).
//! * `mint`: Enables mint (math interoperability standard types) conversions.
//! * `private-apple-apis`: Enables private APIs whose usage might cause rejections from the App
//! Store. Currently enables the use of `CGSSetWindowBackgroundBlurRadius`, commonly used for
//! terminal emulators.
//! Store. Currently switches `Window::set_blur` on macOS to use
//! `CGSSetWindowBackgroundBlurRadius`, which applies an untinted blur of a fixed radius and is
//! commonly used by terminal emulators, instead of the default `NSVisualEffectView` material.
//!
//! See the [`platform`] module for documentation on platform-specific cargo
//! features.
Expand Down