use objc2::rc::Retained;
use objc2::runtime::NSObject;
use objc2::{AllocAnyThread, DefinedClass, define_class, msg_send, sel};
use objc2_foundation::{NSAppleEventDescriptor, NSAppleEventManager};
const GURL: u32 = u32::from_be_bytes(*b"GURL");
const DIRECT_OBJECT: u32 = u32::from_be_bytes(*b"----");
struct Ivars {
on_url: Box<dyn Fn(String)>,
}
define_class!(
#[unsafe(super(NSObject))]
#[name = "BadTermURLHandler"]
#[ivars = Ivars]
struct UrlHandler;
impl UrlHandler {
#[unsafe(method(handleGetURL:withReplyEvent:))]
fn handle_get_url(&self, event: &NSAppleEventDescriptor, _reply: &NSAppleEventDescriptor) {
let param: Option<Retained<NSAppleEventDescriptor>> =
unsafe { msg_send![event, paramDescriptorForKeyword: DIRECT_OBJECT] };
if let Some(url) = param.and_then(|d| d.stringValue()) {
(self.ivars().on_url)(url.to_string());
}
}
}
);
pub fn install(on_url: impl Fn(String) + 'static) {
let handler = UrlHandler::alloc().set_ivars(Ivars { on_url: Box::new(on_url) });
let handler: Retained<UrlHandler> = unsafe { msg_send![super(handler), init] };
let manager = NSAppleEventManager::sharedAppleEventManager();
unsafe {
let _: () = msg_send![
&manager,
setEventHandler: &*handler,
andSelector: sel!(handleGetURL:withReplyEvent:),
forEventClass: GURL,
andEventID: GURL,
];
}
std::mem::forget(handler);
}