Skip to content

Commit

Permalink
Use msg_send_id! and rc::Id
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Jul 18, 2022
1 parent 8357f38 commit 7436f7b
Show file tree
Hide file tree
Showing 92 changed files with 656 additions and 683 deletions.
12 changes: 6 additions & 6 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,8 @@ We'll step through an example (abridged) `View` bridge below, for macOS. You sho
For our basic `View` type, we want to just map to the corresponding class on the Objective-C side (in this case, `NSView`), and maybe do a bit of tweaking for sanity reasons.

``` rust
pub(crate) fn register_view_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_view_class() -> &'static Class {
static mut VIEW_CLASS: Option<'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
Expand All @@ -364,10 +364,10 @@ pub(crate) fn register_view_class() -> *const Class {

decl.add_ivar::<id>(BACKGROUND_COLOR);

VIEW_CLASS = decl.register();
VIEW_CLASS = Some(decl.register());
});

unsafe { VIEW_CLASS }
unsafe { VIEW_CLASS.unwrap() }
}
```

Expand All @@ -377,7 +377,7 @@ Objective-C method signatures, as well as provision space for variable storage (
For our _delegate_ types, we need a different class creation method - one that creates a subclass per-unique-type:

``` rust
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>(instance: &T) -> *const Class {
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSView", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
decl.add_ivar::<id>(BACKGROUND_COLOR);
Expand Down Expand Up @@ -412,7 +412,7 @@ Here, we just want to tell `NSView` to use top,left as the origin point, so we n
extern "C" fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = utils::load::<T>(this, VIEW_DELEGATE_PTR);
view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) }
info: unsafe { Id::retain(info).unwrap() }
}).into()
}
```
Expand Down
16 changes: 8 additions & 8 deletions src/appkit/alert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@
//! }
//! ```

use crate::id_shim::Id;
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel};
use objc::{class, msg_send, msg_send_id, sel};

use crate::foundation::{id, NSString};

/// Represents an `NSAlert`. Has no information other than the retained pointer to the Objective C
/// side, so... don't bother inspecting this.
#[derive(Debug)]
pub struct Alert(Id<Object>);
pub struct Alert(Id<Object, Owned>);

impl Alert {
/// Creates a basic `NSAlert`, storing a pointer to it in the Objective C runtime.
Expand All @@ -44,11 +44,11 @@ impl Alert {
let ok = NSString::new("OK");

Alert(unsafe {
let alert: id = msg_send![class!(NSAlert), new];
let _: () = msg_send![alert, setMessageText: &*title];
let _: () = msg_send![alert, setInformativeText: &*message];
let _: () = msg_send![alert, addButtonWithTitle: &*ok];
Id::from_ptr(alert)
let mut alert = msg_send_id![class!(NSAlert), new].unwrap();
let _: () = msg_send![&mut alert, setMessageText: &*title];
let _: () = msg_send![&mut alert, setInformativeText: &*message];
let _: () = msg_send![&mut alert, addButtonWithTitle: &*ok];
alert
})
}

Expand Down
8 changes: 4 additions & 4 deletions src/appkit/app/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ use objc::declare::ClassDecl;
use objc::runtime::Class;

/// Used for injecting a custom NSApplication. Currently does nothing.
pub(crate) fn register_app_class() -> *const Class {
static mut APP_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_app_class() -> &'static Class {
static mut APP_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
let superclass = class!(NSApplication);
let decl = ClassDecl::new("RSTApplication", superclass).unwrap();
APP_CLASS = decl.register();
APP_CLASS = Some(decl.register());
});

unsafe { APP_CLASS }
unsafe { APP_CLASS.unwrap() }
}
8 changes: 4 additions & 4 deletions src/appkit/app/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ extern "C" fn delegate_handles_key<T: AppDelegate>(this: &Object, _: Sel, _: id,

/// Registers an `NSObject` application delegate, and configures it for the various callbacks and
/// pointers we need to have.
pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> *const Class {
static mut DELEGATE_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> &'static Class {
static mut DELEGATE_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
Expand Down Expand Up @@ -453,8 +453,8 @@ pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> *co
delegate_handles_key::<T> as extern "C" fn(_, _, _, _) -> _
);

DELEGATE_CLASS = decl.register();
DELEGATE_CLASS = Some(decl.register());
});

unsafe { DELEGATE_CLASS }
unsafe { DELEGATE_CLASS.unwrap() }
}
21 changes: 9 additions & 12 deletions src/appkit/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ use std::sync::{Arc, Mutex};

use lazy_static::lazy_static;

use crate::id_shim::Id;
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel};
use objc::{class, msg_send, msg_send_id, sel};

