Skip to content

Commit

Permalink
Support an OpenURL event on macOS
Browse files Browse the repository at this point in the history
This hooks into the application:openUrls delegate callback on macOS to deliver
a corresponding Event::OpenURL to applications.

The event was added as a general Winit event, even though it's only supported
for one platform, but potentially we could add some notion of a PlatformEvent
to make it more explicit that this is only for macOS.
  • Loading branch information
rib committed Nov 28, 2023
1 parent d65d421 commit bacc95b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 4 deletions.
10 changes: 10 additions & 0 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ pub enum Event<'a, T: 'static> {
/// [`ControlFlow::WaitUntil`](crate::event_loop::ControlFlow::WaitUntil) has elapsed.
NewEvents(StartCause),

/// Emitted if a user has requested to open an application specific URL that is registered with the OS
///
/// # Portability
///
/// This event is only ever delivered on MacOS currently
OpenURL { url: String },

/// Emitted when the OS sends an event to a winit window.
WindowEvent {
window_id: WindowId,
Expand Down Expand Up @@ -235,6 +242,7 @@ impl<T: Clone> Clone for Event<'static, T> {
fn clone(&self) -> Self {
use self::Event::*;
match self {
OpenURL { url } => OpenURL { url: url.clone() },
WindowEvent { window_id, event } => WindowEvent {
window_id: *window_id,
event: event.clone(),
Expand All @@ -260,6 +268,7 @@ impl<'a, T> Event<'a, T> {
use self::Event::*;
match self {
UserEvent(_) => Err(self),
OpenURL { url } => Ok(OpenURL { url }),
WindowEvent { window_id, event } => Ok(WindowEvent { window_id, event }),
DeviceEvent { device_id, event } => Ok(DeviceEvent { device_id, event }),
NewEvents(cause) => Ok(NewEvents(cause)),
Expand All @@ -277,6 +286,7 @@ impl<'a, T> Event<'a, T> {
pub fn to_static(self) -> Option<Event<'static, T>> {
use self::Event::*;
match self {
OpenURL { url } => Some(OpenURL { url }),
WindowEvent { window_id, event } => event
.to_static()
.map(|event| WindowEvent { window_id, event }),
Expand Down
37 changes: 35 additions & 2 deletions src/platform_impl/macos/app_delegate.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
use objc2::foundation::NSObject;
use objc2::foundation::{NSArray, NSObject, NSString};
use objc2::rc::{Id, Shared};
use objc2::runtime::Object;
use objc2::{declare_class, msg_send, msg_send_id, ClassType};
use objc2::{declare_class, extern_class, extern_methods, msg_send, msg_send_id, ClassType};

use crate::event::Event;

use super::app_state::AppState;
use super::appkit::NSApplicationActivationPolicy;
use super::event::EventWrapper;

extern_class!(
#[derive(Debug)]
struct NSURL;
unsafe impl ClassType for NSURL {
type Super = NSObject;
}
);

unsafe impl Send for NSURL {}
unsafe impl Sync for NSURL {}

extern_methods!(
unsafe impl NSURL {
pub fn absolute_string(&self) -> Option<Id<NSString, Shared>> {
unsafe { msg_send_id![self, absoluteString] }
}
}
);

declare_class!(
#[derive(Debug)]
Expand Down Expand Up @@ -52,6 +74,17 @@ declare_class!(
// TODO: Notify every window that it will be destroyed, like done in iOS?
AppState::exit();
}

#[sel(application:openURLs:)]
fn application_open_urls(&self, _application: &NSObject, urls: &NSArray<NSURL>) {
for url in urls {
if let Some(url) = url.absolute_string() {
AppState::queue_event(EventWrapper::StaticEvent(Event::OpenURL {
url: url.to_string(),
}));
}
}
}
}
);

Expand Down
4 changes: 2 additions & 2 deletions src/platform_impl/macos/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use std::{boxed::Box, os::raw::*, ptr, str, sync::Mutex};

use objc2::declare::{Ivar, IvarDrop};
use objc2::foundation::{
NSArray, NSAttributedString, NSAttributedStringKey, NSCopying,
NSMutableAttributedString, NSObject, NSPoint, NSRange, NSRect, NSSize, NSString, NSUInteger,
NSArray, NSAttributedString, NSAttributedStringKey, NSCopying, NSMutableAttributedString,
NSObject, NSPoint, NSRange, NSRect, NSSize, NSString, NSUInteger,
};
use objc2::rc::{Id, Owned, Shared, WeakId};
use objc2::runtime::{Object, Sel};
Expand Down

0 comments on commit bacc95b

Please sign in to comment.