Skip to content

Commit

Permalink
feat(macos): add Reopen event, closes #218 (#517)
Browse files Browse the repository at this point in the history
* feat(macOS): add Reopen event

* fix: unable to compile on macos when arch isn't aarch64

* fix(examples::reopen_event): only create new window when no window exists
  • Loading branch information
BillGoldenWater authored May 2, 2024
1 parent cd38f23 commit f06843b
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changes/macos_reopen_event.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tao": minor
---

Add `event::Reopen` for handle click on dock icon on macOS.
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Run the `cargo run --example <file_name>` to see how each example works.
- `multithreaded`: same as multiwindow but multithreaded.
- `multiwindow`: create multiple windows
- `parentwindow`: a window inside another window.
- `reopen_event`: handle click on dock icon on macOS
- `resizable`: allow resizing window or not.
- `set_ime_position`: set IME (input method editor) position when click.
- `transparent`: make a transparent window.
Expand Down
45 changes: 45 additions & 0 deletions examples/reopen_event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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::Reopen {
has_visible_windows,
..
} => {
println!("on reopen, has visible windows: {has_visible_windows}");
if !has_visible_windows {
window = Some(Window::new(&event_loop).unwrap())
}
}
Event::MainEventsCleared => {
if let Some(w) = &window {
w.request_redraw();
}
}
_ => (),
}
});
}
23 changes: 22 additions & 1 deletion src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ pub enum Event<'a, T: 'static> {

/// Emitted when the app is open by external resources, like opening a file or deeplink.
Opened { urls: Vec<url::Url> },

/// ## Platform-specific
///
/// - **macOS**: https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428638-applicationshouldhandlereopen with return value same as hasVisibleWindows
/// - **Other**: Unsupported.
#[non_exhaustive]
Reopen { has_visible_windows: bool },
}

impl<T: Clone> Clone for Event<'static, T> {
Expand All @@ -159,6 +166,11 @@ impl<T: Clone> Clone for Event<'static, T> {
Suspended => Suspended,
Resumed => Resumed,
Opened { urls } => Opened { urls: urls.clone() },
Reopen {
has_visible_windows,
} => Reopen {
has_visible_windows: *has_visible_windows,
},
}
}
}
Expand All @@ -178,6 +190,11 @@ impl<'a, T> Event<'a, T> {
Suspended => Ok(Suspended),
Resumed => Ok(Resumed),
Opened { urls } => Ok(Opened { urls }),
Reopen {
has_visible_windows,
} => Ok(Reopen {
has_visible_windows,
}),
}
}

Expand All @@ -199,6 +216,11 @@ impl<'a, T> Event<'a, T> {
Suspended => Some(Suspended),
Resumed => Some(Resumed),
Opened { urls } => Some(Opened { urls }),
Reopen {
has_visible_windows,
} => Some(Reopen {
has_visible_windows,
}),
}
}
}
Expand Down Expand Up @@ -692,7 +714,6 @@ pub struct KeyEvent {
/// ## Platform-specific
/// - **Web:** Dead keys might be reported as the real key instead
/// of `Dead` depending on the browser/OS.
///
pub logical_key: keyboard::Key<'static>,

/// Contains the text produced by this keypress.
Expand Down
25 changes: 21 additions & 4 deletions src/platform_impl/macos/app_delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use crate::{platform::macos::ActivationPolicy, platform_impl::platform::app_state::AppState};

use cocoa::base::id;
use cocoa::foundation::NSString;
use cocoa::{
base::{id, NO},
foundation::NSString,
};
use objc::{
declare::ClassDecl,
runtime::{Class, Object, Sel, BOOL},
Expand All @@ -15,8 +17,7 @@ use std::{
os::raw::c_void,
};

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

static AUX_DELEGATE_STATE_NAME: &str = "auxState";
Expand Down Expand Up @@ -54,6 +55,10 @@ lazy_static! {
sel!(application:openURLs:),
application_open_urls as extern "C" fn(&Object, Sel, id, id),
);
decl.add_method(
sel!(applicationShouldHandleReopen:hasVisibleWindows:),
application_should_handle_reopen as extern "C" fn(&Object, Sel, id, BOOL) -> BOOL,
);
decl.add_method(
sel!(applicationSupportsSecureRestorableState:),
application_supports_secure_restorable_state as extern "C" fn(&Object, Sel, id) -> BOOL,
Expand Down Expand Up @@ -125,6 +130,18 @@ extern "C" fn application_open_urls(_: &Object, _: Sel, _: id, urls: id) -> () {
trace!("Completed `application:openURLs:`");
}

extern "C" fn application_should_handle_reopen(
_: &Object,
_: Sel,
_: id,
has_visible_windows: BOOL,
) -> BOOL {
trace!("Triggered `applicationShouldHandleReopen`");
AppState::reopen(has_visible_windows != NO);
trace!("Completed `applicationShouldHandleReopen`");
has_visible_windows
}

extern "C" fn application_supports_secure_restorable_state(_: &Object, _: Sel, _: id) -> BOOL {
trace!("Triggered `applicationSupportsSecureRestorableState`");
trace!("Completed `applicationSupportsSecureRestorableState`");
Expand Down
6 changes: 6 additions & 0 deletions src/platform_impl/macos/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,12 @@ impl AppState {
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::Opened { urls }));
}

pub fn reopen(has_visible_windows: bool) {
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::Reopen {
has_visible_windows,
}));
}

pub fn wakeup(panic_info: Weak<PanicInfo>) {
let panic_info = panic_info
.upgrade()
Expand Down

0 comments on commit f06843b

Please sign in to comment.