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

feat: Event::Reopen support for macOS #3499

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Unreleased` header.
- On Orbital, implement `set_window_level`.
- On Orbital, emit `DeviceEvent::MouseMotion`.
- On Wayland, fix title in CSD not updated from `AboutToWait`.
- On macOS, emit `Event::Reopen` to handle dock icon click event.

# 0.29.10

Expand Down
1 change: 1 addition & 0 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ If your PR makes notable changes to Winit's features, please update this section
* Full-size content view
* Accepts first mouse
* Set a preferred theme and get current theme.
* Dock icon click event

### Unix
* Window urgency
Expand Down
61 changes: 61 additions & 0 deletions examples/reopen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#![allow(clippy::single_match)]
I-Info marked this conversation as resolved.
Show resolved Hide resolved

use std::collections::HashMap;

use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::{EventLoop, EventLoopWindowTarget},
window::{Window, WindowId},
};

#[path = "util/fill.rs"]
mod fill;

fn new_window(event_loop: &EventLoopWindowTarget, windows: &mut HashMap<WindowId, Window>) {
let window = Window::new(event_loop).unwrap();
println!("Opened a new window: {:?}", window.id());
windows.insert(window.id(), window);
}

fn main() -> Result<(), impl std::error::Error> {
SimpleLogger::new().init().unwrap();
let event_loop = EventLoop::new().unwrap();

let mut windows = HashMap::new();
new_window(&event_loop, &mut windows);

event_loop.run(move |event, elwt| {
if let Event::WindowEvent { event, window_id } = event {
match event {
WindowEvent::CloseRequested => {
println!("Window {window_id:?} has received the signal to close");

// This drops the window, causing it to close.
windows.remove(&window_id);

// Keep the event loop running on macOS, even if all windows are closed.
#[cfg(not(target_os = "macos"))]
if windows.is_empty() {
elwt.exit();
}
}
WindowEvent::RedrawRequested => {
if let Some(window) = windows.get(&window_id) {
fill::fill_window(window);
}
}
_ => (),
}
} else if let Event::Reopen {
has_visible_windows,
} = event
{
println!("Reopen event: has_visible_windows={}", has_visible_windows);
// If there are no visible windows, open a new one.
if !has_visible_windows {
new_window(elwt, &mut windows);
}
}
})
}
24 changes: 24 additions & 0 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,25 @@ pub enum Event<T: 'static> {
///
/// - **macOS / Wayland / Windows / Orbital:** Unsupported.
MemoryWarning,

/// Emitted when the application has received a reopen request from OS.
///
/// ## Platform-specific
///
/// ### macOS
///
/// On macOS, the `Reopen` event is emitted in response to an [`applicationShouldHandleReopen`]
/// callback, which is typically called when the user clicks on the application's icon in the Dock.
I-Info marked this conversation as resolved.
Show resolved Hide resolved
/// The application should create a new window if it doesn't have any, or bring the
/// existing windows to the front. `has_visible_windows` is `true` if the application has
/// at least one visible window.
I-Info marked this conversation as resolved.
Show resolved Hide resolved
///
/// [`applicationShouldHandleReopen`]: https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428638-applicationshouldhandlereopen
///
/// ### Others
///
/// - **Android / iOS / Web / Wayland / Windows / Orbital:** Unsupported.
Reopen { has_visible_windows: bool },
I-Info marked this conversation as resolved.
Show resolved Hide resolved
}

impl<T> Event<T> {
Expand All @@ -269,6 +288,11 @@ impl<T> Event<T> {
Suspended => Ok(Suspended),
Resumed => Ok(Resumed),
MemoryWarning => Ok(MemoryWarning),
Reopen {
has_visible_windows,
} => Ok(Reopen {
has_visible_windows,
}),
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/platform_impl/macos/app_delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,16 @@ declare_class!(
// TODO: Notify every window that it will be destroyed, like done in iOS?
self.internal_exit();
}

#[method(applicationShouldHandleReopen:hasVisibleWindows:)]
fn should_handle_reopen(&self, _sender: &Option<&AnyObject>, has_visible_windows: bool) -> bool {
trace_scope!("applicationShouldHandleReopen:hasVisibleWindows:");

self.handle_event(Event::Reopen{ has_visible_windows });
// return true to preserve the default behavior, such as showing the minimized window.
true
}

}
);

Expand Down