diff --git a/CHANGELOG.md b/CHANGELOG.md index 722ea7aa..d49e5d0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre # Unreleased +- Added `WindowEvent::Occluded(bool)`, currently implemented on macOS and X11. - On X11, fix events for caps lock key not being sent - Build docs on `docs.rs` for iOS and Android as well. - **Breaking:** Removed the `WindowAttributes` struct, since all its functionality is accessible from `WindowBuilder`. diff --git a/src/event.rs b/src/event.rs index 29e860e6..e6710d44 100644 --- a/src/event.rs +++ b/src/event.rs @@ -372,6 +372,15 @@ pub enum WindowEvent<'a> { /// /// At the moment this is only supported on Windows. ThemeChanged(Theme), + + /// The window has been occluded (completely hidden from view). + /// + /// This is different to window visibility as it depends on whether the window is closed, + /// minimised, set invisible, or fully occluded by another window. + /// + /// Platform-specific behavior: + /// - **iOS / Android / Web / Wayland / Windows :** Unsupported. + Occluded(bool), } impl Clone for WindowEvent<'static> { @@ -461,6 +470,7 @@ impl Clone for WindowEvent<'static> { ScaleFactorChanged { .. } => { unreachable!("Static event can't be about scale factor changing") } + Occluded(occluded) => Occluded(*occluded), }; } } @@ -546,6 +556,7 @@ impl<'a> WindowEvent<'a> { Touch(touch) => Some(Touch(touch)), ThemeChanged(theme) => Some(ThemeChanged(theme)), ScaleFactorChanged { .. } => None, + Occluded(occluded) => Some(Occluded(occluded)), } } } diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index bbd07ff1..54cdc59b 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -531,8 +531,13 @@ impl EventProcessor { ffi::VisibilityNotify => { let xev: &ffi::XVisibilityEvent = xev.as_ref(); let xwindow = xev.window; - - self.with_window(xwindow, |window| window.visibility_notify()); + callback(Event::WindowEvent { + window_id: mkwid(xwindow), + event: WindowEvent::Occluded(xev.state == ffi::VisibilityFullyObscured), + }); + self.with_window(xwindow, |window| { + window.visibility_notify(); + }); } ffi::Expose => { diff --git a/src/platform_impl/macos/window_delegate.rs b/src/platform_impl/macos/window_delegate.rs index 3a8d713f..bb855cd5 100644 --- a/src/platform_impl/macos/window_delegate.rs +++ b/src/platform_impl/macos/window_delegate.rs @@ -5,7 +5,7 @@ use std::{ }; use cocoa::{ - appkit::{self, NSApplicationPresentationOptions, NSView, NSWindow}, + appkit::{self, NSApplicationPresentationOptions, NSView, NSWindow, NSWindowOcclusionState}, base::{id, nil}, foundation::NSUInteger, }; @@ -220,6 +220,10 @@ static WINDOW_DELEGATE_CLASS: Lazy = Lazy::new(|| unsafe { sel!(windowDidFailToEnterFullScreen:), window_did_fail_to_enter_fullscreen as extern "C" fn(&Object, Sel, id), ); + decl.add_method( + sel!(windowDidChangeOcclusionState:), + window_did_change_occlusion_state as extern "C" fn(&Object, Sel, id), + ); decl.add_ivar::<*mut c_void>("winitState"); WindowDelegateClass(decl.register()) @@ -554,3 +558,18 @@ extern "C" fn window_did_fail_to_enter_fullscreen(this: &Object, _: Sel, _: id) } }); } + +// Invoked when the occlusion state of the window changes +extern "C" fn window_did_change_occlusion_state(this: &Object, _: Sel, _: id) { + trace_scope!("windowDidChangeOcclusionState:"); + unsafe { + with_state(this, |state| { + state.emit_event(WindowEvent::Occluded( + !state + .ns_window + .occlusionState() + .contains(NSWindowOcclusionState::NSWindowOcclusionStateVisible), + )) + }); + } +}