use crate::appkit::menu::Menu;
use crate::foundation::{id, nil, AutoReleasePool, NSUInteger, NO, YES};
Expand Down Expand Up @@ -86,11 +86,11 @@ fn shared_application<F: Fn(id)>(handler: F) {
/// application.
pub struct App<T = (), M = ()> {
/// The underlying Objective-C Object.
pub objc: Id<Object>,
pub objc: Id<Object, Owned>,

/// The underlying Objective-C Object, which in this case is a delegate that forwards to the
/// app delegate.
pub objc_delegate: Id<Object>,
pub objc_delegate: Id<Object, Owned>,

/// The stored `AppDelegate`.
pub delegate: Box<T>,
Expand Down Expand Up @@ -142,20 +142,17 @@ where

let pool = AutoReleasePool::new();

let objc = unsafe {
let app: id = msg_send![register_app_class(), sharedApplication];
Id::from_ptr(app)
};
let objc = unsafe { msg_send_id![register_app_class(), sharedApplication].unwrap() };

let app_delegate = Box::new(delegate);

let objc_delegate = unsafe {
let delegate_class = register_app_delegate_class::<T>();
let delegate: id = msg_send![delegate_class, new];
let mut delegate: Id<Object, Owned> = msg_send_id![delegate_class, new].unwrap();
let delegate_ptr: *const T = &*app_delegate;
(&mut *delegate).set_ivar(APP_PTR, delegate_ptr as usize);
let _: () = msg_send![&*objc, setDelegate: delegate];
Id::from_ptr(delegate)
delegate.set_ivar(APP_PTR, delegate_ptr as usize);
let _: () = msg_send![&*objc, setDelegate: &*delegate];
delegate
};

App {
Expand Down
15 changes: 8 additions & 7 deletions src/appkit/event/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use block::ConcreteBlock;

use crate::id_shim::Id;
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel};
use objc::{class, msg_send, msg_send_id, sel};

use crate::foundation::{id, nil, NSString};

Expand All @@ -14,15 +14,15 @@ pub enum EventMask {

/// A wrapper over an `NSEvent`.
#[derive(Debug)]
pub struct EventMonitor(pub Id<Object>);
pub struct EventMonitor(pub Id<Object, Owned>);

/// A wrapper over an `NSEvent`.
#[derive(Debug)]
pub struct Event(pub Id<Object>);
pub struct Event(pub Id<Object, Owned>);

impl Event {
pub(crate) fn new(objc: id) -> Self {
Event(unsafe { Id::from_ptr(objc) })
Event(unsafe { Id::retain(objc).unwrap() })
}

pub fn characters(&self) -> String {
Expand Down Expand Up @@ -68,11 +68,12 @@ impl Event {
let block = block.copy();

EventMonitor(unsafe {
Id::from_ptr(msg_send![
msg_send_id![
class!(NSEvent),
addLocalMonitorForEventsMatchingMask: 1024,
handler: &*block,
])
]
.unwrap()
})
}
}
Expand Down
45 changes: 26 additions & 19 deletions src/appkit/menu/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
use std::fmt;
use std::sync::Once;

use crate::id_shim::Id;
use block::ConcreteBlock;
use objc::declare::ClassDecl;
use objc::rc::{Id, Owned};
use objc::runtime::{Class, Object, Sel};
use objc::{class, msg_send, sel};
use objc::{class, msg_send, msg_send_id, sel};

use crate::events::EventModifierFlag;
use crate::foundation::{id, nil, NSString, NSUInteger};
Expand Down Expand Up @@ -40,7 +40,7 @@ fn make_menu_item<S: AsRef<str>>(
key: Option<&str>,
action: Option<Sel>,
modifiers: Option<&[EventModifierFlag]>
) -> Id<Object> {
) -> Id<Object, Owned> {
unsafe {
let title = NSString::new(title.as_ref());

Expand All @@ -53,14 +53,22 @@ fn make_menu_item<S: AsRef<str>>(
// Stock menu items that use selectors targeted at system pieces are just standard
// `NSMenuItem`s. If there's no custom ones, we use our subclass that has a slot to store a
// handler pointer.
let alloc: id = msg_send![register_menu_item_class(), alloc];
let item = Id::from_retained_ptr(match action {
Some(a) => msg_send![alloc, initWithTitle:&*title action:a keyEquivalent:&*key],

None => msg_send![alloc, initWithTitle:&*title
action:sel!(fireBlockAction:)
keyEquivalent:&*key]
});
let alloc = msg_send_id![register_menu_item_class(), alloc];
let item = match action {
Some(a) => msg_send_id![
alloc,
initWithTitle: &*title,
action: a,
keyEquivalent: &*key,
],
None => msg_send_id![
alloc,
initWithTitle: &*title,
action: sel!(fireBlockAction:),
keyEquivalent: &*key,
]
}
.unwrap();

if let Some(modifiers) = modifiers {
let mut key_mask: NSUInteger = 0;
Expand All @@ -86,7 +94,7 @@ pub enum MenuItem {
/// You can (and should) create this variant via the `new(title)` method, but if you need to do
/// something crazier, then wrap it in this and you can hook into the Cacao menu system
/// accordingly.
Custom(Id<Object>),
Custom(Id<Object, Owned>),

/// Shows a standard "About" item, which will bring up the necessary window when clicked
/// (include a `credits.html` in your App to make use of here). The argument baked in here
Expand Down Expand Up @@ -153,7 +161,7 @@ pub enum MenuItem {
impl MenuItem {
/// Consumes and returns a handle for the underlying MenuItem. This is internal as we make a few assumptions
/// for how it interacts with our `Menu` setup, but this could be made public in the future.
pub(crate) unsafe fn to_objc(self) -> Id<Object> {
pub(crate) unsafe fn to_objc(self) -> Id<Object, Owned> {
match self {
Self::Custom(objc) => objc,

Expand Down Expand Up @@ -210,8 +218,7 @@ impl MenuItem {

Self::Separator => {
let cls = class!(NSMenuItem);
let separator: id = msg_send![cls, separatorItem];
Id::from_ptr(separator)
msg_send_id![cls, separatorItem].unwrap()
}
}
}
Expand Down Expand Up @@ -313,8 +320,8 @@ extern "C" fn fire_block_action(this: &Object, _: Sel, _item: id) {
///
/// In general, we do not want to do more than we need to here - menus are one of the last areas
/// where Carbon still lurks, and subclassing things can get weird.
pub(crate) fn register_menu_item_class() -> *const Class {
static mut APP_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_menu_item_class() -> &'static Class {
static mut APP_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
Expand All @@ -325,8 +332,8 @@ pub(crate) fn register_menu_item_class() -> *const Class {
decl.add_method(sel!(dealloc), dealloc_cacao_menuitem as extern "C" fn(_, _));
decl.add_method(sel!(fireBlockAction:), fire_block_action as extern "C" fn(_, _, _));

APP_CLASS = decl.register();
APP_CLASS = Some(decl.register());
});

unsafe { APP_CLASS }
unsafe { APP_CLASS.unwrap() }
}
14 changes: 7 additions & 7 deletions src/appkit/menu/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

use std::sync::{Arc, Mutex};

use crate::id_shim::{Id, ShareId};
use objc::rc::{Id, Owned, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, sel};
use objc::{class, msg_send, msg_send_id, sel};

use crate::appkit::menu::item::MenuItem;
use crate::foundation::{id, NSInteger, NSString};

/// A struct that represents an `NSMenu`. It takes ownership of items, and handles instrumenting
/// them throughout the application lifecycle.
#[derive(Debug)]
pub struct Menu(pub Id<Object>);
pub struct Menu(pub Id<Object, Owned>);

impl Menu {
/// Creates a new `Menu` with the given title, and uses the passed items as submenu items.
Expand All @@ -27,16 +27,16 @@ impl Menu {
pub fn new(title: &str, items: Vec<MenuItem>) -> Self {
Menu(unsafe {
let cls = class!(NSMenu);
let alloc: id = msg_send![cls, alloc];
let alloc = msg_send_id![cls, alloc];
let title = NSString::new(title);
let menu: id = msg_send![alloc, initWithTitle:&*title];
let mut menu = msg_send_id![alloc, initWithTitle: &*title].unwrap();

for item in items.into_iter() {
let objc = item.to_objc();
let _: () = msg_send![menu, addItem:&*objc];
let _: () = msg_send![&mut menu, addItem:&*objc];
}

Id::from_retained_ptr(menu)
menu
})
}

Expand Down
6 changes: 3 additions & 3 deletions src/appkit/printing/settings.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Represents settings for printing items. Backed by an `NSDictionary` in Objective-C, this struct
//! aims to make it easier to query/process printing operations.

use crate::id_shim::ShareId;
use objc::rc::{Id, Shared};
use objc::runtime::Object;

use crate::foundation::id;
Expand All @@ -10,14 +10,14 @@ use crate::foundation::id;
/// application/user.
#[derive(Clone, Debug)]
pub struct PrintSettings {
pub inner: ShareId<Object>
pub inner: Id<Object, Shared>
}

impl PrintSettings {
/// Internal method, constructs a wrapper around the backing `NSDictionary` print settings.
pub(crate) fn with_inner(inner: id) -> Self {
PrintSettings {
inner: unsafe { ShareId::from_ptr(inner) }
inner: unsafe { Id::retain(inner).unwrap() }
}
}
}
2 changes: 1 addition & 1 deletion src/appkit/toolbar/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ extern "C" fn item_for_identifier<T: ToolbarDelegate>(this: &Object, _: Sel, _:

/// Registers a `NSToolbar` subclass, and configures it to hold some ivars for various things we need
/// to store. We use it as our delegate as well, just to cut down on moving pieces.
pub(crate) fn register_toolbar_class<T: ToolbarDelegate>(instance: &T) -> *const Class {
pub(crate) fn register_toolbar_class<T: ToolbarDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSObject", instance.subclass_name(), |decl| unsafe {
// For callbacks
decl.add_ivar::<usize>(TOOLBAR_PTR);
Expand Down
Loading

0 comments on commit 7436f7b

Please sign in to comment.