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
5 changes: 5 additions & 0 deletions .changes/macos_exit_requested_event.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": minor
---

Added `event::ExitRequested` handle for dock icon exit on macOS.
3 changes: 2 additions & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Run the `cargo run --example <file_name>` to see how each example works.
- `cursor_grab`: prevent the cursor from going outside the window.
- `cursor`: set different cursor icons.
- `drag_window`: allow dragging window when hold left mouse and move.
- `exit_requested_event`: handle for dock icon exit on macOS.
- `min_max_size`: set smallest/largest window size you can zoom.
- `minimize`: minimize window.
- `monitor_list`: list all available monitors.
Expand All @@ -30,4 +31,4 @@ Run the `cargo run --example <file_name>` to see how each example works.
- `transparent`: make a transparent window.
- `video_modes`: example that lists all video modes of primary monitor
- `window_icon`: add window icon.
- `window`: example that makes a window.
- `window`: example that makes a window.
42 changes: 42 additions & 0 deletions examples/exit_requested_event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2014-2021 The winit contributors
// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0

use tao::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::Window,
};

#[allow(clippy::single_match)]
fn main() {
let event_loop = EventLoop::new();

let mut window = Some(Window::new(&event_loop).unwrap());

event_loop.run(move |event, event_loop, control_flow| {
*control_flow = ControlFlow::Wait;

match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
// drop the window
window = None;
}
Event::MainEventsCleared => {
if let Some(w) = &window {
w.request_redraw();
}
}
Event::ExitRequested => {
println!("Exit requested");

// drop the window
window = None;
}
_ => (),
}
});
}
10 changes: 10 additions & 0 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ pub enum Event<'a, T: 'static> {
/// - **Other**: Unsupported.
#[non_exhaustive]
Reopen { has_visible_windows: bool },

/// The MacOS dock has requested to quit the application.
///
/// ## Platform-specific
/// - **macOS**: https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428642-applicationshouldterminate
/// - **Other**: Unsupported.
ExitRequested,
}

impl<T: Clone> Clone for Event<'static, T> {
Expand Down Expand Up @@ -171,6 +178,7 @@ impl<T: Clone> Clone for Event<'static, T> {
} => Reopen {
has_visible_windows: *has_visible_windows,
},
ExitRequested => ExitRequested,
}
}
}
Expand All @@ -195,6 +203,7 @@ impl<'a, T> Event<'a, T> {
} => Ok(Reopen {
has_visible_windows,
}),
ExitRequested => Ok(ExitRequested),
}
}

Expand All @@ -221,6 +230,7 @@ impl<'a, T> Event<'a, T> {
} => Some(Reopen {
has_visible_windows,
}),
ExitRequested => Some(ExitRequested),
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/platform_impl/macos/app_delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ use std::{

use cocoa::foundation::{NSArray, NSURL};
use std::ffi::CStr;
use std::os::raw::c_int;

static AUX_DELEGATE_STATE_NAME: &str = "auxState";

const NS_TERMINATE_LATER: c_int = 2;

pub struct AuxDelegateState {
/// We store this value in order to be able to defer setting the activation policy until
/// after the app has finished launching. If the activation policy is set earlier, the
Expand All @@ -47,6 +50,10 @@ lazy_static! {
sel!(applicationDidFinishLaunching:),
did_finish_launching as extern "C" fn(&Object, Sel, id),
);
decl.add_method(
sel!(applicationShouldTerminate:),
application_should_terminate as extern "C" fn(&Object, Sel, id) -> c_int,
);
decl.add_method(
sel!(applicationWillTerminate:),
application_will_terminate as extern "C" fn(&Object, Sel, id),
Expand Down Expand Up @@ -106,6 +113,13 @@ extern "C" fn did_finish_launching(this: &Object, _: Sel, _: id) {
trace!("Completed `applicationDidFinishLaunching`");
}

extern "C" fn application_should_terminate(_: &Object, _: Sel, _: id) -> c_int {
trace!("Triggered `applicationShouldTerminate`");
AppState::should_exit();
trace!("Completed `applicationShouldTerminate`");
NS_TERMINATE_LATER
Copy link
Member

@amrbashir amrbashir Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, this will cause the application to never quit unless the event loop is changed programatically.

I see that in the associated tauri PR, you call replyToApplicationShouldTerminate which is fine I guess but the default behavior here should return NS_TERMINATE_NOW and need a way for that to be overridden.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't think of a good way to handle this problem.

Is it possible to transplant the processing method in tauri to tao? By default, NSTerminateLater is returned. If the user does not handle the event, reply to exit. Otherwise, reply, terminate or cancel according to the user's processing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a similar mechanism used when ScaleFactorChanged event is fired.

}

extern "C" fn application_will_terminate(_: &Object, _: Sel, _: id) {
trace!("Triggered `applicationWillTerminate`");
AppState::exit();
Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/macos/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,10 @@ impl AppState {
}));
}

pub fn should_exit() {
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::ExitRequested));
}

pub fn exit() -> i32 {
HANDLER.set_in_callback(true);
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::LoopDestroyed));
Expand Down
Loading