#[cfg(target_os = "macos")]
mod imp {
use std::cell::RefCell;
use objc2::rc::Retained;
use objc2::runtime::{NSObject, NSObjectProtocol};
use objc2::{AnyThread, MainThreadMarker, define_class, msg_send, sel};
use objc2_foundation::{NSAppleEventDescriptor, NSAppleEventManager};
type UrlHandler = Box<dyn FnMut(String)>;
thread_local! {
static URL_HANDLER: RefCell<Option<UrlHandler>> = const { RefCell::new(None) };
static HANDLER: RefCell<Option<Retained<PikiUrlHandler>>> = const { RefCell::new(None) };
}
pub fn set_open_url_handler<F: FnMut(String) + 'static>(handler: F) {
URL_HANDLER.with(|h| *h.borrow_mut() = Some(Box::new(handler)));
}
fn dispatch(url: String) {
URL_HANDLER.with(|h| {
if let Ok(mut slot) = h.try_borrow_mut()
&& let Some(cb) = slot.as_mut()
{
cb(url);
}
});
}
define_class!(
#[unsafe(super(NSObject))]
#[name = "PikiUrlHandler"]
struct PikiUrlHandler;
impl PikiUrlHandler {
#[unsafe(method(handleGetURLEvent:withReplyEvent:))]
fn handle_get_url_event(
&self,
event: &NSAppleEventDescriptor,
_reply: &NSAppleEventDescriptor,
) {
let key_direct_object = u32::from_be_bytes(*b"----");
let desc: Option<Retained<NSAppleEventDescriptor>> =
unsafe { msg_send![event, paramDescriptorForKeyword: key_direct_object] };
if let Some(desc) = desc
&& let Some(url) = desc.stringValue()
{
dispatch(url.to_string());
}
}
}
unsafe impl NSObjectProtocol for PikiUrlHandler {}
);
impl PikiUrlHandler {
fn new() -> Retained<Self> {
unsafe { msg_send![Self::alloc(), init] }
}
}
pub fn register() {
if MainThreadMarker::new().is_none() {
return;
}
let manager = NSAppleEventManager::sharedAppleEventManager();
let handler = PikiUrlHandler::new();
let event_class = u32::from_be_bytes(*b"GURL");
let event_id = u32::from_be_bytes(*b"GURL");
unsafe {
let _: () = msg_send![
&*manager,
setEventHandler: &*handler,
andSelector: sel!(handleGetURLEvent:withReplyEvent:),
forEventClass: event_class,
andEventID: event_id,
];
}
HANDLER.with(|h| *h.borrow_mut() = Some(handler));
}
}
#[cfg(target_os = "macos")]
pub use imp::{register, set_open_url_handler};
#[cfg(not(target_os = "macos"))]
pub fn set_open_url_handler<F: FnMut(String) + 'static>(_handler: F) {}
#[cfg(not(target_os = "macos"))]
pub fn register() {}