Initial conversion to objc2 (#30)

* Use objc2

* Replace `objc_id`

* Remove sel_impl import

* Fix `add_method` calls

* Fix accessing raw FFI functions

* Fix Encode impl

* Fix message sends arguments that do not implement `Encode`

* Use immutable reference in a few places where now necessary

See https://github.com/madsmtm/objc2/pull/150 for a bit of background

* Add a few Send + Sync bounds where examples require it

This is something we'll need to look into properly

* Use `&'static Class` instead of `*const Class`

Safer and more ergonomic. Also required for `msg_send_id!` macro

* Use msg_send_id! and rc::Id

* Update objc2 to v0.3.0-beta.2

* Replace `BOOL` with `Bool` when declaring delegates

This makes cacao compile on Aarch64 again

* Remove a few impossible to use correctly `into_inner` functions

These consumed `self`, and hence also dropped `Id` variable that was responsible for keeping the returned pointer alive

* Remove a few impossible to use correctly `From` implementations

* Quickly fix UB with using BACKGROUND_COLOR ivar

* Fix double-freeing of windows

* Fix double freeing of strings

* Fix a few remaining double-frees
This commit is contained in:
Mads Marquart 2023-09-11 18:59:21 +02:00 committed by GitHub
parent 4f40d62623
commit 094ed59a04
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
114 changed files with 1248 additions and 1455 deletions

View file

@ -209,9 +209,7 @@ impl View {
center_x: LayoutAnchorX::center(view), center_x: LayoutAnchorX::center(view),
center_y: LayoutAnchorY::center(view), center_y: LayoutAnchorY::center(view),
layer: Layer::wrap(unsafe { layer: Layer::from_id(unsafe { msg_send_id![view, layer] }),
msg_send![view, layer]
}),
objc: ObjcProperty::retain(view), objc: ObjcProperty::retain(view),
} }
@ -293,7 +291,8 @@ impl<T> View<T> {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
self.objc.with_mut(|obj| unsafe { self.objc.with_mut(|obj| unsafe {
(&mut *obj).set_ivar(BACKGROUND_COLOR, color); // TODO: Fix this unnecessary retain!
(&mut *obj).set_ivar::<id>(BACKGROUND_COLOR, msg_send![color, retain]);
}); });
#[cfg(target_os = "ios")] #[cfg(target_os = "ios")]
@ -352,22 +351,22 @@ 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. 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 ``` rust
pub(crate) fn register_view_class() -> *const Class { pub(crate) fn register_view_class() -> &'static Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class; static mut VIEW_CLASS: Option<'static Class> = None;
static INIT: Once = Once::new(); static INIT: Once = Once::new();
INIT.call_once(|| unsafe { INIT.call_once(|| unsafe {
let superclass = class!(NSView); let superclass = class!(NSView);
let mut decl = ClassDecl::new("RSTView", superclass).unwrap(); let mut decl = ClassDecl::new("RSTView", superclass).unwrap();
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
decl.add_ivar::<id>(BACKGROUND_COLOR); decl.add_ivar::<id>(BACKGROUND_COLOR);
VIEW_CLASS = decl.register(); VIEW_CLASS = Some(decl.register());
}); });
unsafe { VIEW_CLASS } unsafe { VIEW_CLASS.unwrap() }
} }
``` ```
@ -377,19 +376,19 @@ 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: For our _delegate_ types, we need a different class creation method - one that creates a subclass per-unique-type:
``` rust ``` 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 { load_or_register_class("NSView", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR); decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
decl.add_ivar::<id>(BACKGROUND_COLOR); decl.add_ivar::<id>(BACKGROUND_COLOR);
decl.add_method( decl.add_method(
sel!(isFlipped), sel!(isFlipped),
enforce_normalcy as extern "C" fn(&Object, _) -> BOOL enforce_normalcy as extern "C" fn(_, _) -> _,
); );
decl.add_method( decl.add_method(
sel!(draggingEntered:), sel!(draggingEntered:),
dragging_entered::<T> as extern "C" fn (&mut Object, _, _) -> NSUInteger dragging_entered::<T> as extern "C" fn (_, _, _) -> _,
); );
}) })
} }
@ -401,18 +400,18 @@ to the Rust `ViewDelegate` implementation.
The methods we're setting up can range from simple to complex - take `isFlipped`: The methods we're setting up can range from simple to complex - take `isFlipped`:
``` rust ``` rust
extern "C" fn is_flipped(_: &Object, _: Sel) -> BOOL { extern "C" fn is_flipped(_: &Object, _: Sel) -> Bool {
return YES; return Bool::YES;
} }
``` ```
Here, we just want to tell `NSView` to use top,left as the origin point, so we need to respond `YES` in this subclass method. Here, we just want to tell `NSView` to use top,left as the origin point, so we need to respond `Bool::YES` in this subclass method.
``` rust ``` rust
extern "C" fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger { extern "C" fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = utils::load::<T>(this, VIEW_DELEGATE_PTR); let view = utils::load::<T>(this, VIEW_DELEGATE_PTR);
view.dragging_entered(DragInfo { view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}).into() }).into()
} }
``` ```

View file

@ -20,15 +20,16 @@ rustdoc-args = ["--cfg", "docsrs"]
[dependencies] [dependencies]
bitmask-enum = "2.2.1" bitmask-enum = "2.2.1"
block = "0.1.6" objc = { version = "=0.3.0-beta.2", package = "objc2" }
core-foundation = "0.9" block = { version = "=0.2.0-alpha.6", package = "block2" }
core-graphics = "0.23" # Temporary: Patched versions that implement `Encode` for common types
# Branch: `objc2`
core-foundation = { git = "https://github.com/madsmtm/core-foundation-rs.git", rev = "7d593d016175755e492a92ef89edca68ac3bd5cd" }
core-graphics = { git = "https://github.com/madsmtm/core-foundation-rs.git", rev = "7d593d016175755e492a92ef89edca68ac3bd5cd" }
dispatch = "0.2.0" dispatch = "0.2.0"
infer = { version = "0.15", optional = true } infer = { version = "0.15", optional = true }
lazy_static = "1.4.0" lazy_static = "1.4.0"
libc = "0.2" libc = "0.2"
objc = "0.2.7"
objc_id = "0.1.1"
os_info = "3.0.1" os_info = "3.0.1"
url = "2.1.1" url = "2.1.1"
uuid = { version = "1.1", features = ["v4"], optional = true } uuid = { version = "1.1", features = ["v4"], optional = true }

View file

@ -1,4 +1,4 @@
use cacao::objc::{msg_send, sel, sel_impl}; use cacao::objc::{msg_send, sel};
use cacao::button::Button; use cacao::button::Button;
use cacao::input::{TextField, TextFieldDelegate}; use cacao::input::{TextField, TextFieldDelegate};
@ -35,12 +35,12 @@ impl BrowserToolbar {
let back_button = Button::new("Back"); let back_button = Button::new("Back");
let mut back_item = ToolbarItem::new(BACK_BUTTON); let mut back_item = ToolbarItem::new(BACK_BUTTON);
back_item.set_button(back_button); back_item.set_button(back_button);
back_item.set_action(|| Action::Back.dispatch()); back_item.set_action(|_| Action::Back.dispatch());
let forwards_button = Button::new("Forwards"); let forwards_button = Button::new("Forwards");
let mut forwards_item = ToolbarItem::new(FWDS_BUTTON); let mut forwards_item = ToolbarItem::new(FWDS_BUTTON);
forwards_item.set_button(forwards_button); forwards_item.set_button(forwards_button);
forwards_item.set_action(|| Action::Forwards.dispatch()); forwards_item.set_action(|_| Action::Forwards.dispatch());
let url_bar = TextField::with(URLBar); let url_bar = TextField::with(URLBar);
let url_bar_item = ToolbarItem::new(URL_BAR); let url_bar_item = ToolbarItem::new(URL_BAR);

View file

@ -24,16 +24,16 @@
//! } //! }
//! ``` //! ```
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::foundation::{id, NSString}; use crate::foundation::{id, NSString};
/// Represents an `NSAlert`. Has no information other than the retained pointer to the Objective C /// Represents an `NSAlert`. Has no information other than the retained pointer to the Objective C
/// side, so... don't bother inspecting this. /// side, so... don't bother inspecting this.
#[derive(Debug)] #[derive(Debug)]
pub struct Alert(Id<Object>); pub struct Alert(Id<Object, Owned>);
impl Alert { impl Alert {
/// Creates a basic `NSAlert`, storing a pointer to it in the Objective C runtime. /// Creates a basic `NSAlert`, storing a pointer to it in the Objective C runtime.
@ -44,11 +44,11 @@ impl Alert {
let ok = NSString::new("OK"); let ok = NSString::new("OK");
Alert(unsafe { Alert(unsafe {
let alert: id = msg_send![class!(NSAlert), new]; let mut alert = msg_send_id![class!(NSAlert), new];
let _: () = msg_send![alert, setMessageText: title]; let _: () = msg_send![&mut alert, setMessageText: &*title];
let _: () = msg_send![alert, setInformativeText: message]; let _: () = msg_send![&mut alert, setInformativeText: &*message];
let _: () = msg_send![alert, addButtonWithTitle: ok]; let _: () = msg_send![&mut alert, addButtonWithTitle: &*ok];
Id::from_ptr(alert) alert
}) })
} }

View file

@ -1,5 +1,5 @@
use block::ConcreteBlock; use block::ConcreteBlock;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use crate::foundation::id; use crate::foundation::id;
@ -39,7 +39,7 @@ impl AnimationContext {
unsafe { unsafe {
//let context: id = msg_send![class!(NSAnimationContext), currentContext]; //let context: id = msg_send![class!(NSAnimationContext), currentContext];
let _: () = msg_send![class!(NSAnimationContext), runAnimationGroup: block]; let _: () = msg_send![class!(NSAnimationContext), runAnimationGroup: &*block];
} }
} }
@ -66,8 +66,11 @@ impl AnimationContext {
unsafe { unsafe {
//let context: id = msg_send![class!(NSAnimationContext), currentContext]; //let context: id = msg_send![class!(NSAnimationContext), currentContext];
let _: () = msg_send![class!(NSAnimationContext), runAnimationGroup:block let _: () = msg_send![
completionHandler:completion_block]; class!(NSAnimationContext),
runAnimationGroup: &*block,
completionHandler: &*completion_block,
];
} }
} }
} }

View file

@ -7,6 +7,6 @@ use objc::runtime::Class;
use crate::foundation::load_or_register_class; use crate::foundation::load_or_register_class;
/// Used for injecting a custom NSApplication. Currently does nothing. /// Used for injecting a custom NSApplication. Currently does nothing.
pub(crate) fn register_app_class() -> *const Class { pub(crate) fn register_app_class() -> &'static Class {
load_or_register_class("NSApplication", "RSTApplication", |decl| unsafe {}) load_or_register_class("NSApplication", "RSTApplication", |decl| unsafe {})
} }

View file

@ -5,8 +5,8 @@
use std::ffi::c_void; use std::ffi::c_void;
use block::Block; use block::Block;
use objc::runtime::{Class, Object, Sel}; use objc::runtime::{Bool, Class, Object, Sel};
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, sel};
use url::Url; use url::Url;
use crate::appkit::app::{AppDelegate, APP_PTR}; use crate::appkit::app::{AppDelegate, APP_PTR};
@ -14,7 +14,7 @@ use crate::appkit::printing::PrintSettings;
#[cfg(feature = "cloudkit")] #[cfg(feature = "cloudkit")]
use crate::cloudkit::share::CKShareMetaData; use crate::cloudkit::share::CKShareMetaData;
use crate::error::Error; use crate::error::Error;
use crate::foundation::{id, load_or_register_class, nil, to_bool, NSArray, NSString, NSUInteger, BOOL, NO, YES}; use crate::foundation::{id, load_or_register_class, nil, NSArray, NSString, NSUInteger};
use crate::user_activity::UserActivity; use crate::user_activity::UserActivity;
/// A handy method for grabbing our `AppDelegate` from the pointer. This is different from our /// A handy method for grabbing our `AppDelegate` from the pointer. This is different from our
@ -99,11 +99,8 @@ extern "C" fn did_update<T: AppDelegate>(this: &Object, _: Sel, _: id) {
/// Fires when the Application Delegate receives a /// Fires when the Application Delegate receives a
/// `applicationShouldHandleReopen:hasVisibleWindows:` notification. /// `applicationShouldHandleReopen:hasVisibleWindows:` notification.
extern "C" fn should_handle_reopen<T: AppDelegate>(this: &Object, _: Sel, _: id, has_visible_windows: BOOL) -> BOOL { extern "C" fn should_handle_reopen<T: AppDelegate>(this: &Object, _: Sel, _: id, has_visible_windows: Bool) -> Bool {
match app::<T>(this).should_handle_reopen(to_bool(has_visible_windows)) { Bool::new(app::<T>(this).should_handle_reopen(has_visible_windows.as_bool()))
true => YES,
false => NO
}
} }
/// Fires when the application delegate receives a `applicationDockMenu:` request. /// Fires when the application delegate receives a `applicationDockMenu:` request.
@ -128,29 +125,23 @@ extern "C" fn did_change_screen_parameters<T: AppDelegate>(this: &Object, _: Sel
/// Fires when the application receives a `application:willContinueUserActivityWithType:` /// Fires when the application receives a `application:willContinueUserActivityWithType:`
/// notification. /// notification.
extern "C" fn will_continue_user_activity_with_type<T: AppDelegate>(this: &Object, _: Sel, _: id, activity_type: id) -> BOOL { extern "C" fn will_continue_user_activity_with_type<T: AppDelegate>(this: &Object, _: Sel, _: id, activity_type: id) -> Bool {
let activity = NSString::retain(activity_type); let activity = NSString::retain(activity_type);
match app::<T>(this).will_continue_user_activity(activity.to_str()) { Bool::new(app::<T>(this).will_continue_user_activity(activity.to_str()))
true => YES,
false => NO
}
} }
/// Fires when the application receives a `application:continueUserActivity:restorationHandler:` notification. /// Fires when the application receives a `application:continueUserActivity:restorationHandler:` notification.
extern "C" fn continue_user_activity<T: AppDelegate>(this: &Object, _: Sel, _: id, activity: id, handler: id) -> BOOL { extern "C" fn continue_user_activity<T: AppDelegate>(this: &Object, _: Sel, _: id, activity: id, handler: id) -> Bool {
// @TODO: This needs to support restorable objects, but it involves a larger question about how // @TODO: This needs to support restorable objects, but it involves a larger question about how
// much `NSObject` retainping we want to do here. For now, pass the handler for whenever it's // much `NSObject` retainping we want to do here. For now, pass the handler for whenever it's
// useful. // useful.
let activity = UserActivity::with_inner(activity); let activity = UserActivity::with_inner(activity);
match app::<T>(this).continue_user_activity(activity, || unsafe { Bool::new(app::<T>(this).continue_user_activity(activity, || unsafe {
let handler = handler as *const Block<(id,), c_void>; let handler = handler as *const Block<(id,), ()>;
(*handler).call((nil,)); (*handler).call((nil,));
}) { }))
true => YES,
false => NO
}
} }
/// Fires when the application receives a /// Fires when the application receives a
@ -199,57 +190,39 @@ extern "C" fn open_urls<T: AppDelegate>(this: &Object, _: Sel, _: id, file_urls:
} }
/// Fires when the application receives an `application:openFileWithoutUI:` message. /// Fires when the application receives an `application:openFileWithoutUI:` message.
extern "C" fn open_file_without_ui<T: AppDelegate>(this: &Object, _: Sel, _: id, file: id) -> BOOL { extern "C" fn open_file_without_ui<T: AppDelegate>(this: &Object, _: Sel, _: id, file: id) -> Bool {
let filename = NSString::retain(file); let filename = NSString::retain(file);
match app::<T>(this).open_file_without_ui(filename.to_str()) { Bool::new(app::<T>(this).open_file_without_ui(filename.to_str()))
true => YES,
false => NO
}
} }
/// Fired when the application receives an `applicationShouldOpenUntitledFile:` message. /// Fired when the application receives an `applicationShouldOpenUntitledFile:` message.
extern "C" fn should_open_untitled_file<T: AppDelegate>(this: &Object, _: Sel, _: id) -> BOOL { extern "C" fn should_open_untitled_file<T: AppDelegate>(this: &Object, _: Sel, _: id) -> Bool {
match app::<T>(this).should_open_untitled_file() { Bool::new(app::<T>(this).should_open_untitled_file())
true => YES,
false => NO
}
} }
/// Fired when the application receives an `applicationShouldTerminateAfterLastWindowClosed:` message. /// Fired when the application receives an `applicationShouldTerminateAfterLastWindowClosed:` message.
extern "C" fn should_terminate_after_last_window_closed<T: AppDelegate>(this: &Object, _: Sel, _: id) -> BOOL { extern "C" fn should_terminate_after_last_window_closed<T: AppDelegate>(this: &Object, _: Sel, _: id) -> Bool {
match app::<T>(this).should_terminate_after_last_window_closed() { Bool::new(app::<T>(this).should_terminate_after_last_window_closed())
true => YES,
false => NO
}
} }
/// Fired when the application receives an `applicationOpenUntitledFile:` message. /// Fired when the application receives an `applicationOpenUntitledFile:` message.
extern "C" fn open_untitled_file<T: AppDelegate>(this: &Object, _: Sel, _: id) -> BOOL { extern "C" fn open_untitled_file<T: AppDelegate>(this: &Object, _: Sel, _: id) -> Bool {
match app::<T>(this).open_untitled_file() { Bool::new(app::<T>(this).open_untitled_file())
true => YES,
false => NO
}
} }
/// Fired when the application receives an `application:openTempFile:` message. /// Fired when the application receives an `application:openTempFile:` message.
extern "C" fn open_temp_file<T: AppDelegate>(this: &Object, _: Sel, _: id, filename: id) -> BOOL { extern "C" fn open_temp_file<T: AppDelegate>(this: &Object, _: Sel, _: id, filename: id) -> Bool {
let filename = NSString::retain(filename); let filename = NSString::retain(filename);
match app::<T>(this).open_temp_file(filename.to_str()) { Bool::new(app::<T>(this).open_temp_file(filename.to_str()))
true => YES,
false => NO
}
} }
/// Fired when the application receives an `application:printFile:` message. /// Fired when the application receives an `application:printFile:` message.
extern "C" fn print_file<T: AppDelegate>(this: &Object, _: Sel, _: id, file: id) -> BOOL { extern "C" fn print_file<T: AppDelegate>(this: &Object, _: Sel, _: id, file: id) -> Bool {
let filename = NSString::retain(file); let filename = NSString::retain(file);
match app::<T>(this).print_file(filename.to_str()) { Bool::new(app::<T>(this).print_file(filename.to_str()))
true => YES,
false => NO
}
} }
/// Fired when the application receives an `application:printFiles:withSettings:showPrintPanels:` /// Fired when the application receives an `application:printFiles:withSettings:showPrintPanels:`
@ -260,7 +233,7 @@ extern "C" fn print_files<T: AppDelegate>(
_: id, _: id,
files: id, files: id,
settings: id, settings: id,
show_print_panels: BOOL show_print_panels: Bool
) -> NSUInteger { ) -> NSUInteger {
let files = NSArray::retain(files) let files = NSArray::retain(files)
.iter() .iter()
@ -269,7 +242,9 @@ extern "C" fn print_files<T: AppDelegate>(
let settings = PrintSettings::with_inner(settings); let settings = PrintSettings::with_inner(settings);
app::<T>(this).print_files(files, settings, to_bool(show_print_panels)).into() app::<T>(this)
.print_files(files, settings, show_print_panels.as_bool())
.into()
} }
/// Called when the application's occlusion state has changed. /// Called when the application's occlusion state has changed.
@ -280,168 +255,156 @@ extern "C" fn did_change_occlusion_state<T: AppDelegate>(this: &Object, _: Sel,
/// Called when the application receives an `application:delegateHandlesKey:` message. /// Called when the application receives an `application:delegateHandlesKey:` message.
/// Note: this may not fire in sandboxed applications. Apple's documentation is unclear on the /// Note: this may not fire in sandboxed applications. Apple's documentation is unclear on the
/// matter. /// matter.
extern "C" fn delegate_handles_key<T: AppDelegate>(this: &Object, _: Sel, _: id, key: id) -> BOOL { extern "C" fn delegate_handles_key<T: AppDelegate>(this: &Object, _: Sel, _: id, key: id) -> Bool {
let key = NSString::retain(key); let key = NSString::retain(key);
match app::<T>(this).delegate_handles_key(key.to_str()) { Bool::new(app::<T>(this).delegate_handles_key(key.to_str()))
true => YES,
false => NO
}
} }
/// Registers an `NSObject` application delegate, and configures it for the various callbacks and /// Registers an `NSObject` application delegate, and configures it for the various callbacks and
/// pointers we need to have. /// pointers we need to have.
pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> *const Class { pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> &'static Class {
load_or_register_class("NSObject", "RSTAppDelegate", |decl| unsafe { load_or_register_class("NSObject", "RSTAppDelegate", |decl| unsafe {
decl.add_ivar::<usize>(APP_PTR); decl.add_ivar::<usize>(APP_PTR);
// Launching Applications // Launching Applications
decl.add_method( decl.add_method(
sel!(applicationWillFinishLaunching:), sel!(applicationWillFinishLaunching:),
will_finish_launching::<T> as extern "C" fn(&Object, _, _) will_finish_launching::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(applicationDidFinishLaunching:), sel!(applicationDidFinishLaunching:),
did_finish_launching::<T> as extern "C" fn(&Object, _, _) did_finish_launching::<T> as extern "C" fn(_, _, _)
); );
// Managing Active Status // Managing Active Status
decl.add_method( decl.add_method(
sel!(applicationWillBecomeActive:), sel!(applicationWillBecomeActive:),
will_become_active::<T> as extern "C" fn(&Object, _, _) will_become_active::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(applicationDidBecomeActive:), sel!(applicationDidBecomeActive:),
did_become_active::<T> as extern "C" fn(&Object, _, _) did_become_active::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(applicationWillResignActive:), sel!(applicationWillResignActive:),
will_resign_active::<T> as extern "C" fn(&Object, _, _) will_resign_active::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(applicationDidResignActive:), sel!(applicationDidResignActive:),
did_resign_active::<T> as extern "C" fn(&Object, _, _) did_resign_active::<T> as extern "C" fn(_, _, _)
); );
// Terminating Applications // Terminating Applications
decl.add_method( decl.add_method(
sel!(applicationShouldTerminate:), sel!(applicationShouldTerminate:),
should_terminate::<T> as extern "C" fn(&Object, _, _) -> NSUInteger should_terminate::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(
sel!(applicationWillTerminate:),
will_terminate::<T> as extern "C" fn(&Object, _, _)
); );
decl.add_method(sel!(applicationWillTerminate:), will_terminate::<T> as extern "C" fn(_, _, _));
decl.add_method( decl.add_method(
sel!(applicationShouldTerminateAfterLastWindowClosed:), sel!(applicationShouldTerminateAfterLastWindowClosed:),
should_terminate_after_last_window_closed::<T> as extern "C" fn(&Object, _, _) -> BOOL should_terminate_after_last_window_closed::<T> as extern "C" fn(_, _, _) -> _
); );
// Hiding Applications // Hiding Applications
decl.add_method(sel!(applicationWillHide:), will_hide::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(applicationWillHide:), will_hide::<T> as extern "C" fn(_, _, _));
decl.add_method(sel!(applicationDidHide:), did_hide::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(applicationDidHide:), did_hide::<T> as extern "C" fn(_, _, _));
decl.add_method(sel!(applicationWillUnhide:), will_unhide::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(applicationWillUnhide:), will_unhide::<T> as extern "C" fn(_, _, _));
decl.add_method(sel!(applicationDidUnhide:), did_unhide::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(applicationDidUnhide:), did_unhide::<T> as extern "C" fn(_, _, _));
// Managing Windows // Managing Windows
decl.add_method(sel!(applicationWillUpdate:), will_update::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(applicationWillUpdate:), will_update::<T> as extern "C" fn(_, _, _));
decl.add_method(sel!(applicationDidUpdate:), did_update::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(applicationDidUpdate:), did_update::<T> as extern "C" fn(_, _, _));
decl.add_method( decl.add_method(
sel!(applicationShouldHandleReopen:hasVisibleWindows:), sel!(applicationShouldHandleReopen:hasVisibleWindows:),
should_handle_reopen::<T> as extern "C" fn(&Object, _, _, BOOL) -> BOOL should_handle_reopen::<T> as extern "C" fn(_, _, _, _) -> _
); );
// Dock Menu // Dock Menu
decl.add_method( decl.add_method(sel!(applicationDockMenu:), dock_menu::<T> as extern "C" fn(_, _, _) -> _);
sel!(applicationDockMenu:),
dock_menu::<T> as extern "C" fn(&Object, _, _) -> id
);
// Displaying Errors // Displaying Errors
decl.add_method( decl.add_method(
sel!(application:willPresentError:), sel!(application:willPresentError:),
will_present_error::<T> as extern "C" fn(&Object, _, _, id) -> id will_present_error::<T> as extern "C" fn(_, _, _, _) -> _
); );
// Managing the Screen // Managing the Screen
decl.add_method( decl.add_method(
sel!(applicationDidChangeScreenParameters:), sel!(applicationDidChangeScreenParameters:),
did_change_screen_parameters::<T> as extern "C" fn(&Object, _, _) did_change_screen_parameters::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(applicationDidChangeOcclusionState:), sel!(applicationDidChangeOcclusionState:),
did_change_occlusion_state::<T> as extern "C" fn(&Object, _, _) did_change_occlusion_state::<T> as extern "C" fn(_, _, _)
); );
// User Activities // User Activities
decl.add_method( decl.add_method(
sel!(application:willContinueUserActivityWithType:), sel!(application:willContinueUserActivityWithType:),
will_continue_user_activity_with_type::<T> as extern "C" fn(&Object, _, _, id) -> BOOL will_continue_user_activity_with_type::<T> as extern "C" fn(_, _, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(application:continueUserActivity:restorationHandler:), sel!(application:continueUserActivity:restorationHandler:),
continue_user_activity::<T> as extern "C" fn(&Object, _, _, id, id) -> BOOL continue_user_activity::<T> as extern "C" fn(_, _, _, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(application:didFailToContinueUserActivityWithType:error:), sel!(application:didFailToContinueUserActivityWithType:error:),
failed_to_continue_user_activity::<T> as extern "C" fn(&Object, _, _, id, id) failed_to_continue_user_activity::<T> as extern "C" fn(_, _, _, _, _)
); );
decl.add_method( decl.add_method(
sel!(application:didUpdateUserActivity:), sel!(application:didUpdateUserActivity:),
did_update_user_activity::<T> as extern "C" fn(&Object, _, _, id) did_update_user_activity::<T> as extern "C" fn(_, _, _, _)
); );
// Handling push notifications // Handling push notifications
decl.add_method( decl.add_method(
sel!(application:didRegisterForRemoteNotificationsWithDeviceToken:), sel!(application:didRegisterForRemoteNotificationsWithDeviceToken:),
registered_for_remote_notifications::<T> as extern "C" fn(&Object, _, _, id) registered_for_remote_notifications::<T> as extern "C" fn(_, _, _, _)
); );
decl.add_method( decl.add_method(
sel!(application:didFailToRegisterForRemoteNotificationsWithError:), sel!(application:didFailToRegisterForRemoteNotificationsWithError:),
failed_to_register_for_remote_notifications::<T> as extern "C" fn(&Object, _, _, id) failed_to_register_for_remote_notifications::<T> as extern "C" fn(_, _, _, _)
); );
decl.add_method( decl.add_method(
sel!(application:didReceiveRemoteNotification:), sel!(application:didReceiveRemoteNotification:),
did_receive_remote_notification::<T> as extern "C" fn(&Object, _, _, id) did_receive_remote_notification::<T> as extern "C" fn(_, _, _, _)
); );
// CloudKit // CloudKit
#[cfg(feature = "cloudkit")] #[cfg(feature = "cloudkit")]
decl.add_method( decl.add_method(
sel!(application:userDidAcceptCloudKitShareWithMetadata:), sel!(application:userDidAcceptCloudKitShareWithMetadata:),
accepted_cloudkit_share::<T> as extern "C" fn(&Object, _, _, id) accepted_cloudkit_share::<T> as extern "C" fn(_, _, _, _)
); );
// Opening Files // Opening Files
decl.add_method( decl.add_method(sel!(application:openURLs:), open_urls::<T> as extern "C" fn(_, _, _, _));
sel!(application:openURLs:),
open_urls::<T> as extern "C" fn(&Object, _, _, id)
);
decl.add_method( decl.add_method(
sel!(application:openFileWithoutUI:), sel!(application:openFileWithoutUI:),
open_file_without_ui::<T> as extern "C" fn(&Object, _, _, id) -> BOOL open_file_without_ui::<T> as extern "C" fn(_, _, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(applicationShouldOpenUntitledFile:), sel!(applicationShouldOpenUntitledFile:),
should_open_untitled_file::<T> as extern "C" fn(&Object, _, _) -> BOOL should_open_untitled_file::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(applicationOpenUntitledFile:), sel!(applicationOpenUntitledFile:),
open_untitled_file::<T> as extern "C" fn(&Object, _, _) -> BOOL open_untitled_file::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(application:openTempFile:), sel!(application:openTempFile:),
open_temp_file::<T> as extern "C" fn(&Object, _, _, id) -> BOOL open_temp_file::<T> as extern "C" fn(_, _, _, _) -> _
); );
// Printing // Printing
decl.add_method( decl.add_method(
sel!(application:printFile:), sel!(application:printFile:),
print_file::<T> as extern "C" fn(&Object, _, _, id) -> BOOL print_file::<T> as extern "C" fn(_, _, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(application:printFiles:withSettings:showPrintPanels:), sel!(application:printFiles:withSettings:showPrintPanels:),
print_files::<T> as extern "C" fn(&Object, _, id, id, id, BOOL) -> NSUInteger print_files::<T> as extern "C" fn(_, _, _, _, _, _) -> _
); );
// @TODO: Restoring Application State // @TODO: Restoring Application State
@ -450,7 +413,7 @@ pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> *co
// Scripting // Scripting
decl.add_method( decl.add_method(
sel!(application:delegateHandlesKey:), sel!(application:delegateHandlesKey:),
delegate_handles_key::<T> as extern "C" fn(&Object, _, _, id) -> BOOL delegate_handles_key::<T> as extern "C" fn(_, _, _, _) -> _
); );
}) })
} }

View file

@ -39,9 +39,9 @@ use std::sync::{Arc, Mutex};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::appkit::menu::Menu; use crate::appkit::menu::Menu;
use crate::foundation::{id, nil, AutoReleasePool, NSUInteger, NO, YES}; use crate::foundation::{id, nil, AutoReleasePool, NSUInteger, NO, YES};
@ -88,11 +88,11 @@ pub(crate) fn shared_application<T, F: Fn(id) -> T>(handler: F) -> T {
/// application. /// application.
pub struct App<T = (), M = ()> { pub struct App<T = (), M = ()> {
/// The underlying Objective-C Object. /// 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 /// The underlying Objective-C Object, which in this case is a delegate that forwards to the
/// app delegate. /// app delegate.
pub objc_delegate: Id<Object>, pub objc_delegate: Id<Object, Owned>,
/// The stored `AppDelegate`. /// The stored `AppDelegate`.
pub delegate: Box<T>, pub delegate: Box<T>,
@ -144,20 +144,17 @@ where
let pool = AutoReleasePool::new(); let pool = AutoReleasePool::new();
let objc = unsafe { let objc: Id<_, _> = unsafe { msg_send_id![register_app_class(), sharedApplication] };
let app: id = msg_send![register_app_class(), sharedApplication];
Id::from_ptr(app)
};
let app_delegate = Box::new(delegate); let app_delegate = Box::new(delegate);
let objc_delegate = unsafe { let objc_delegate = unsafe {
let delegate_class = register_app_delegate_class::<T>(); 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];
let delegate_ptr: *const T = &*app_delegate; let delegate_ptr: *const T = &*app_delegate;
(&mut *delegate).set_ivar(APP_PTR, delegate_ptr as usize); delegate.set_ivar(APP_PTR, delegate_ptr as usize);
let _: () = msg_send![&*objc, setDelegate: delegate]; let _: () = msg_send![&*objc, setDelegate: &*delegate];
Id::from_ptr(delegate) delegate
}; };
App { App {

View file

@ -1,4 +1,4 @@
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use crate::foundation::{id, NO, YES}; use crate::foundation::{id, NO, YES};

View file

@ -1,9 +1,9 @@
use bitmask_enum::bitmask; use bitmask_enum::bitmask;
use block::ConcreteBlock; use block::ConcreteBlock;
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::events::EventType; use crate::events::EventType;
use crate::foundation::{id, nil, NSInteger, NSPoint, NSString}; use crate::foundation::{id, nil, NSInteger, NSPoint, NSString};
@ -53,15 +53,15 @@ pub enum EventMask {
/// A wrapper over an `NSEvent`. /// A wrapper over an `NSEvent`.
#[derive(Debug)] #[derive(Debug)]
pub struct EventMonitor(pub Id<Object>); pub struct EventMonitor(pub Id<Object, Owned>);
/// A wrapper over an `NSEvent`. /// A wrapper over an `NSEvent`.
#[derive(Debug)] #[derive(Debug)]
pub struct Event(pub Id<Object>); pub struct Event(pub Id<Object, Owned>);
impl Event { impl Event {
pub(crate) fn new(objc: id) -> Self { pub(crate) fn new(objc: id) -> Self {
Event(unsafe { Id::from_ptr(objc) }) Event(unsafe { Id::retain(objc).unwrap() })
} }
/// The event's type. /// The event's type.
@ -137,8 +137,11 @@ impl Event {
let block = block.copy(); let block = block.copy();
EventMonitor(unsafe { EventMonitor(unsafe {
msg_send![class!(NSEvent), addLocalMonitorForEventsMatchingMask:mask.bits msg_send_id![
handler:block] class!(NSEvent),
addLocalMonitorForEventsMatchingMask: mask.bits,
handler: &*block,
]
}) })
} }
@ -163,8 +166,11 @@ impl Event {
let block = block.copy(); let block = block.copy();
EventMonitor(unsafe { EventMonitor(unsafe {
msg_send![class!(NSEvent), addGlobalMonitorForEventsMatchingMask:mask.bits msg_send_id![
handler:block] class!(NSEvent),
addGlobalMonitorForEventsMatchingMask: mask.bits,
handler: &*block,
]
}) })
} }
} }

View file

@ -1,17 +1,17 @@
use std::convert::TryFrom; use std::convert::TryFrom;
use objc::{class, msg_send, runtime::Object, sel, sel_impl}; use objc::rc::{Id, Shared};
use objc_id::ShareId; use objc::{class, msg_send, msg_send_id, runtime::Object, sel};
use crate::foundation::NSUInteger; use crate::foundation::NSUInteger;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct HapticFeedbackPerformer(pub ShareId<Object>); pub struct HapticFeedbackPerformer(pub Id<Object, Shared>);
impl HapticFeedbackPerformer { impl HapticFeedbackPerformer {
pub fn perform(&self, pattern: FeedbackPattern, performance_time: PerformanceTime) { pub fn perform(&self, pattern: FeedbackPattern, performance_time: PerformanceTime) {
unsafe { unsafe {
let _: () = msg_send![&*self.0, performFeedbackPattern: pattern performanceTime: performance_time]; let _: () = msg_send![&*self.0, performFeedbackPattern: pattern as isize performanceTime: performance_time as usize];
} }
} }
} }
@ -19,10 +19,7 @@ impl HapticFeedbackPerformer {
impl Default for HapticFeedbackPerformer { impl Default for HapticFeedbackPerformer {
/// Returns the default haptic feedback performer. /// Returns the default haptic feedback performer.
fn default() -> Self { fn default() -> Self {
HapticFeedbackPerformer(unsafe { HapticFeedbackPerformer(unsafe { msg_send_id![class!(NSHapticFeedbackManager), defaultPerformer] })
let manager = msg_send![class!(NSHapticFeedbackManager), defaultPerformer];
ShareId::from_ptr(manager)
})
} }
} }

View file

@ -4,9 +4,9 @@
use std::fmt; use std::fmt;
use objc::rc::{Id, Owned};
use objc::runtime::{Class, Object, Sel}; use objc::runtime::{Class, Object, Sel};
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::events::EventModifierFlag; use crate::events::EventModifierFlag;
use crate::foundation::{id, load_or_register_class, NSString, NSUInteger}; use crate::foundation::{id, load_or_register_class, NSString, NSUInteger};
@ -37,7 +37,7 @@ fn make_menu_item<S: AsRef<str>>(
key: Option<&str>, key: Option<&str>,
action: Option<Sel>, action: Option<Sel>,
modifiers: Option<&[EventModifierFlag]> modifiers: Option<&[EventModifierFlag]>
) -> Id<Object> { ) -> Id<Object, Owned> {
unsafe { unsafe {
let title = NSString::new(title.as_ref()); let title = NSString::new(title.as_ref());
@ -50,14 +50,21 @@ fn make_menu_item<S: AsRef<str>>(
// Stock menu items that use selectors targeted at system pieces are just standard // 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 // `NSMenuItem`s. If there's no custom ones, we use our subclass that has a slot to store a
// handler pointer. // handler pointer.
let alloc: id = msg_send![register_menu_item_class(), alloc]; let alloc = msg_send_id![register_menu_item_class(), alloc];
let item = Id::from_retained_ptr(match action { let item: Id<_, _> = match action {
Some(a) => msg_send![alloc, initWithTitle:&*title action:a keyEquivalent:&*key], Some(a) => msg_send_id![
alloc,
None => msg_send![alloc, initWithTitle:&*title initWithTitle: &*title,
action:sel!(fireBlockAction:) action: a,
keyEquivalent:&*key] keyEquivalent: &*key,
}); ],
None => msg_send_id![
alloc,
initWithTitle: &*title,
action: sel!(fireBlockAction:),
keyEquivalent: &*key,
]
};
if let Some(modifiers) = modifiers { if let Some(modifiers) = modifiers {
let mut key_mask: NSUInteger = 0; let mut key_mask: NSUInteger = 0;
@ -83,7 +90,7 @@ pub enum MenuItem {
/// You can (and should) create this variant via the `new(title)` method, but if you need to do /// 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 /// something crazier, then wrap it in this and you can hook into the Cacao menu system
/// accordingly. /// accordingly.
Custom(Id<Object>), Custom(Id<Object, Owned>),
/// Shows a standard "About" item, which will bring up the necessary window when clicked /// 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 /// (include a `credits.html` in your App to make use of here). The argument baked in here
@ -150,7 +157,7 @@ pub enum MenuItem {
impl MenuItem { impl MenuItem {
/// Consumes and returns a handle for the underlying MenuItem. This is internal as we make a few assumptions /// 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. /// 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 { match self {
Self::Custom(objc) => objc, Self::Custom(objc) => objc,
@ -211,8 +218,7 @@ impl MenuItem {
Self::Separator => { Self::Separator => {
let cls = class!(NSMenuItem); let cls = class!(NSMenuItem);
let separator: id = msg_send![cls, separatorItem]; msg_send_id![cls, separatorItem]
Id::from_ptr(separator)
} }
} }
} }
@ -229,7 +235,7 @@ impl MenuItem {
if let MenuItem::Custom(objc) = self { if let MenuItem::Custom(objc) = self {
unsafe { unsafe {
let key = NSString::new(key); let key = NSString::new(key);
let _: () = msg_send![&*objc, setKeyEquivalent: key]; let _: () = msg_send![&*objc, setKeyEquivalent: &*key];
} }
return MenuItem::Custom(objc); return MenuItem::Custom(objc);
@ -314,11 +320,11 @@ 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 /// 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. /// where Carbon still lurks, and subclassing things can get weird.
pub(crate) fn register_menu_item_class() -> *const Class { pub(crate) fn register_menu_item_class() -> &'static Class {
load_or_register_class("NSMenuItem", "CacaoMenuItem", |decl| unsafe { load_or_register_class("NSMenuItem", "CacaoMenuItem", |decl| unsafe {
decl.add_ivar::<usize>(BLOCK_PTR); decl.add_ivar::<usize>(BLOCK_PTR);
decl.add_method(sel!(dealloc), dealloc_cacao_menuitem as extern "C" fn(&Object, _)); decl.add_method(sel!(dealloc), dealloc_cacao_menuitem as extern "C" fn(_, _));
decl.add_method(sel!(fireBlockAction:), fire_block_action as extern "C" fn(&Object, _, id)); decl.add_method(sel!(fireBlockAction:), fire_block_action as extern "C" fn(_, _, _));
}) })
} }

View file

@ -2,9 +2,9 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use objc::rc::{Id, Owned, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::{Id, ShareId};
use crate::appkit::menu::item::MenuItem; use crate::appkit::menu::item::MenuItem;
use crate::foundation::{id, NSInteger, NSString}; use crate::foundation::{id, NSInteger, NSString};
@ -12,7 +12,7 @@ use crate::foundation::{id, NSInteger, NSString};
/// A struct that represents an `NSMenu`. It takes ownership of items, and handles instrumenting /// A struct that represents an `NSMenu`. It takes ownership of items, and handles instrumenting
/// them throughout the application lifecycle. /// them throughout the application lifecycle.
#[derive(Debug)] #[derive(Debug)]
pub struct Menu(pub Id<Object>); pub struct Menu(pub Id<Object, Owned>);
impl Menu { impl Menu {
/// Creates a new `Menu` with the given title, and uses the passed items as submenu items. /// Creates a new `Menu` with the given title, and uses the passed items as submenu items.
@ -27,16 +27,16 @@ impl Menu {
pub fn new(title: &str, items: Vec<MenuItem>) -> Self { pub fn new(title: &str, items: Vec<MenuItem>) -> Self {
Menu(unsafe { Menu(unsafe {
let cls = class!(NSMenu); let cls = class!(NSMenu);
let alloc: id = msg_send![cls, alloc]; let alloc = msg_send_id![cls, alloc];
let title = NSString::new(title); let title = NSString::new(title);
let menu: id = msg_send![alloc, initWithTitle:&*title]; let mut menu = msg_send_id![alloc, initWithTitle: &*title];
for item in items.into_iter() { for item in items.into_iter() {
let objc = item.to_objc(); let objc = item.to_objc();
let _: () = msg_send![menu, addItem:&*objc]; let _: () = msg_send![&mut menu, addItem:&*objc];
} }
Id::from_retained_ptr(menu) menu
}) })
} }

View file

@ -1,8 +1,8 @@
//! Represents settings for printing items. Backed by an `NSDictionary` in Objective-C, this struct //! Represents settings for printing items. Backed by an `NSDictionary` in Objective-C, this struct
//! aims to make it easier to query/process printing operations. //! aims to make it easier to query/process printing operations.
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc_id::ShareId;
use crate::foundation::id; use crate::foundation::id;
@ -10,14 +10,14 @@ use crate::foundation::id;
/// application/user. /// application/user.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PrintSettings { pub struct PrintSettings {
pub inner: ShareId<Object> pub inner: Id<Object, Shared>
} }
impl PrintSettings { impl PrintSettings {
/// Internal method, constructs a wrapper around the backing `NSDictionary` print settings. /// Internal method, constructs a wrapper around the backing `NSDictionary` print settings.
pub(crate) fn with_inner(inner: id) -> Self { pub(crate) fn with_inner(inner: id) -> Self {
PrintSettings { PrintSettings {
inner: unsafe { ShareId::from_ptr(inner) } inner: unsafe { Id::retain(inner).unwrap() }
} }
} }
} }

View file

@ -7,9 +7,9 @@ use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use objc::declare::ClassDecl; use objc::declare::ClassDecl;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object, Sel}; use objc::runtime::{Class, Object, Sel};
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::color::Color; use crate::color::Color;
use crate::control::Control; use crate::control::Control;
@ -171,7 +171,7 @@ impl SegmentedControl {
pub fn set_tooltip_segment(&mut self, index: NSUInteger, tooltip: &str) { pub fn set_tooltip_segment(&mut self, index: NSUInteger, tooltip: &str) {
self.objc.with_mut(|obj| unsafe { self.objc.with_mut(|obj| unsafe {
let converted = NSString::new(tooltip); let converted = NSString::new(tooltip);
let _: () = msg_send![obj, setToolTip: converted forSegment: index]; let _: () = msg_send![obj, setToolTip: &*converted.objc, forSegment: index];
}) })
} }
@ -193,7 +193,7 @@ impl SegmentedControl {
/// best just to message pass or something. /// best just to message pass or something.
pub fn set_action<F: Fn(i32) + Send + Sync + 'static>(&mut self, action: F) { pub fn set_action<F: Fn(i32) + Send + Sync + 'static>(&mut self, action: F) {
// @TODO: This probably isn't ideal but gets the job done for now; needs revisiting. // @TODO: This probably isn't ideal but gets the job done for now; needs revisiting.
let this = self.objc.get(|obj| unsafe { ShareId::from_ptr(msg_send![obj, self]) }); let this: Id<_, Shared> = self.objc.get(|obj| unsafe { msg_send_id![obj, self] });
let handler = TargetActionHandler::new(&*this, move |obj: *const Object| unsafe { let handler = TargetActionHandler::new(&*this, move |obj: *const Object| unsafe {
let selected: i32 = msg_send![obj, selectedSegment]; let selected: i32 = msg_send![obj, selectedSegment];
action(selected) action(selected)

View file

@ -3,11 +3,12 @@
use std::sync::Once; use std::sync::Once;
use objc::declare::ClassDecl; use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel}; use objc::rc::Id;
use objc::{class, msg_send, sel, sel_impl}; use objc::runtime::{Bool, Class, Object, Sel};
use objc::{class, msg_send, sel};
use crate::appkit::toolbar::{ToolbarDelegate, TOOLBAR_PTR}; use crate::appkit::toolbar::{ToolbarDelegate, TOOLBAR_PTR};
use crate::foundation::{id, load_or_register_class, NSArray, NSString, BOOL}; use crate::foundation::{id, load_or_register_class, NSArray, NSString};
use crate::utils::load; use crate::utils::load;
/// Retrieves and passes the allowed item identifiers for this toolbar. /// Retrieves and passes the allowed item identifiers for this toolbar.
@ -21,7 +22,7 @@ extern "C" fn allowed_item_identifiers<T: ToolbarDelegate>(this: &Object, _: Sel
.collect::<Vec<id>>() .collect::<Vec<id>>()
.into(); .into();
identifiers.into() Id::autorelease_return(identifiers.0)
} }
/// Retrieves and passes the default item identifiers for this toolbar. /// Retrieves and passes the default item identifiers for this toolbar.
@ -35,7 +36,7 @@ extern "C" fn default_item_identifiers<T: ToolbarDelegate>(this: &Object, _: Sel
.collect::<Vec<id>>() .collect::<Vec<id>>()
.into(); .into();
identifiers.into() Id::autorelease_return(identifiers.0)
} }
/// Retrieves and passes the default item identifiers for this toolbar. /// Retrieves and passes the default item identifiers for this toolbar.
@ -49,14 +50,14 @@ extern "C" fn selectable_item_identifiers<T: ToolbarDelegate>(this: &Object, _:
.collect::<Vec<id>>() .collect::<Vec<id>>()
.into(); .into();
identifiers.into() Id::autorelease_return(identifiers.0)
} }
/// Loads the controller, grabs whatever item is for this identifier, and returns what the /// Loads the controller, grabs whatever item is for this identifier, and returns what the
/// Objective-C runtime needs. /// Objective-C runtime needs.
extern "C" fn item_for_identifier<T: ToolbarDelegate>(this: &Object, _: Sel, _: id, identifier: id, _: BOOL) -> id { extern "C" fn item_for_identifier<T: ToolbarDelegate>(this: &Object, _: Sel, _: id, identifier: id, _: Bool) -> id {
let toolbar = load::<T>(this, TOOLBAR_PTR); let toolbar = load::<T>(this, TOOLBAR_PTR);
let identifier = NSString::from_retained(identifier); let identifier = NSString::retain(identifier);
let item = toolbar.item_for(identifier.to_str()); let item = toolbar.item_for(identifier.to_str());
unsafe { msg_send![&*item.objc, self] } unsafe { msg_send![&*item.objc, self] }
@ -65,7 +66,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 /// 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. /// 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 { load_or_register_class("NSObject", instance.subclass_name(), |decl| unsafe {
// For callbacks // For callbacks
decl.add_ivar::<usize>(TOOLBAR_PTR); decl.add_ivar::<usize>(TOOLBAR_PTR);
@ -73,19 +74,19 @@ pub(crate) fn register_toolbar_class<T: ToolbarDelegate>(instance: &T) -> *const
// Add callback methods // Add callback methods
decl.add_method( decl.add_method(
sel!(toolbarAllowedItemIdentifiers:), sel!(toolbarAllowedItemIdentifiers:),
allowed_item_identifiers::<T> as extern "C" fn(&Object, _, _) -> id allowed_item_identifiers::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(toolbarDefaultItemIdentifiers:), sel!(toolbarDefaultItemIdentifiers:),
default_item_identifiers::<T> as extern "C" fn(&Object, _, _) -> id default_item_identifiers::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(toolbarSelectableItemIdentifiers:), sel!(toolbarSelectableItemIdentifiers:),
selectable_item_identifiers::<T> as extern "C" fn(&Object, _, _) -> id selectable_item_identifiers::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:), sel!(toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:),
item_for_identifier::<T> as extern "C" fn(&Object, _, _, _, _) -> id item_for_identifier::<T> as extern "C" fn(_, _, _, _, _) -> _
); );
}) })
} }

View file

@ -1,5 +1,7 @@
//! Various types used for Toolbar configuration. //! Various types used for Toolbar configuration.
use objc::rc::Id;
use crate::foundation::{id, NSString, NSUInteger}; use crate::foundation::{id, NSString, NSUInteger};
/// Represents the display mode(s) a Toolbar can render in. /// Represents the display mode(s) a Toolbar can render in.
@ -95,7 +97,8 @@ impl ItemIdentifier {
pub(crate) fn to_nsstring(&self) -> id { pub(crate) fn to_nsstring(&self) -> id {
unsafe { unsafe {
match self { match self {
Self::Custom(s) => NSString::new(s).into(), // FIXME: We shouldn't use autorelease here
Self::Custom(s) => Id::autorelease_return(NSString::new(s).objc),
Self::CloudSharing => NSToolbarCloudSharingItemIdentifier, Self::CloudSharing => NSToolbarCloudSharingItemIdentifier,
Self::FlexibleSpace => NSToolbarFlexibleSpaceItemIdentifier, Self::FlexibleSpace => NSToolbarFlexibleSpaceItemIdentifier,
Self::Print => NSToolbarPrintItemIdentifier, Self::Print => NSToolbarPrintItemIdentifier,
@ -106,7 +109,10 @@ impl ItemIdentifier {
// This ensures that the framework compiles and runs on 10.15.7 and lower; it will // This ensures that the framework compiles and runs on 10.15.7 and lower; it will
// not actually work on anything except 11.0+. Use a runtime check to be safe. // not actually work on anything except 11.0+. Use a runtime check to be safe.
Self::SidebarTracker => NSString::no_copy("NSToolbarSidebarTrackingSeparatorItemIdentifier").into() // FIXME: We shouldn't use autorelease here
Self::SidebarTracker => {
Id::autorelease_return(NSString::no_copy("NSToolbarSidebarTrackingSeparatorItemIdentifier").objc)
},
} }
} }
} }

View file

@ -6,9 +6,9 @@
use core_graphics::geometry::CGSize; use core_graphics::geometry::CGSize;
use std::fmt; use std::fmt;
use objc::rc::{Id, Owned, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::{Id, ShareId};
use crate::appkit::segmentedcontrol::SegmentedControl; use crate::appkit::segmentedcontrol::SegmentedControl;
use crate::button::{BezelStyle, Button}; use crate::button::{BezelStyle, Button};
@ -20,7 +20,7 @@ use crate::invoker::TargetActionHandler;
#[derive(Debug)] #[derive(Debug)]
pub struct ToolbarItem { pub struct ToolbarItem {
pub identifier: String, pub identifier: String,
pub objc: Id<Object>, pub objc: Id<Object, Owned>,
pub button: Option<Button>, pub button: Option<Button>,
pub segmented_control: Option<SegmentedControl>, pub segmented_control: Option<SegmentedControl>,
pub image: Option<Image>, pub image: Option<Image>,
@ -34,10 +34,9 @@ impl ToolbarItem {
let identifier = identifier.into(); let identifier = identifier.into();
let objc = unsafe { let objc = unsafe {
let identifr = NSString::new(&identifier); let identifer = NSString::new(&identifier);
let alloc: id = msg_send![class!(NSToolbarItem), alloc]; let alloc = msg_send_id![class!(NSToolbarItem), alloc];
let item: id = msg_send![alloc, initWithItemIdentifier: identifr]; msg_send_id![alloc, initWithItemIdentifier: &*identifer]
Id::from_ptr(item)
}; };
ToolbarItem { ToolbarItem {
@ -50,17 +49,6 @@ impl ToolbarItem {
} }
} }
pub(crate) fn wrap(item: id) -> Self {
ToolbarItem {
identifier: "".to_string(),
objc: unsafe { Id::from_retained_ptr(item) },
button: None,
segmented_control: None,
image: None,
handler: None
}
}
/// Sets the title for this item. /// Sets the title for this item.
pub fn set_title(&mut self, title: &str) { pub fn set_title(&mut self, title: &str) {
unsafe { unsafe {

View file

@ -5,9 +5,9 @@
use std::fmt; use std::fmt;
use objc::rc::{Id, Owned, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::foundation::{id, nil, NSString, NSUInteger, NO, YES}; use crate::foundation::{id, nil, NSString, NSUInteger, NO, YES};
@ -32,10 +32,10 @@ pub struct Toolbar<T = ()> {
pub identifier: String, pub identifier: String,
/// The Objective-C runtime toolbar. /// The Objective-C runtime toolbar.
pub objc: ShareId<Object>, pub objc: Id<Object, Shared>,
/// A pointer to the underlying delegate. /// A pointer to the underlying delegate.
pub objc_delegate: ShareId<Object>, pub objc_delegate: Id<Object, Shared>,
/// The user supplied delegate. /// The user supplied delegate.
pub delegate: Option<Box<T>> pub delegate: Option<Box<T>>
@ -53,16 +53,18 @@ where
let mut delegate = Box::new(delegate); let mut delegate = Box::new(delegate);
let (objc, objc_delegate) = unsafe { let (objc, objc_delegate) = unsafe {
let alloc: id = msg_send![class!(NSToolbar), alloc]; let alloc = msg_send_id![class!(NSToolbar), alloc];
let identifier = NSString::new(&identifier); let identifier = NSString::new(&identifier);
let toolbar: id = msg_send![alloc, initWithIdentifier: identifier]; let mut toolbar: Id<Object, Owned> = msg_send_id![alloc, initWithIdentifier: &*identifier];
let objc_delegate: id = msg_send![cls, new]; //WithIdentifier:identifier]; let mut objc_delegate: Id<Object, Owned> = msg_send_id![cls, new]; //WithIdentifier:identifier];
let ptr: *const T = &*delegate; let ptr: *const T = &*delegate;
(&mut *objc_delegate).set_ivar(TOOLBAR_PTR, ptr as usize); objc_delegate.set_ivar(TOOLBAR_PTR, ptr as usize);
let _: () = msg_send![toolbar, setDelegate: objc_delegate];
(ShareId::from_ptr(toolbar), ShareId::from_ptr(objc_delegate)) let objc_delegate: Id<Object, Shared> = Id::into_shared(objc_delegate);
let _: () = msg_send![&mut toolbar, setDelegate: &*objc_delegate];
(Id::into_shared(toolbar), objc_delegate)
}; };
let _ret = &mut delegate.did_load(Toolbar { let _ret = &mut delegate.did_load(Toolbar {

View file

@ -6,22 +6,19 @@ use std::sync::Once;
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use objc::declare::ClassDecl; use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel}; use objc::runtime::{Bool, Class, Object, Sel};
use objc::{class, sel, sel_impl}; use objc::{class, sel};
use crate::appkit::window::{WindowDelegate, WINDOW_DELEGATE_PTR}; use crate::appkit::window::{WindowDelegate, WINDOW_DELEGATE_PTR};
use crate::foundation::{id, load_or_register_class, NSUInteger, BOOL, NO, YES}; use crate::foundation::{id, load_or_register_class, NSUInteger};
use crate::utils::{load, CGSize}; use crate::utils::{load, CGSize};
/// Called when an `NSWindowDelegate` receives a `windowWillClose:` event. /// Called when an `NSWindowDelegate` receives a `windowWillClose:` event.
/// Good place to clean up memory and what not. /// Good place to clean up memory and what not.
extern "C" fn should_close<T: WindowDelegate>(this: &Object, _: Sel, _: id) -> BOOL { extern "C" fn should_close<T: WindowDelegate>(this: &Object, _: Sel, _: id) -> Bool {
let window = load::<T>(this, WINDOW_DELEGATE_PTR); let window = load::<T>(this, WINDOW_DELEGATE_PTR);
match window.should_close() { Bool::new(window.should_close())
true => YES,
false => NO
}
} }
/// Called when an `NSWindowDelegate` receives a `windowWillClose:` event. /// Called when an `NSWindowDelegate` receives a `windowWillClose:` event.
@ -227,117 +224,99 @@ extern "C" fn cancel<T: WindowDelegate>(this: &Object, _: Sel, _: id) {
/// Injects an `NSWindowDelegate` subclass, with some callback and pointer ivars for what we /// Injects an `NSWindowDelegate` subclass, with some callback and pointer ivars for what we
/// need to do. /// need to do.
pub(crate) fn register_window_class_with_delegate<T: WindowDelegate>(instance: &T) -> *const Class { pub(crate) fn register_window_class_with_delegate<T: WindowDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSWindow", instance.subclass_name(), |decl| unsafe { load_or_register_class("NSWindow", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(WINDOW_DELEGATE_PTR); decl.add_ivar::<usize>(WINDOW_DELEGATE_PTR);
// NSWindowDelegate methods // NSWindowDelegate methods
decl.add_method( decl.add_method(sel!(windowShouldClose:), should_close::<T> as extern "C" fn(_, _, _) -> _);
sel!(windowShouldClose:), decl.add_method(sel!(windowWillClose:), will_close::<T> as extern "C" fn(_, _, _));
should_close::<T> as extern "C" fn(&Object, _, _) -> BOOL
);
decl.add_method(sel!(windowWillClose:), will_close::<T> as extern "C" fn(&Object, _, _));
// Sizing // Sizing
decl.add_method( decl.add_method(
sel!(windowWillResize:toSize:), sel!(windowWillResize:toSize:),
will_resize::<T> as extern "C" fn(&Object, _, _, CGSize) -> CGSize will_resize::<T> as extern "C" fn(_, _, _, _) -> _
); );
decl.add_method(sel!(windowDidResize:), did_resize::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(windowDidResize:), did_resize::<T> as extern "C" fn(_, _, _));
decl.add_method( decl.add_method(
sel!(windowWillStartLiveResize:), sel!(windowWillStartLiveResize:),
will_start_live_resize::<T> as extern "C" fn(&Object, _, _) will_start_live_resize::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(windowDidEndLiveResize:), sel!(windowDidEndLiveResize:),
did_end_live_resize::<T> as extern "C" fn(&Object, _, _) did_end_live_resize::<T> as extern "C" fn(_, _, _)
); );
// Minimizing // Minimizing
decl.add_method( decl.add_method(sel!(windowWillMiniaturize:), will_miniaturize::<T> as extern "C" fn(_, _, _));
sel!(windowWillMiniaturize:), decl.add_method(sel!(windowDidMiniaturize:), did_miniaturize::<T> as extern "C" fn(_, _, _));
will_miniaturize::<T> as extern "C" fn(&Object, _, _)
);
decl.add_method(
sel!(windowDidMiniaturize:),
did_miniaturize::<T> as extern "C" fn(&Object, _, _)
);
decl.add_method( decl.add_method(
sel!(windowDidDeminiaturize:), sel!(windowDidDeminiaturize:),
did_deminiaturize::<T> as extern "C" fn(&Object, _, _) did_deminiaturize::<T> as extern "C" fn(_, _, _)
); );
// Full Screen // Full Screen
decl.add_method( decl.add_method(
sel!(window:willUseFullScreenContentSize:), sel!(window:willUseFullScreenContentSize:),
content_size_for_full_screen::<T> as extern "C" fn(&Object, _, _, CGSize) -> CGSize content_size_for_full_screen::<T> as extern "C" fn(_, _, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(window:willUseFullScreenPresentationOptions:), sel!(window:willUseFullScreenPresentationOptions:),
options_for_full_screen::<T> as extern "C" fn(&Object, _, _, NSUInteger) -> NSUInteger options_for_full_screen::<T> as extern "C" fn(_, _, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(windowWillEnterFullScreen:), sel!(windowWillEnterFullScreen:),
will_enter_full_screen::<T> as extern "C" fn(&Object, _, _) will_enter_full_screen::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(windowDidEnterFullScreen:), sel!(windowDidEnterFullScreen:),
did_enter_full_screen::<T> as extern "C" fn(&Object, _, _) did_enter_full_screen::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(windowWillExitFullScreen:), sel!(windowWillExitFullScreen:),
will_exit_full_screen::<T> as extern "C" fn(&Object, _, _) will_exit_full_screen::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(windowDidExitFullScreen:), sel!(windowDidExitFullScreen:),
did_exit_full_screen::<T> as extern "C" fn(&Object, _, _) did_exit_full_screen::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(windowDidFailToEnterFullScreen:), sel!(windowDidFailToEnterFullScreen:),
did_fail_to_enter_full_screen::<T> as extern "C" fn(&Object, _, _) did_fail_to_enter_full_screen::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(windowDidFailToExitFullScreen:), sel!(windowDidFailToExitFullScreen:),
did_fail_to_exit_full_screen::<T> as extern "C" fn(&Object, _, _) did_fail_to_exit_full_screen::<T> as extern "C" fn(_, _, _)
); );
// Key status // Key status
decl.add_method(sel!(windowDidBecomeKey:), did_become_key::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(windowDidBecomeKey:), did_become_key::<T> as extern "C" fn(_, _, _));
decl.add_method(sel!(windowDidResignKey:), did_resign_key::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(windowDidResignKey:), did_resign_key::<T> as extern "C" fn(_, _, _));
// Main status // Main status
decl.add_method( decl.add_method(sel!(windowDidBecomeMain:), did_become_main::<T> as extern "C" fn(_, _, _));
sel!(windowDidBecomeMain:), decl.add_method(sel!(windowDidResignMain:), did_resign_main::<T> as extern "C" fn(_, _, _));
did_become_main::<T> as extern "C" fn(&Object, _, _)
);
decl.add_method(
sel!(windowDidResignMain:),
did_resign_main::<T> as extern "C" fn(&Object, _, _)
);
// Moving Windows // Moving Windows
decl.add_method(sel!(windowWillMove:), will_move::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(windowWillMove:), will_move::<T> as extern "C" fn(_, _, _));
decl.add_method(sel!(windowDidMove:), did_move::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(windowDidMove:), did_move::<T> as extern "C" fn(_, _, _));
decl.add_method( decl.add_method(sel!(windowDidChangeScreen:), did_change_screen::<T> as extern "C" fn(_, _, _));
sel!(windowDidChangeScreen:),
did_change_screen::<T> as extern "C" fn(&Object, _, _)
);
decl.add_method( decl.add_method(
sel!(windowDidChangeScreenProfile:), sel!(windowDidChangeScreenProfile:),
did_change_screen_profile::<T> as extern "C" fn(&Object, _, _) did_change_screen_profile::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(windowDidChangeBackingProperties:), sel!(windowDidChangeBackingProperties:),
did_change_backing_properties::<T> as extern "C" fn(&Object, _, _) did_change_backing_properties::<T> as extern "C" fn(_, _, _)
); );
// Random // Random
decl.add_method( decl.add_method(
sel!(windowDidChangeOcclusionState:), sel!(windowDidChangeOcclusionState:),
did_change_occlusion_state::<T> as extern "C" fn(&Object, _, _) did_change_occlusion_state::<T> as extern "C" fn(_, _, _)
); );
decl.add_method(sel!(windowDidExpose:), did_expose::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(windowDidExpose:), did_expose::<T> as extern "C" fn(_, _, _));
decl.add_method(sel!(windowDidUpdate:), did_update::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(windowDidUpdate:), did_update::<T> as extern "C" fn(_, _, _));
decl.add_method(sel!(cancelOperation:), cancel::<T> as extern "C" fn(&Object, _, _)); decl.add_method(sel!(cancelOperation:), cancel::<T> as extern "C" fn(_, _, _));
}) })
} }

View file

@ -8,7 +8,7 @@ use crate::foundation::load_or_register_class;
/// Injects an `NSWindowController` subclass, with some callback and pointer ivars for what we /// Injects an `NSWindowController` subclass, with some callback and pointer ivars for what we
/// need to do. /// need to do.
pub(crate) fn register_window_controller_class<T: WindowDelegate>() -> *const Class { pub(crate) fn register_window_controller_class<T: WindowDelegate>() -> &'static Class {
load_or_register_class("NSWindowController", "RSTWindowController", |decl| unsafe { load_or_register_class("NSWindowController", "RSTWindowController", |decl| unsafe {
decl.add_ivar::<usize>(WINDOW_DELEGATE_PTR); decl.add_ivar::<usize>(WINDOW_DELEGATE_PTR);
}) })

View file

@ -30,9 +30,9 @@
use std::fmt; use std::fmt;
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::appkit::window::{Window, WindowConfig, WindowDelegate, WINDOW_DELEGATE_PTR}; use crate::appkit::window::{Window, WindowConfig, WindowDelegate, WINDOW_DELEGATE_PTR};
use crate::foundation::{id, nil}; use crate::foundation::{id, nil};
@ -45,7 +45,7 @@ use class::register_window_controller_class;
/// provides some extra lifecycle methods. /// provides some extra lifecycle methods.
pub struct WindowController<T> { pub struct WindowController<T> {
/// A handler to the underlying `NSWindowController`. /// A handler to the underlying `NSWindowController`.
pub objc: Id<Object>, pub objc: Id<Object, Owned>,
/// The underlying `Window` that this controller wraps. /// The underlying `Window` that this controller wraps.
pub window: Window<T> pub window: Window<T>
@ -62,15 +62,15 @@ where
let objc = unsafe { let objc = unsafe {
let window_controller_class = register_window_controller_class::<T>(); let window_controller_class = register_window_controller_class::<T>();
let controller_alloc: id = msg_send![window_controller_class, alloc]; let controller_alloc = msg_send_id![window_controller_class, alloc];
let controller: id = msg_send![controller_alloc, initWithWindow:&*window.objc]; let mut controller: Id<Object, Owned> = msg_send_id![controller_alloc, initWithWindow: &*window.objc];
if let Some(delegate) = &window.delegate { if let Some(delegate) = &window.delegate {
let ptr: *const T = &**delegate; let ptr: *const T = &**delegate;
(&mut *controller).set_ivar(WINDOW_DELEGATE_PTR, ptr as usize); controller.set_ivar(WINDOW_DELEGATE_PTR, ptr as usize);
} }
Id::from_ptr(controller) controller
}; };
WindowController { objc, window } WindowController { objc, window }

View file

@ -13,9 +13,9 @@ use block::ConcreteBlock;
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use core_graphics::geometry::{CGRect, CGSize}; use core_graphics::geometry::{CGRect, CGSize};
use objc::rc::{Id, Owned, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::appkit::toolbar::{Toolbar, ToolbarDelegate}; use crate::appkit::toolbar::{Toolbar, ToolbarDelegate};
use crate::color::Color; use crate::color::Color;
@ -47,7 +47,7 @@ pub(crate) static WINDOW_DELEGATE_PTR: &str = "rstWindowDelegate";
#[derive(Debug)] #[derive(Debug)]
pub struct Window<T = ()> { pub struct Window<T = ()> {
/// Represents an `NS/UIWindow` in the Objective-C runtime. /// Represents an `NS/UIWindow` in the Objective-C runtime.
pub objc: ShareId<Object>, pub objc: Id<Object, Shared>,
/// A delegate for this window. /// A delegate for this window.
pub delegate: Option<Box<T>> pub delegate: Option<Box<T>>
@ -72,40 +72,38 @@ impl Window {
// apps that would use this toolkit wouldn't be tab-oriented... // apps that would use this toolkit wouldn't be tab-oriented...
let _: () = msg_send![class!(NSWindow), setAllowsAutomaticWindowTabbing: NO]; let _: () = msg_send![class!(NSWindow), setAllowsAutomaticWindowTabbing: NO];
let alloc: id = msg_send![class!(NSWindow), alloc];
// Other types of backing (Retained/NonRetained) are archaic, dating back to the // Other types of backing (Retained/NonRetained) are archaic, dating back to the
// NeXTSTEP era, and are outright deprecated... so we don't allow setting them. // NeXTSTEP era, and are outright deprecated... so we don't allow setting them.
let buffered: NSUInteger = 2; let buffered: NSUInteger = 2;
let dimensions: CGRect = config.initial_dimensions.into(); let dimensions: CGRect = config.initial_dimensions.into();
let window: id = msg_send![alloc, initWithContentRect:dimensions let window: Id<_, _> = msg_send_id![
styleMask:config.style msg_send_id![class!(NSWindow), alloc],
backing:buffered initWithContentRect: dimensions,
defer:match config.defer { styleMask: config.style,
backing: buffered,
defer: match config.defer {
true => YES, true => YES,
false => NO false => NO
} },
]; ];
let _: () = msg_send![window, autorelease];
// This is very important! NSWindow is an old class and has some behavior that we need // This is very important! NSWindow is an old class and has some behavior that we need
// to disable, like... this. If we don't set this, we'll segfault entirely because the // to disable, like... this. If we don't set this, we'll segfault entirely because the
// Objective-C runtime gets out of sync by releasing the window out from underneath of // Objective-C runtime gets out of sync by releasing the window out from underneath of
// us. // us.
let _: () = msg_send![window, setReleasedWhenClosed: NO]; let _: () = msg_send![&*window, setReleasedWhenClosed: NO];
let _: () = msg_send![window, setRestorable: NO]; let _: () = msg_send![&*window, setRestorable: NO];
// This doesn't exist prior to Big Sur, but is important to support for Big Sur. // This doesn't exist prior to Big Sur, but is important to support for Big Sur.
// //
// Why this isn't a setting on the Toolbar itself I'll never know. // Why this isn't a setting on the Toolbar itself I'll never know.
if os::is_minimum_version(11) { if os::is_minimum_version(11) {
let toolbar_style: NSUInteger = config.toolbar_style.into(); let toolbar_style: NSUInteger = config.toolbar_style.into();
let _: () = msg_send![window, setToolbarStyle: toolbar_style]; let _: () = msg_send![&*window, setToolbarStyle: toolbar_style];
} }
ShareId::from_ptr(window) window
}; };
Window { Window {
@ -116,7 +114,7 @@ impl Window {
pub(crate) unsafe fn existing(window: *mut Object) -> Window { pub(crate) unsafe fn existing(window: *mut Object) -> Window {
Window { Window {
objc: ShareId::from_ptr(window), objc: Id::retain(window).unwrap(),
delegate: None delegate: None
} }
} }
@ -134,51 +132,49 @@ where
let class = register_window_class_with_delegate::<T>(&delegate); let class = register_window_class_with_delegate::<T>(&delegate);
let mut delegate = Box::new(delegate); let mut delegate = Box::new(delegate);
let objc = unsafe { let objc: Id<Object, Shared> = unsafe {
// This behavior might make sense to keep as default (YES), but I think the majority of // This behavior might make sense to keep as default (YES), but I think the majority of
// apps that would use this toolkit wouldn't be tab-oriented... // apps that would use this toolkit wouldn't be tab-oriented...
let _: () = msg_send![class!(NSWindow), setAllowsAutomaticWindowTabbing: NO]; let _: () = msg_send![class!(NSWindow), setAllowsAutomaticWindowTabbing: NO];
let alloc: id = msg_send![class, alloc];
// Other types of backing (Retained/NonRetained) are archaic, dating back to the // Other types of backing (Retained/NonRetained) are archaic, dating back to the
// NeXTSTEP era, and are outright deprecated... so we don't allow setting them. // NeXTSTEP era, and are outright deprecated... so we don't allow setting them.
let buffered: NSUInteger = 2; let buffered: NSUInteger = 2;
let dimensions: CGRect = config.initial_dimensions.into(); let dimensions: CGRect = config.initial_dimensions.into();
let window: id = msg_send![alloc, initWithContentRect:dimensions let mut window: Id<Object, Owned> = msg_send_id![
styleMask:config.style msg_send_id![class, alloc],
backing:buffered initWithContentRect: dimensions,
defer:match config.defer { styleMask: config.style,
backing: buffered,
defer: match config.defer {
true => YES, true => YES,
false => NO false => NO
} },
]; ];
let delegate_ptr: *const T = &*delegate; let delegate_ptr: *const T = &*delegate;
(&mut *window).set_ivar(WINDOW_DELEGATE_PTR, delegate_ptr as usize); window.set_ivar(WINDOW_DELEGATE_PTR, delegate_ptr as usize);
let _: () = msg_send![window, autorelease];
// This is very important! NSWindow is an old class and has some behavior that we need // This is very important! NSWindow is an old class and has some behavior that we need
// to disable, like... this. If we don't set this, we'll segfault entirely because the // to disable, like... this. If we don't set this, we'll segfault entirely because the
// Objective-C runtime gets out of sync by releasing the window out from underneath of // Objective-C runtime gets out of sync by releasing the window out from underneath of
// us. // us.
let _: () = msg_send![window, setReleasedWhenClosed: NO]; let _: () = msg_send![&*window, setReleasedWhenClosed: NO];
// We set the window to be its own delegate - this is cleaned up inside `Drop`. // We set the window to be its own delegate - this is cleaned up inside `Drop`.
let _: () = msg_send![window, setDelegate: window]; let _: () = msg_send![&*window, setDelegate: &*window];
let _: () = msg_send![window, setRestorable: NO]; let _: () = msg_send![&*window, setRestorable: NO];
// This doesn't exist prior to Big Sur, but is important to support for Big Sur. // This doesn't exist prior to Big Sur, but is important to support for Big Sur.
// //
// Why this isn't a setting on the Toolbar itself I'll never know. // Why this isn't a setting on the Toolbar itself I'll never know.
if os::is_minimum_version(11) { if os::is_minimum_version(11) {
let toolbar_style: NSUInteger = config.toolbar_style.into(); let toolbar_style: NSUInteger = config.toolbar_style.into();
let _: () = msg_send![window, setToolbarStyle: toolbar_style]; let _: () = msg_send![&*window, setToolbarStyle: toolbar_style];
} }
ShareId::from_ptr(window) window.into()
}; };
{ {
@ -201,7 +197,7 @@ impl<T> Window<T> {
pub fn set_title(&self, title: &str) { pub fn set_title(&self, title: &str) {
unsafe { unsafe {
let title = NSString::new(title); let title = NSString::new(title);
let _: () = msg_send![&*self.objc, setTitle: title]; let _: () = msg_send![&*self.objc, setTitle: &*title];
} }
} }
@ -216,7 +212,7 @@ impl<T> Window<T> {
unsafe { unsafe {
let subtitle = NSString::new(subtitle); let subtitle = NSString::new(subtitle);
let _: () = msg_send![&*self.objc, setSubtitle: subtitle]; let _: () = msg_send![&*self.objc, setSubtitle: &*subtitle];
} }
} }
@ -252,7 +248,7 @@ impl<T> Window<T> {
pub fn set_autosave_name(&self, name: &str) { pub fn set_autosave_name(&self, name: &str) {
unsafe { unsafe {
let autosave = NSString::new(name); let autosave = NSString::new(name);
let _: () = msg_send![&*self.objc, setFrameAutosaveName: autosave]; let _: () = msg_send![&*self.objc, setFrameAutosaveName: &*autosave];
} }
} }
@ -296,11 +292,8 @@ impl<T> Window<T> {
} }
/// Used for setting a toolbar on this window. /// Used for setting a toolbar on this window.
pub fn toolbar(&self) -> ShareId<Object> { pub fn toolbar(&self) -> Id<Object, Shared> {
unsafe { unsafe { msg_send_id![&self.objc, toolbar] }
let o: *mut Object = msg_send![&*self.objc, toolbar];
ShareId::from_ptr(o)
}
} }
/// Toggles whether the toolbar is shown for this window. Has no effect if no toolbar exists on /// Toggles whether the toolbar is shown for this window. Has no effect if no toolbar exists on
@ -514,7 +507,7 @@ impl<T> Window<T> {
let block = block.copy(); let block = block.copy();
unsafe { unsafe {
let _: () = msg_send![&*self.objc, beginSheet:&*window.objc completionHandler:block]; let _: () = msg_send![&*self.objc, beginSheet: &*window.objc, completionHandler: &*block];
} }
} }

View file

@ -11,14 +11,9 @@
use std::ffi::CString; use std::ffi::CString;
use std::mem; use std::mem;
use objc::{class, msg_send, sel, sel_impl, Encode, Encoding, EncodeArguments, Message}; use objc::ffi;
use objc::runtime::{Class, Sel, Method, Object, Imp}; use objc::runtime::{Class, Imp, Object, Sel};
use objc::runtime::{ use objc::{class, msg_send, sel, Encode, EncodeArguments, Encoding, Message};
objc_getClass,
class_addMethod,
class_getInstanceMethod,
method_exchangeImplementations
};
use crate::foundation::{id, nil, BOOL, YES, NSString}; use crate::foundation::{id, nil, BOOL, YES, NSString};
@ -73,24 +68,27 @@ extern "C" fn get_bundle_id(this: &Object, s: Sel, v: id) -> id {
} }
} }
unsafe fn swizzle_bundle_id<F>(bundle_id: &str, func: F) where F: MethodImplementation<Callee=Object> { unsafe fn swizzle_bundle_id<F>(bundle_id: &str, func: F)
where
F: MethodImplementation<Callee = Object>,
{
let name = CString::new("NSBundle").unwrap(); let name = CString::new("NSBundle").unwrap();
let cls = objc_getClass(name.as_ptr()); let cls = ffi::objc_getClass(name.as_ptr());
// let mut cls = class!(NSBundle) as *mut Class; // let mut cls = class!(NSBundle) as *mut Class;
// Class::get("NSBundle").unwrap(); // Class::get("NSBundle").unwrap();
// let types = format!("{}{}{}", Encoding::String, <*mut Object>::ENCODING, Sel::ENCODING); // let types = format!("{}{}{}", Encoding::String, <*mut Object>::ENCODING, Sel::ENCODING);
let added = class_addMethod( let added = ffi::class_addMethod(
cls as *mut Class, cls as *mut ffi::objc_class,
sel!(__bundleIdentifier), sel!(__bundleIdentifier).as_ptr(),
func.imp(), func.imp(),
CString::new("*@:").unwrap().as_ptr() CString::new("*@:").unwrap().as_ptr(),
); );
let method1 = class_getInstanceMethod(cls, sel!(bundleIdentifier)) as *mut Method; let method1 = ffi::class_getInstanceMethod(cls, sel!(bundleIdentifier).as_ptr()) as *mut ffi::objc_method;
let method2 = class_getInstanceMethod(cls, sel!(__bundleIdentifier)) as *mut Method; let method2 = ffi::class_getInstanceMethod(cls, sel!(__bundleIdentifier).as_ptr()) as *mut ffi::objc_method;
method_exchangeImplementations(method1, method2); ffi::method_exchangeImplementations(method1, method2);
} }
pub fn set_bundle_id(bundle_id: &str) { pub fn set_bundle_id(bundle_id: &str) {

View file

@ -21,9 +21,9 @@
//! my_view.add_subview(&button); //! my_view.add_subview(&button);
//! ``` //! ```
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, msg_send_id, sel};
use objc_id::ShareId;
pub use enums::*; pub use enums::*;
@ -214,7 +214,7 @@ impl Button {
/// best just to message pass or something. /// best just to message pass or something.
pub fn set_action<F: Fn(*const Object) + Send + Sync + 'static>(&mut self, action: F) { pub fn set_action<F: Fn(*const Object) + Send + Sync + 'static>(&mut self, action: F) {
// @TODO: This probably isn't ideal but gets the job done for now; needs revisiting. // @TODO: This probably isn't ideal but gets the job done for now; needs revisiting.
let this = self.objc.get(|obj| unsafe { ShareId::from_ptr(msg_send![obj, self]) }); let this: Id<Object, Shared> = self.objc.get(|obj| unsafe { msg_send_id![obj, self] });
let handler = TargetActionHandler::new(&*this, action); let handler = TargetActionHandler::new(&*this, action);
self.handler = Some(handler); self.handler = Some(handler);
} }
@ -352,7 +352,7 @@ impl Drop for Button {
/// Registers an `NSButton` subclass, and configures it to hold some ivars /// Registers an `NSButton` subclass, and configures it to hold some ivars
/// for various things we need to store. /// for various things we need to store.
fn register_class() -> *const Class { fn register_class() -> &'static Class {
#[cfg(feature = "appkit")] #[cfg(feature = "appkit")]
let super_class = "NSButton"; let super_class = "NSButton";
#[cfg(all(feature = "uikit", not(feature = "appkit")))] #[cfg(all(feature = "uikit", not(feature = "appkit")))]

View file

@ -1,7 +1,7 @@
//! This module includes wrappers for `CKShare` and `CKShareMetaData`. //! This module includes wrappers for `CKShare` and `CKShareMetaData`.
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc_id::ShareId;
use crate::foundation::id; use crate::foundation::id;
@ -9,14 +9,14 @@ use crate::foundation::id;
/// to, say, handle accepting an invite for a share. /// to, say, handle accepting an invite for a share.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct CKShareMetaData { pub struct CKShareMetaData {
pub inner: ShareId<Object> pub inner: Id<Object, Shared>
} }
impl CKShareMetaData { impl CKShareMetaData {
/// Internal method for wrapping a system-provided `CKShareMetaData` object. /// Internal method for wrapping a system-provided `CKShareMetaData` object.
pub(crate) fn with_inner(object: id) -> Self { pub(crate) fn with_inner(object: id) -> Self {
CKShareMetaData { CKShareMetaData {
inner: unsafe { ShareId::from_ptr(object) } inner: unsafe { Id::retain(object).unwrap() }
} }
} }
} }

View file

@ -12,7 +12,7 @@
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use objc::runtime::{Class, Object, Sel}; use objc::runtime::{Class, Object, Sel};
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use crate::foundation::{id, load_or_register_class, nil, NSArray, NSInteger}; use crate::foundation::{id, load_or_register_class, nil, NSArray, NSInteger};
use crate::utils::os; use crate::utils::os;
@ -253,95 +253,68 @@ extern "C" fn color_with_system_effect(this: &Object, _: Sel, effect: NSInteger)
unsafe { msg_send![color, colorWithSystemEffect: effect] } unsafe { msg_send![color, colorWithSystemEffect: effect] }
} }
pub(crate) fn register_class() -> *const Class { pub(crate) fn register_class() -> &'static Class {
load_or_register_class("NSColor", "CacaoDynamicColor", |decl| unsafe { load_or_register_class("NSColor", "CacaoDynamicColor", |decl| unsafe {
// These methods all need to be forwarded, so let's hook them up. // These methods all need to be forwarded, so let's hook them up.
decl.add_method(sel!(colorSpace), color_space as extern "C" fn(&Object, _) -> id); decl.add_method(sel!(colorSpace), color_space as extern "C" fn(_, _) -> _);
decl.add_method( decl.add_method(
sel!(colorUsingColorSpace:), sel!(colorUsingColorSpace:),
color_using_color_space as extern "C" fn(&Object, _, id) -> id color_using_color_space as extern "C" fn(_, _, _) -> _
); );
decl.add_method(sel!(colorSpaceName), color_space_name as extern "C" fn(&Object, _) -> id); decl.add_method(sel!(colorSpaceName), color_space_name as extern "C" fn(_, _) -> _);
decl.add_method( decl.add_method(
sel!(colorUsingColorSpaceName:), sel!(colorUsingColorSpaceName:),
color_using_color_space_name as extern "C" fn(&Object, _, id) -> id color_using_color_space_name as extern "C" fn(_, _, _) -> _
);
decl.add_method(
sel!(numberOfComponents),
number_of_components as extern "C" fn(&Object, _) -> NSInteger
); );
decl.add_method(sel!(numberOfComponents), number_of_components as extern "C" fn(_, _) -> _);
decl.add_method(sel!(getComponents:), get_components as extern "C" fn(&Object, _, CGFloat)); decl.add_method(sel!(getComponents:), get_components as extern "C" fn(_, _, _));
decl.add_method( decl.add_method(sel!(getRed:green:blue:alpha:), get_rgba as extern "C" fn(_, _, _, _, _, _));
sel!(getRed:green:blue:alpha:), decl.add_method(sel!(redComponent), red_component as extern "C" fn(_, _) -> _);
get_rgba as extern "C" fn(&Object, _, CGFloat, CGFloat, CGFloat, CGFloat) decl.add_method(sel!(greenComponent), green_component as extern "C" fn(_, _) -> _);
); decl.add_method(sel!(blueComponent), blue_component as extern "C" fn(_, _) -> _);
decl.add_method(sel!(redComponent), red_component as extern "C" fn(&Object, _) -> CGFloat);
decl.add_method(sel!(greenComponent), green_component as extern "C" fn(&Object, _) -> CGFloat);
decl.add_method(sel!(blueComponent), blue_component as extern "C" fn(&Object, _) -> CGFloat);
decl.add_method(sel!(hueComponent), hue_component as extern "C" fn(&Object, _) -> CGFloat); decl.add_method(sel!(hueComponent), hue_component as extern "C" fn(_, _) -> _);
decl.add_method( decl.add_method(sel!(saturationComponent), saturation_component as extern "C" fn(_, _) -> _);
sel!(saturationComponent), decl.add_method(sel!(brightnessComponent), brightness_component as extern "C" fn(_, _) -> _);
saturation_component as extern "C" fn(&Object, _) -> CGFloat
);
decl.add_method(
sel!(brightnessComponent),
brightness_component as extern "C" fn(&Object, _) -> CGFloat
);
decl.add_method( decl.add_method(
sel!(getHue:saturation:brightness:alpha:), sel!(getHue:saturation:brightness:alpha:),
get_hsba as extern "C" fn(&Object, _, CGFloat, CGFloat, CGFloat, CGFloat) get_hsba as extern "C" fn(_, _, _, _, _, _)
); );
decl.add_method(sel!(whiteComponent), white_component as extern "C" fn(&Object, _) -> CGFloat); decl.add_method(sel!(whiteComponent), white_component as extern "C" fn(_, _) -> _);
decl.add_method( decl.add_method(sel!(getWhite:alpha:), get_white as extern "C" fn(_, _, _, _));
sel!(getWhite:alpha:),
get_white as extern "C" fn(&Object, _, CGFloat, CGFloat)
);
decl.add_method(sel!(cyanComponent), cyan_component as extern "C" fn(&Object, _) -> CGFloat); decl.add_method(sel!(cyanComponent), cyan_component as extern "C" fn(_, _) -> _);
decl.add_method( decl.add_method(sel!(magentaComponent), magenta_component as extern "C" fn(_, _) -> _);
sel!(magentaComponent), decl.add_method(sel!(yellowComponent), yellow_component as extern "C" fn(_, _) -> _);
magenta_component as extern "C" fn(&Object, _) -> CGFloat decl.add_method(sel!(blackComponent), black_component as extern "C" fn(_, _) -> _);
);
decl.add_method(
sel!(yellowComponent),
yellow_component as extern "C" fn(&Object, _) -> CGFloat
);
decl.add_method(sel!(blackComponent), black_component as extern "C" fn(&Object, _) -> CGFloat);
decl.add_method( decl.add_method(
sel!(getCyan:magenta:yellow:black:alpha:), sel!(getCyan:magenta:yellow:black:alpha:),
get_cmyk as extern "C" fn(&Object, _, CGFloat, CGFloat, CGFloat, CGFloat, CGFloat) get_cmyk as extern "C" fn(_, _, _, _, _, _, _)
); );
decl.add_method(sel!(alphaComponent), alpha_component as extern "C" fn(&Object, _) -> CGFloat); decl.add_method(sel!(alphaComponent), alpha_component as extern "C" fn(_, _) -> _);
decl.add_method(sel!(CGColor), cg_color as extern "C" fn(&Object, _) -> id); decl.add_method(sel!(CGColor), cg_color as extern "C" fn(_, _) -> _);
decl.add_method(sel!(setStroke), set_stroke as extern "C" fn(&Object, _)); decl.add_method(sel!(setStroke), set_stroke as extern "C" fn(_, _));
decl.add_method(sel!(setFill), set_fill as extern "C" fn(&Object, _)); decl.add_method(sel!(setFill), set_fill as extern "C" fn(_, _));
decl.add_method(sel!(set), call_set as extern "C" fn(&Object, _)); decl.add_method(sel!(set), call_set as extern "C" fn(_, _));
decl.add_method( decl.add_method(sel!(highlightWithLevel:), highlight_with_level as extern "C" fn(_, _, _) -> _);
sel!(highlightWithLevel:), decl.add_method(sel!(shadowWithLevel:), shadow_with_level as extern "C" fn(_, _, _) -> _);
highlight_with_level as extern "C" fn(&Object, _, CGFloat) -> id
);
decl.add_method(
sel!(shadowWithLevel:),
shadow_with_level as extern "C" fn(&Object, _, CGFloat) -> id
);
decl.add_method( decl.add_method(
sel!(colorWithAlphaComponent:), sel!(colorWithAlphaComponent:),
color_with_alpha_component as extern "C" fn(&Object, _, CGFloat) -> id color_with_alpha_component as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(blendedColorWithFraction:ofColor:), sel!(blendedColorWithFraction:ofColor:),
blended_color as extern "C" fn(&Object, _, CGFloat, id) -> id blended_color as extern "C" fn(_, _, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(colorWithSystemEffect:), sel!(colorWithSystemEffect:),
color_with_system_effect as extern "C" fn(&Object, _, NSInteger) -> id color_with_system_effect as extern "C" fn(_, _, _) -> _
); );
decl.add_ivar::<id>(AQUA_LIGHT_COLOR_NORMAL_CONTRAST); decl.add_ivar::<id>(AQUA_LIGHT_COLOR_NORMAL_CONTRAST);

View file

@ -15,12 +15,13 @@
/// @TODO: bundle iOS/tvOS support. /// @TODO: bundle iOS/tvOS support.
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use core_foundation::base::TCFType;
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use core_graphics::color::CGColor; use core_graphics::color::CGColor;
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::foundation::id; use crate::foundation::id;
use crate::utils::os; use crate::utils::os;
@ -85,7 +86,7 @@ pub enum Color {
/// ///
/// If you need to do custom work not covered by this enum, you can drop to /// If you need to do custom work not covered by this enum, you can drop to
/// the Objective-C level yourself and wrap your color in this. /// the Objective-C level yourself and wrap your color in this.
Custom(Arc<RwLock<Id<Object>>>), Custom(Arc<RwLock<Id<Object, Owned>>>),
/// The system-provided black. Harsh - you probably don't want to use this. /// The system-provided black. Harsh - you probably don't want to use this.
SystemBlack, SystemBlack,
@ -247,9 +248,9 @@ impl Color {
let b = blue as CGFloat / 255.0; let b = blue as CGFloat / 255.0;
let a = alpha as CGFloat / 255.0; let a = alpha as CGFloat / 255.0;
#[cfg(feature = "appkit")] #[cfg(feature = "appkit")]
let ptr = unsafe { Id::from_ptr(msg_send![class!(NSColor), colorWithCalibratedRed:r green:g blue:b alpha:a]) }; let ptr = unsafe { msg_send_id![class!(NSColor), colorWithCalibratedRed: r, green: g, blue: b, alpha: a] };
#[cfg(all(feature = "uikit", not(feature = "appkit")))] #[cfg(all(feature = "uikit", not(feature = "appkit")))]
let ptr = unsafe { Id::from_ptr(msg_send![class!(UIColor), colorWithRed:r green:g blue:b alpha:a]) }; let ptr = unsafe { msg_send_id![class!(UIColor), colorWithRed: r, green: g, blue: b, alpha: a] };
Color::Custom(Arc::new(RwLock::new(ptr))) Color::Custom(Arc::new(RwLock::new(ptr)))
} }
@ -271,12 +272,18 @@ impl Color {
Color::Custom(Arc::new(RwLock::new(unsafe { Color::Custom(Arc::new(RwLock::new(unsafe {
#[cfg(feature = "appkit")] #[cfg(feature = "appkit")]
{ {
Id::from_ptr(msg_send![class!(NSColor), colorWithCalibratedHue:h saturation:s brightness:b alpha:a]) msg_send_id![
class!(NSColor),
colorWithCalibratedHue: h,
saturation: s,
brightness: b,
alpha: a
]
} }
#[cfg(all(feature = "uikit", not(feature = "appkit")))] #[cfg(all(feature = "uikit", not(feature = "appkit")))]
{ {
Id::from_ptr(msg_send![class!(UIColor), colorWithHue:h saturation:s brightness:b alpha:a]) msg_send_id![class!(UIColor), colorWithHue: h, saturation: s, brightness: b, alpha: a]
} }
}))) })))
} }
@ -293,12 +300,12 @@ impl Color {
Color::Custom(Arc::new(RwLock::new(unsafe { Color::Custom(Arc::new(RwLock::new(unsafe {
#[cfg(feature = "appkit")] #[cfg(feature = "appkit")]
{ {
Id::from_ptr(msg_send![class!(NSColor), colorWithCalibratedWhite:level alpha:alpha]) msg_send_id![class!(NSColor), colorWithCalibratedWhite: level, alpha: alpha]
} }
#[cfg(all(feature = "uikit", not(feature = "appkit")))] #[cfg(all(feature = "uikit", not(feature = "appkit")))]
{ {
Id::from_ptr(msg_send![class!(UIColor), colorWithWhite:level alpha:alpha]) msg_send_id![class!(UIColor), colorWithWhite: level, alpha: alpha]
} }
}))) })))
} }
@ -345,49 +352,37 @@ impl Color {
// am happy to do this for now and let someone who needs true dynamic allocation look into // am happy to do this for now and let someone who needs true dynamic allocation look into
// it and PR it. // it and PR it.
Color::Custom(Arc::new(RwLock::new(unsafe { Color::Custom(Arc::new(RwLock::new(unsafe {
let color: id = msg_send![appkit_dynamic_color::register_class(), new]; let mut color: Id<Object, Owned> = msg_send_id![appkit_dynamic_color::register_class(), new];
(&mut *color).set_ivar(AQUA_LIGHT_COLOR_NORMAL_CONTRAST, { color.set_ivar(AQUA_LIGHT_COLOR_NORMAL_CONTRAST, {
let color: id = handler(Style { to_objc(&handler(Style {
theme: Theme::Light, theme: Theme::Light,
contrast: Contrast::Normal contrast: Contrast::Normal
}) }))
.into();
color
}); });
(&mut *color).set_ivar(AQUA_LIGHT_COLOR_HIGH_CONTRAST, { color.set_ivar(AQUA_LIGHT_COLOR_HIGH_CONTRAST, {
let color: id = handler(Style { to_objc(&handler(Style {
theme: Theme::Light, theme: Theme::Light,
contrast: Contrast::High contrast: Contrast::High
}) }))
.into();
color
}); });
(&mut *color).set_ivar(AQUA_DARK_COLOR_NORMAL_CONTRAST, { color.set_ivar(AQUA_DARK_COLOR_NORMAL_CONTRAST, {
let color: id = handler(Style { to_objc(&handler(Style {
theme: Theme::Dark, theme: Theme::Dark,
contrast: Contrast::Normal contrast: Contrast::Normal
}) }))
.into();
color
}); });
(&mut *color).set_ivar(AQUA_DARK_COLOR_HIGH_CONTRAST, { color.set_ivar(AQUA_DARK_COLOR_HIGH_CONTRAST, {
let color: id = handler(Style { to_objc(&handler(Style {
theme: Theme::Light, theme: Theme::Light,
contrast: Contrast::Normal contrast: Contrast::Normal
}) }))
.into();
color
}); });
Id::from_ptr(color) color
}))) })))
} }
@ -398,10 +393,9 @@ impl Color {
/// you're not using a cached version of this unless you explicitly want the _same_ color /// you're not using a cached version of this unless you explicitly want the _same_ color
/// in every context it's used in. /// in every context it's used in.
pub fn cg_color(&self) -> CGColor { pub fn cg_color(&self) -> CGColor {
// @TODO: This should probably return a CGColorRef...
unsafe { unsafe {
let objc: id = self.into(); let objc: id = self.into();
msg_send![objc, CGColor] CGColor::wrap_under_get_rule(msg_send![objc, CGColor])
} }
} }
} }
@ -414,15 +408,8 @@ impl AsRef<Color> for Color {
} }
} }
impl From<Color> for id {
/// Consumes and returns the pointer to the underlying Color.
fn from(color: Color) -> Self {
unsafe { to_objc(&color) }
}
}
impl From<&Color> for id { impl From<&Color> for id {
/// Consumes and returns the pointer to the underlying Color. /// Returns the pointer to the underlying Color.
fn from(color: &Color) -> Self { fn from(color: &Color) -> Self {
unsafe { to_objc(color) } unsafe { to_objc(color) }
} }

View file

@ -1,5 +1,5 @@
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use crate::foundation::{id, NSUInteger, NO, YES}; use crate::foundation::{id, NSUInteger, NO, YES};
use crate::objc_access::ObjcAccess; use crate::objc_access::ObjcAccess;

View file

@ -34,9 +34,9 @@
use std::collections::HashMap; use std::collections::HashMap;
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::foundation::{id, nil, to_bool, NSData, NSMutableDictionary, NSNumber, NSString, BOOL, NO, YES}; use crate::foundation::{id, nil, to_bool, NSData, NSMutableDictionary, NSNumber, NSString, BOOL, NO, YES};
@ -48,7 +48,7 @@ pub use value::Value;
/// ///
/// This should not be used for sensitive data - use the Keychain for that. /// This should not be used for sensitive data - use the Keychain for that.
#[derive(Debug)] #[derive(Debug)]
pub struct UserDefaults(pub Id<Object>); pub struct UserDefaults(pub Id<Object, Owned>);
impl Default for UserDefaults { impl Default for UserDefaults {
/// Equivalent to calling `UserDefaults::standard()`. /// Equivalent to calling `UserDefaults::standard()`.
@ -71,7 +71,7 @@ impl UserDefaults {
/// let _ = defaults.get("test"); /// let _ = defaults.get("test");
/// ``` /// ```
pub fn standard() -> Self { pub fn standard() -> Self {
UserDefaults(unsafe { Id::from_ptr(msg_send![class!(NSUserDefaults), standardUserDefaults]) }) UserDefaults(unsafe { msg_send_id![class!(NSUserDefaults), standardUserDefaults] })
} }
/// Returns a user defaults instance for the given suite name. You typically use this to share /// Returns a user defaults instance for the given suite name. You typically use this to share
@ -89,8 +89,8 @@ impl UserDefaults {
let name = NSString::new(named); let name = NSString::new(named);
UserDefaults(unsafe { UserDefaults(unsafe {
let alloc: id = msg_send![class!(NSUserDefaults), alloc]; let alloc = msg_send_id![class!(NSUserDefaults), alloc];
Id::from_ptr(msg_send![alloc, initWithSuiteName:&*name]) msg_send_id![alloc, initWithSuiteName:&*name]
}) })
} }
@ -130,10 +130,10 @@ impl UserDefaults {
/// ``` /// ```
pub fn insert<K: AsRef<str>>(&mut self, key: K, value: Value) { pub fn insert<K: AsRef<str>>(&mut self, key: K, value: Value) {
let key = NSString::new(key.as_ref()); let key = NSString::new(key.as_ref());
let value: id = value.into(); let value: id = &mut *value.into_id();
unsafe { unsafe {
let _: () = msg_send![&*self.0, setObject:value forKey:key]; let _: () = msg_send![&*self.0, setObject: value, forKey: &*key];
} }
} }
@ -200,7 +200,7 @@ impl UserDefaults {
// //
// For context: https://nshipster.com/type-encodings/ // For context: https://nshipster.com/type-encodings/
if NSNumber::is(result) { if NSNumber::is(result) {
let number = NSNumber::wrap(result); let number = NSNumber::retain(result);
return match number.objc_type() { return match number.objc_type() {
"c" => Some(Value::Bool(number.as_bool())), "c" => Some(Value::Bool(number.as_bool())),

View file

@ -1,5 +1,10 @@
use std::collections::HashMap; use std::collections::HashMap;
use objc::{
rc::{Id, Owned, Shared},
runtime::Object
};
use crate::foundation::{id, NSData, NSMutableDictionary, NSNumber, NSString}; use crate::foundation::{id, NSData, NSMutableDictionary, NSNumber, NSString};
/// Represents a Value that can be stored or queried with `UserDefaults`. /// Represents a Value that can be stored or queried with `UserDefaults`.
@ -128,19 +133,17 @@ impl Value {
_ => None _ => None
} }
} }
}
impl From<Value> for id {
/// Shepherds `Value` types into `NSObject`s that can be stored in `NSUserDefaults`. /// Shepherds `Value` types into `NSObject`s that can be stored in `NSUserDefaults`.
// These currently work, but may not be exhaustive and should be looked over past the preview // These currently work, but may not be exhaustive and should be looked over past the preview
// period. // period.
fn from(value: Value) -> Self { pub fn into_id(self) -> Id<Object, Owned> {
match value { match self {
Value::Bool(b) => NSNumber::bool(b).into(), Value::Bool(b) => NSNumber::bool(b).0,
Value::String(s) => NSString::new(&s).into(), Value::String(s) => NSString::new(&s).objc,
Value::Float(f) => NSNumber::float(f).into(), Value::Float(f) => NSNumber::float(f).0,
Value::Integer(i) => NSNumber::integer(i).into(), Value::Integer(i) => NSNumber::integer(i).0,
Value::Data(data) => NSData::new(data).into() Value::Data(data) => NSData::new(data).0
} }
} }
} }
@ -155,7 +158,7 @@ where
for (key, value) in map.into_iter() { for (key, value) in map.into_iter() {
let k = NSString::new(key.as_ref()); let k = NSString::new(key.as_ref());
dictionary.insert(k, value.into()); dictionary.insert(k, &mut *value.into_id());
} }
dictionary dictionary

View file

@ -2,9 +2,9 @@
//! across the codebase, hence why they're here - they're not currently exhaustive, so feel free to //! across the codebase, hence why they're here - they're not currently exhaustive, so feel free to
//! tinker and pull request. //! tinker and pull request.
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, sel};
use objc_id::ShareId;
use crate::foundation::NSUInteger; use crate::foundation::NSUInteger;
use crate::pasteboard::Pasteboard; use crate::pasteboard::Pasteboard;
@ -54,7 +54,7 @@ impl From<DragOperation> for NSUInteger {
/// this only provides getters - merely a Rust-y way to grab what you need. /// this only provides getters - merely a Rust-y way to grab what you need.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DragInfo { pub struct DragInfo {
pub info: ShareId<Object> pub info: Id<Object, Shared>
} }
impl DragInfo { impl DragInfo {

View file

@ -7,7 +7,7 @@
use std::error; use std::error;
use std::fmt; use std::fmt;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use crate::foundation::{id, nil, NSInteger, NSString}; use crate::foundation::{id, nil, NSInteger, NSString};
@ -58,7 +58,7 @@ impl Error {
unsafe { unsafe {
let domain = NSString::new(&self.domain); let domain = NSString::new(&self.domain);
let code = self.code as NSInteger; let code = self.code as NSInteger;
msg_send![class!(NSError), errorWithDomain:domain code:code userInfo:nil] msg_send![class!(NSError), errorWithDomain: &*domain, code: code, userInfo: nil]
} }
} }
} }

View file

@ -4,9 +4,9 @@
use std::error::Error; use std::error::Error;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use objc::rc::{Id, Owned};
use objc::runtime::{Object, BOOL}; use objc::runtime::{Object, BOOL};
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use url::Url; use url::Url;
use crate::error::Error as AppKitError; use crate::error::Error as AppKitError;
@ -18,17 +18,16 @@ use crate::foundation::{id, nil, NSString, NSUInteger, NO};
/// If your app is not sandboxed, you can use your favorite Rust library - /// If your app is not sandboxed, you can use your favorite Rust library -
/// but if you _are_ operating in the sandbox, there's a good chance you'll want to use this. /// but if you _are_ operating in the sandbox, there's a good chance you'll want to use this.
/// ///
/// @TODO: Couldn't this just be a ShareId? /// @TODO: Couldn't this just be a Id<Object, Shared>?
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct FileManager(pub Arc<RwLock<Id<Object>>>); pub struct FileManager(pub Arc<RwLock<Id<Object, Owned>>>);
impl Default for FileManager { impl Default for FileManager {
/// Returns a default file manager, which maps to the default system file manager. For common /// Returns a default file manager, which maps to the default system file manager. For common
/// and simple tasks, with no callbacks, you might want this. /// and simple tasks, with no callbacks, you might want this.
fn default() -> Self { fn default() -> Self {
FileManager(Arc::new(RwLock::new(unsafe { FileManager(Arc::new(RwLock::new(unsafe {
let manager: id = msg_send![class!(NSFileManager), defaultManager]; msg_send_id![class!(NSFileManager), defaultManager]
Id::from_ptr(manager)
}))) })))
} }
} }
@ -36,10 +35,7 @@ impl Default for FileManager {
impl FileManager { impl FileManager {
/// Returns a new FileManager that opts in to delegate methods. /// Returns a new FileManager that opts in to delegate methods.
pub fn new() -> Self { pub fn new() -> Self {
FileManager(Arc::new(RwLock::new(unsafe { FileManager(Arc::new(RwLock::new(unsafe { msg_send_id![class!(NSFileManager), new] })))
let manager: id = msg_send![class!(NSFileManager), new];
Id::from_ptr(manager)
})))
} }
/// Given a directory/domain combination, will attempt to get the directory that matches. /// Given a directory/domain combination, will attempt to get the directory that matches.

View file

@ -4,19 +4,19 @@
use block::ConcreteBlock; use block::ConcreteBlock;
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::foundation::{id, nil, NSInteger, NSString, NO, YES}; use crate::foundation::{id, nil, NSInteger, NSString, NO, YES};
#[derive(Debug)] #[derive(Debug)]
pub struct FileSavePanel { pub struct FileSavePanel {
/// The internal Objective C `NSOpenPanel` instance. /// The internal Objective C `NSOpenPanel` instance.
pub panel: ShareId<Object>, pub panel: Id<Object, Shared>,
/// The internal `NSObject` that routes delegate callbacks around. /// The internal `NSObject` that routes delegate callbacks around.
pub delegate: ShareId<Object>, pub delegate: Id<Object, Shared>,
/// Whether the user can choose files. Defaults to `true`. /// Whether the user can choose files. Defaults to `true`.
pub can_create_directories: bool pub can_create_directories: bool
@ -35,11 +35,10 @@ impl FileSavePanel {
FileSavePanel { FileSavePanel {
panel: unsafe { panel: unsafe {
let cls = class!(NSSavePanel); let cls = class!(NSSavePanel);
let x: id = msg_send![cls, savePanel]; msg_send_id![cls, savePanel]
ShareId::from_ptr(x)
}, },
delegate: unsafe { ShareId::from_ptr(msg_send![class!(NSObject), new]) }, delegate: unsafe { msg_send_id![class!(NSObject), new] },
can_create_directories: true can_create_directories: true
} }
@ -95,7 +94,7 @@ impl FileSavePanel {
let _: () = msg_send![&*self.panel, runModal]; let _: () = msg_send![&*self.panel, runModal];
completion.call((1,)); completion.call((1,));
//beginWithCompletionHandler:completion.copy()]; //beginWithCompletionHandler:completion.copy()];
//let _: () = msg_send![&*self.panel, beginWithCompletionHandler:completion.copy()]; //let _: () = msg_send![&*self.panel, beginWithCompletionHandler: &*completion.copy()];
} }
} }
} }

View file

@ -6,9 +6,9 @@ use std::path::PathBuf;
use block::ConcreteBlock; use block::ConcreteBlock;
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::filesystem::enums::ModalResponse; use crate::filesystem::enums::ModalResponse;
use crate::foundation::{id, nil, NSInteger, NSString, NO, NSURL, YES}; use crate::foundation::{id, nil, NSInteger, NSString, NO, NSURL, YES};
@ -19,10 +19,10 @@ use crate::appkit::window::{Window, WindowDelegate};
#[derive(Debug)] #[derive(Debug)]
pub struct FileSelectPanel { pub struct FileSelectPanel {
/// The internal Objective C `NSOpenPanel` instance. /// The internal Objective C `NSOpenPanel` instance.
pub panel: ShareId<Object>, pub panel: Id<Object, Shared>,
/// The internal `NSObject` that routes delegate callbacks around. /// The internal `NSObject` that routes delegate callbacks around.
pub delegate: ShareId<Object>, pub delegate: Id<Object, Shared>,
/// Whether the user can choose files. Defaults to `true`. /// Whether the user can choose files. Defaults to `true`.
pub can_choose_files: bool, pub can_choose_files: bool,
@ -54,11 +54,10 @@ impl FileSelectPanel {
FileSelectPanel { FileSelectPanel {
panel: unsafe { panel: unsafe {
let cls = class!(NSOpenPanel); let cls = class!(NSOpenPanel);
let x: id = msg_send![cls, openPanel]; msg_send_id![cls, openPanel]
ShareId::from_ptr(x)
}, },
delegate: unsafe { ShareId::from_ptr(msg_send![class!(NSObject), new]) }, delegate: unsafe { msg_send_id![class!(NSObject), new] },
can_choose_files: true, can_choose_files: true,
can_choose_directories: false, can_choose_directories: false,
@ -148,7 +147,7 @@ impl FileSelectPanel {
}); });
unsafe { unsafe {
let _: () = msg_send![&*self.panel, beginWithCompletionHandler:completion.copy()]; let _: () = msg_send![&*self.panel, beginWithCompletionHandler: &*completion.copy()];
} }
} }
@ -184,7 +183,11 @@ impl FileSelectPanel {
}); });
unsafe { unsafe {
let _: () = msg_send![&*self.panel, beginSheetModalForWindow:&*window.objc completionHandler:completion.copy()]; let _: () = msg_send![
&*self.panel,
beginSheetModalForWindow: &*window.objc,
completionHandler: &*completion.copy(),
];
} }
} }
} }

View file

@ -1,8 +1,8 @@
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::foundation::id; use crate::foundation::id;
@ -11,29 +11,24 @@ use crate::foundation::id;
/// ever deemed necessary (unlikely, given how much Apple has optimized the Foundation classes, but /// ever deemed necessary (unlikely, given how much Apple has optimized the Foundation classes, but
/// still...). /// still...).
#[derive(Debug)] #[derive(Debug)]
pub struct NSArray(pub Id<Object>); pub struct NSArray(pub Id<Object, Owned>);
impl NSArray { impl NSArray {
/// Given a set of `Object`s, creates and retains an `NSArray` that holds them. /// Given a set of `Object`s, creates and retains an `NSArray` that holds them.
pub fn new(objects: &[id]) -> Self { pub fn new(objects: &[id]) -> Self {
NSArray(unsafe { NSArray(unsafe {
Id::from_ptr(msg_send![class!(NSArray), msg_send_id![
arrayWithObjects:objects.as_ptr() class!(NSArray),
count:objects.len() arrayWithObjects: objects.as_ptr(),
]) count: objects.len()
]
}) })
} }
/// In some cases, we're vended an `NSArray` by the system that we need to call retain on. /// In some cases, we're vended an `NSArray` by the system that we need to call retain on.
/// This handles that case. /// This handles that case.
pub fn retain(array: id) -> Self { pub fn retain(array: id) -> Self {
NSArray(unsafe { Id::from_ptr(array) }) NSArray(unsafe { Id::retain(array).unwrap() })
}
/// In some cases, we're vended an `NSArray` by the system, and it's ideal to not retain that.
/// This handles that edge case.
pub fn from_retained(array: id) -> Self {
NSArray(unsafe { Id::from_retained_ptr(array) })
} }
/// Returns the `count` (`len()` equivalent) for the backing `NSArray`. /// Returns the `count` (`len()` equivalent) for the backing `NSArray`.
@ -83,10 +78,11 @@ impl From<Vec<&Object>> for NSArray {
/// Given a set of `Object`s, creates an `NSArray` that holds them. /// Given a set of `Object`s, creates an `NSArray` that holds them.
fn from(objects: Vec<&Object>) -> Self { fn from(objects: Vec<&Object>) -> Self {
NSArray(unsafe { NSArray(unsafe {
Id::from_ptr(msg_send![class!(NSArray), msg_send_id![
arrayWithObjects:objects.as_ptr() class!(NSArray),
count:objects.len() arrayWithObjects: objects.as_ptr(),
]) count: objects.len(),
]
}) })
} }
} }
@ -95,21 +91,15 @@ impl From<Vec<id>> for NSArray {
/// Given a set of `*mut Object`s, creates an `NSArray` that holds them. /// Given a set of `*mut Object`s, creates an `NSArray` that holds them.
fn from(objects: Vec<id>) -> Self { fn from(objects: Vec<id>) -> Self {
NSArray(unsafe { NSArray(unsafe {
Id::from_ptr(msg_send![class!(NSArray), msg_send_id![
arrayWithObjects:objects.as_ptr() class!(NSArray),
count:objects.len() arrayWithObjects: objects.as_ptr(),
]) count: objects.len()
]
}) })
} }
} }
impl From<NSArray> for id {
/// Consumes and returns the pointer to the underlying NSArray.
fn from(mut array: NSArray) -> Self {
&mut *array
}
}
impl Deref for NSArray { impl Deref for NSArray {
type Target = Object; type Target = Object;

View file

@ -1,6 +1,6 @@
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
/// A wrapper around `NSAutoReleasePool`. The core `App` structures create and manage one of these, /// A wrapper around `NSAutoReleasePool`. The core `App` structures create and manage one of these,
/// but it's conceivable that users might need to create their own. /// but it's conceivable that users might need to create their own.
@ -8,13 +8,13 @@ use objc_id::Id;
/// When this is dropped, we automatically send a `drain` message to the underlying pool. You can /// When this is dropped, we automatically send a `drain` message to the underlying pool. You can
/// also call `drain()` yourself if you need to drain for whatever reason. /// also call `drain()` yourself if you need to drain for whatever reason.
#[derive(Debug)] #[derive(Debug)]
pub struct AutoReleasePool(pub Id<Object>); pub struct AutoReleasePool(pub Id<Object, Owned>);
impl AutoReleasePool { impl AutoReleasePool {
/// Creates and returns a new `AutoReleasePool`. You need to take care to keep this alive for /// Creates and returns a new `AutoReleasePool`. You need to take care to keep this alive for
/// as long as you need it. /// as long as you need it.
pub fn new() -> Self { pub fn new() -> Self {
AutoReleasePool(unsafe { Id::from_retained_ptr(msg_send![class!(NSAutoreleasePool), new]) }) AutoReleasePool(unsafe { msg_send_id![class!(NSAutoreleasePool), new] })
} }
/// Drains the underlying AutoreleasePool. /// Drains the underlying AutoreleasePool.

View file

@ -9,7 +9,8 @@ use std::time::Instant;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use objc::declare::ClassDecl; use objc::declare::ClassDecl;
use objc::runtime::{objc_getClass, Class}; use objc::ffi;
use objc::runtime::Class;
lazy_static! { lazy_static! {
static ref CLASSES: ClassMap = ClassMap::new(); static ref CLASSES: ClassMap = ClassMap::new();
@ -59,7 +60,7 @@ impl ClassMap {
} }
/// A publicly accessible load method that just passes through our global singleton. /// A publicly accessible load method that just passes through our global singleton.
pub fn static_load(class_name: &'static str, superclass_name: Option<&'static str>) -> Option<*const Class> { pub fn static_load(class_name: &'static str, superclass_name: Option<&'static str>) -> Option<&'static Class> {
CLASSES.load(class_name, superclass_name) CLASSES.load(class_name, superclass_name)
} }
@ -67,12 +68,12 @@ impl ClassMap {
/// ///
/// This checks our internal map first, and then calls out to the Objective-C runtime to ensure /// This checks our internal map first, and then calls out to the Objective-C runtime to ensure
/// we're not missing anything. /// we're not missing anything.
pub fn load(&self, class_name: &'static str, superclass_name: Option<&'static str>) -> Option<*const Class> { pub fn load(&self, class_name: &'static str, superclass_name: Option<&'static str>) -> Option<&'static Class> {
{ {
let reader = self.0.read().unwrap(); let reader = self.0.read().unwrap();
if let Some(entry) = (*reader).get(&(class_name, superclass_name)) { if let Some(entry) = (*reader).get(&(class_name, superclass_name)) {
let ptr = &entry.ptr; let ptr = &entry.ptr;
return Some(*ptr as *const Class); return Some(unsafe { &*(*ptr as *const Class) });
} }
} }
@ -83,7 +84,7 @@ impl ClassMap {
// runtime, and we can wind up in a situation where we're attempting to register a Class // runtime, and we can wind up in a situation where we're attempting to register a Class
// that already exists but we can't see. // that already exists but we can't see.
let objc_class_name = CString::new(class_name).unwrap(); let objc_class_name = CString::new(class_name).unwrap();
let class = unsafe { objc_getClass(objc_class_name.as_ptr() as *const _) }; let class = unsafe { ffi::objc_getClass(objc_class_name.as_ptr() as *const _) };
// This should not happen for our use-cases, but it's conceivable that this could actually // This should not happen for our use-cases, but it's conceivable that this could actually
// be expected, so just return None and let the caller panic if so desired. // be expected, so just return None and let the caller panic if so desired.
@ -101,7 +102,7 @@ impl ClassMap {
}); });
} }
Some(class) Some(unsafe { class.cast::<Class>().as_ref() }.unwrap())
} }
/// Store a newly created subclass type. /// Store a newly created subclass type.
@ -129,7 +130,7 @@ impl ClassMap {
/// > class name - but most cases do not need this and it would be a larger change to orchestrate at /// > class name - but most cases do not need this and it would be a larger change to orchestrate at
/// > the moment. /// > the moment.
#[inline(always)] #[inline(always)]
pub fn load_or_register_class<F>(superclass_name: &'static str, subclass_name: &'static str, config: F) -> *const Class pub fn load_or_register_class<F>(superclass_name: &'static str, subclass_name: &'static str, config: F) -> &'static Class
where where
F: Fn(&mut ClassDecl) + 'static F: Fn(&mut ClassDecl) + 'static
{ {
@ -155,7 +156,7 @@ pub fn load_or_register_class_with_optional_generated_suffix<F>(
subclass_name: &'static str, subclass_name: &'static str,
should_append_random_subclass_name_suffix: bool, should_append_random_subclass_name_suffix: bool,
config: F config: F
) -> *const Class ) -> &'static Class
where where
F: Fn(&mut ClassDecl) + 'static F: Fn(&mut ClassDecl) + 'static
{ {
@ -188,7 +189,7 @@ where
false => format!("{}_{}", subclass_name, superclass_name) false => format!("{}_{}", subclass_name, superclass_name)
}; };
match ClassDecl::new(&objc_subclass_name, unsafe { &*superclass }) { match ClassDecl::new(&objc_subclass_name, superclass) {
Some(mut decl) => { Some(mut decl) => {
config(&mut decl); config(&mut decl);

View file

@ -5,9 +5,9 @@ use std::slice;
use block::{Block, ConcreteBlock}; use block::{Block, ConcreteBlock};
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::foundation::{id, to_bool, NSUInteger, BOOL, NO, YES}; use crate::foundation::{id, to_bool, NSUInteger, BOOL, NO, YES};
@ -18,7 +18,7 @@ use crate::foundation::{id, to_bool, NSUInteger, BOOL, NO, YES};
/// ///
/// This is an intentionally limited API. /// This is an intentionally limited API.
#[derive(Debug)] #[derive(Debug)]
pub struct NSData(pub Id<Object>); pub struct NSData(pub Id<Object, Owned>);
impl NSData { impl NSData {
/// Given a vector of bytes, creates, retains, and returns a wrapped `NSData`. /// Given a vector of bytes, creates, retains, and returns a wrapped `NSData`.
@ -41,12 +41,15 @@ impl NSData {
let bytes_ptr = bytes.as_mut_ptr() as *mut c_void; let bytes_ptr = bytes.as_mut_ptr() as *mut c_void;
unsafe { unsafe {
let obj: id = msg_send![class!(NSData), alloc]; let obj = msg_send_id![class!(NSData), alloc];
let obj: id = msg_send![obj, initWithBytesNoCopy:bytes_ptr let obj = msg_send_id![
length:bytes.len() obj,
deallocator:dealloc]; initWithBytesNoCopy: bytes_ptr,
length: bytes.len(),
deallocator: dealloc,
];
mem::forget(bytes); mem::forget(bytes);
NSData(Id::from_ptr(obj)) NSData(obj)
} }
} }
@ -60,20 +63,18 @@ impl NSData {
let bytes_ptr = bytes.as_ptr() as *mut c_void; let bytes_ptr = bytes.as_ptr() as *mut c_void;
unsafe { unsafe {
let obj: id = msg_send![class!(NSData), dataWithBytes:bytes_ptr length:bytes.len()]; let obj = msg_send_id![
NSData(Id::from_ptr(obj)) class!(NSData),
dataWithBytes: bytes_ptr,
length: bytes.len(),
];
NSData(obj)
} }
} }
/// Given a (presumably) `NSData`, wraps and retains it. /// Given a (presumably) `NSData`, wraps and retains it.
pub fn retain(data: id) -> Self { pub fn retain(data: id) -> Self {
NSData(unsafe { Id::from_ptr(data) }) NSData(unsafe { Id::retain(data).unwrap() })
}
/// If we're vended an NSData from a method (e.g, a push notification token) we might want to
/// wrap it while we figure out what to do with it. This does that.
pub fn from_retained(data: id) -> Self {
NSData(unsafe { Id::from_retained_ptr(data) })
} }
/// A helper method for determining if a given `NSObject` is an `NSData`. /// A helper method for determining if a given `NSObject` is an `NSData`.
@ -127,13 +128,6 @@ impl NSData {
} }
} }
impl From<NSData> for id {
/// Consumes and returns the underlying `NSData`.
fn from(mut data: NSData) -> Self {
&mut *data.0
}
}
impl Deref for NSData { impl Deref for NSData {
type Target = Object; type Target = Object;

View file

@ -1,15 +1,15 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::foundation::{id, NSString}; use crate::foundation::{id, NSString};
/// A wrapper for `NSMutableDictionary`. /// A wrapper for `NSMutableDictionary`.
#[derive(Debug)] #[derive(Debug)]
pub struct NSMutableDictionary(pub Id<Object>); pub struct NSMutableDictionary(pub Id<Object, Owned>);
impl Default for NSMutableDictionary { impl Default for NSMutableDictionary {
/// Returns a blank NSMutableDictionary. /// Returns a blank NSMutableDictionary.
@ -26,7 +26,7 @@ impl NSMutableDictionary {
/// object model. You can, of course, bypass it and `msg_send![]` yourself, but it'd require an /// object model. You can, of course, bypass it and `msg_send![]` yourself, but it'd require an
/// `unsafe {}` block... so you'll know you're in special territory then. /// `unsafe {}` block... so you'll know you're in special territory then.
pub fn new() -> Self { pub fn new() -> Self {
NSMutableDictionary(unsafe { Id::from_ptr(msg_send![class!(NSMutableDictionary), new]) }) NSMutableDictionary(unsafe { msg_send_id![class!(NSMutableDictionary), new] })
} }
/// Inserts an object into the backing NSMutablyDictionary. /// Inserts an object into the backing NSMutablyDictionary.
@ -37,11 +37,6 @@ impl NSMutableDictionary {
let _: () = msg_send![&*self.0, setObject:object forKey:&*key]; let _: () = msg_send![&*self.0, setObject:object forKey:&*key];
} }
} }
/// Consumes and returns the underlying `NSMutableDictionary`.
pub fn into_inner(mut self) -> id {
&mut *self.0
}
} }
impl Deref for NSMutableDictionary { impl Deref for NSMutableDictionary {

View file

@ -1,9 +1,9 @@
use std::ffi::CStr; use std::ffi::CStr;
use std::os::raw::c_char; use std::os::raw::c_char;
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::foundation::{id, to_bool, NSInteger, BOOL, NO, YES}; use crate::foundation::{id, to_bool, NSInteger, BOOL, NO, YES};
@ -12,39 +12,33 @@ use crate::foundation::{id, to_bool, NSInteger, BOOL, NO, YES};
/// In general we strive to avoid using this in the codebase, but it's a requirement for moving /// In general we strive to avoid using this in the codebase, but it's a requirement for moving
/// objects in and out of certain situations (e.g, `UserDefaults`). /// objects in and out of certain situations (e.g, `UserDefaults`).
#[derive(Debug)] #[derive(Debug)]
pub struct NSNumber(pub Id<Object>); pub struct NSNumber(pub Id<Object, Owned>);
impl NSNumber { impl NSNumber {
/// If we're vended an NSNumber from a method (e.g, `NSUserDefaults` querying) we might want to /// If we're vended an NSNumber from a method (e.g, `NSUserDefaults` querying) we might want to
/// wrap (and retain) it while we figure out what to do with it. This does that. /// wrap (and retain) it while we figure out what to do with it. This does that.
pub fn retain(data: id) -> Self { pub fn retain(data: id) -> Self {
NSNumber(unsafe { Id::from_ptr(data) }) NSNumber(unsafe { Id::retain(data).unwrap() })
}
/// If we're vended an NSNumber from a method (e.g, `NSUserDefaults` querying) we might want to
/// wrap it while we figure out what to do with it. This does that.
pub fn wrap(data: id) -> Self {
NSNumber(unsafe { Id::from_retained_ptr(data) })
} }
/// Constructs a `numberWithBool` instance of `NSNumber` and retains it. /// Constructs a `numberWithBool` instance of `NSNumber` and retains it.
pub fn bool(value: bool) -> Self { pub fn bool(value: bool) -> Self {
NSNumber(unsafe { NSNumber(unsafe {
Id::from_retained_ptr(msg_send![class!(NSNumber), numberWithBool:match value { msg_send_id![class!(NSNumber), numberWithBool:match value {
true => YES, true => YES,
false => NO false => NO
}]) }]
}) })
} }
/// Constructs a `numberWithInteger` instance of `NSNumber` and retains it. /// Constructs a `numberWithInteger` instance of `NSNumber` and retains it.
pub fn integer(value: i64) -> Self { pub fn integer(value: i64) -> Self {
NSNumber(unsafe { Id::from_retained_ptr(msg_send![class!(NSNumber), numberWithInteger: value as NSInteger]) }) NSNumber(unsafe { msg_send_id![class!(NSNumber), numberWithInteger: value as NSInteger] })
} }
/// Constructs a `numberWithDouble` instance of `NSNumber` and retains it. /// Constructs a `numberWithDouble` instance of `NSNumber` and retains it.
pub fn float(value: f64) -> Self { pub fn float(value: f64) -> Self {
NSNumber(unsafe { Id::from_retained_ptr(msg_send![class!(NSNumber), numberWithDouble: value]) }) NSNumber(unsafe { msg_send_id![class!(NSNumber), numberWithDouble: value] })
} }
/// Returns the `objCType` of the underlying `NSNumber` as a Rust `&str`. This flag can be used /// Returns the `objCType` of the underlying `NSNumber` as a Rust `&str`. This flag can be used
@ -96,10 +90,3 @@ impl NSNumber {
to_bool(result) to_bool(result)
} }
} }
impl From<NSNumber> for id {
/// Consumes and returns the underlying `NSNumber`.
fn from(mut number: NSNumber) -> Self {
&mut *number.0
}
}

View file

@ -3,9 +3,9 @@ use std::ops::{Deref, DerefMut};
use std::os::raw::c_char; use std::os::raw::c_char;
use std::{fmt, slice, str}; use std::{fmt, slice, str};
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::foundation::{id, to_bool, BOOL, NO, YES}; use crate::foundation::{id, to_bool, BOOL, NO, YES};
@ -18,7 +18,7 @@ const UTF8_ENCODING: usize = 4;
#[derive(Debug)] #[derive(Debug)]
pub struct NSString<'a> { pub struct NSString<'a> {
/// A reference to the backing `NSString`. /// A reference to the backing `NSString`.
pub objc: Id<Object>, pub objc: Id<Object, Owned>,
phantom: PhantomData<&'a ()> phantom: PhantomData<&'a ()>
} }
@ -27,11 +27,12 @@ impl<'a> NSString<'a> {
pub fn new(s: &str) -> Self { pub fn new(s: &str) -> Self {
NSString { NSString {
objc: unsafe { objc: unsafe {
let nsstring: *mut Object = msg_send![class!(NSString), alloc]; msg_send_id![
Id::from_ptr(msg_send![nsstring, initWithBytes:s.as_ptr() msg_send_id![class!(NSString), alloc],
length:s.len() initWithBytes: s.as_ptr(),
encoding:UTF8_ENCODING length: s.len(),
]) encoding: UTF8_ENCODING,
]
}, },
phantom: PhantomData phantom: PhantomData
@ -42,12 +43,14 @@ impl<'a> NSString<'a> {
pub fn no_copy(s: &'a str) -> Self { pub fn no_copy(s: &'a str) -> Self {
NSString { NSString {
objc: unsafe { objc: unsafe {
let nsstring: id = msg_send![class!(NSString), alloc]; let nsstring = msg_send_id![class!(NSString), alloc];
Id::from_ptr(msg_send![nsstring, initWithBytesNoCopy:s.as_ptr() msg_send_id![
length:s.len() nsstring,
encoding:UTF8_ENCODING initWithBytesNoCopy: s.as_ptr(),
freeWhenDone:NO length: s.len(),
]) encoding: UTF8_ENCODING,
freeWhenDone: NO,
]
}, },
phantom: PhantomData phantom: PhantomData
@ -58,15 +61,14 @@ impl<'a> NSString<'a> {
/// retain it. /// retain it.
pub fn retain(object: id) -> Self { pub fn retain(object: id) -> Self {
NSString { NSString {
objc: unsafe { Id::from_ptr(object) }, objc: unsafe { Id::retain(object).unwrap() },
phantom: PhantomData phantom: PhantomData
} }
} }
/// In some cases, we want to wrap a system-provided NSString without retaining it. pub fn from_id(objc: Id<Object, Owned>) -> Self {
pub fn from_retained(object: id) -> Self { Self {
NSString { objc,
objc: unsafe { Id::from_retained_ptr(object) },
phantom: PhantomData phantom: PhantomData
} }
} }
@ -113,13 +115,6 @@ impl fmt::Display for NSString<'_> {
} }
} }
impl From<NSString<'_>> for id {
/// Consumes and returns the pointer to the underlying NSString instance.
fn from(mut string: NSString) -> Self {
&mut *string.objc
}
}
impl Deref for NSString<'_> { impl Deref for NSString<'_> {
type Target = Object; type Target = Object;

View file

@ -3,9 +3,9 @@ use std::marker::PhantomData;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::path::PathBuf; use std::path::PathBuf;
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::foundation::{id, nil, NSData, NSString, NSUInteger}; use crate::foundation::{id, nil, NSData, NSString, NSUInteger};
@ -31,7 +31,7 @@ pub use resource_keys::{NSURLFileResource, NSURLResourceKey, NSUbiquitousItemDow
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct NSURL<'a> { pub struct NSURL<'a> {
/// A reference to the backing `NSURL`. /// A reference to the backing `NSURL`.
pub objc: ShareId<Object>, pub objc: Id<Object, Shared>,
phantom: PhantomData<&'a ()> phantom: PhantomData<&'a ()>
} }
@ -40,15 +40,7 @@ impl<'a> NSURL<'a> {
/// retain it. /// retain it.
pub fn retain(object: id) -> Self { pub fn retain(object: id) -> Self {
NSURL { NSURL {
objc: unsafe { ShareId::from_ptr(object) }, objc: unsafe { Id::retain(object).unwrap() },
phantom: PhantomData
}
}
/// In some cases, we want to wrap a system-provided NSURL without retaining it.
pub fn from_retained(object: id) -> Self {
NSURL {
objc: unsafe { ShareId::from_retained_ptr(object) },
phantom: PhantomData phantom: PhantomData
} }
} }
@ -58,7 +50,7 @@ impl<'a> NSURL<'a> {
let url = NSString::new(url); let url = NSString::new(url);
Self { Self {
objc: unsafe { ShareId::from_ptr(msg_send![class!(NSURL), URLWithString:&*url]) }, objc: unsafe { msg_send_id![class!(NSURL), URLWithString:&*url] },
phantom: PhantomData phantom: PhantomData
} }
@ -105,18 +97,22 @@ impl<'a> NSURL<'a> {
// Mutability woes mean we just go through a match here to satisfy message passing needs. // Mutability woes mean we just go through a match here to satisfy message passing needs.
let bookmark_data = NSData::retain(match relative_to_url { let bookmark_data = NSData::retain(match relative_to_url {
Some(relative_url) => unsafe { Some(relative_url) => unsafe {
msg_send![&*self.objc, bookmarkDataWithOptions:opts msg_send![
includingResourceValuesForKeys:resource_keys &*self.objc,
relativeToURL:relative_url bookmarkDataWithOptions: opts,
error:nil includingResourceValuesForKeys: resource_keys,
relativeToURL: &*relative_url,
error: nil,
] ]
}, },
None => unsafe { None => unsafe {
msg_send![&*self.objc, bookmarkDataWithOptions:opts msg_send![
includingResourceValuesForKeys:resource_keys &*self.objc,
relativeToURL:nil bookmarkDataWithOptions: opts,
error:nil includingResourceValuesForKeys: resource_keys,
relativeToURL: nil,
error: nil,
] ]
} }
}); });
@ -158,13 +154,6 @@ impl<'a> NSURL<'a> {
} }
} }
/*impl From<NSString<'_>> for id {
/// Consumes and returns the pointer to the underlying NSString instance.
fn from(mut string: NSString) -> Self {
&mut *string.objc
}
}*/
impl Deref for NSURL<'_> { impl Deref for NSURL<'_> {
type Target = Object; type Target = Object;

View file

@ -14,8 +14,8 @@ use crate::foundation::load_or_register_class;
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we /// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be /// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates. /// used if there's no delegates.
pub(crate) fn register_image_view_class() -> *const Class { pub(crate) fn register_image_view_class() -> &'static Class {
load_or_register_class("NSImageView", "RSTImageView", |decl| unsafe { load_or_register_class("NSImageView", "RSTImageView", |decl| unsafe {
//decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); //decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
}) })
} }

View file

@ -1,12 +1,12 @@
use objc_id::ShareId; use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
/// Views get passed these, and can /// Views get passed these, and can
#[derive(Debug)] #[derive(Debug)]
pub struct ViewHandle<T> { pub struct ViewHandle<T> {
/// A pointer to the Objective-C runtime view controller. /// A pointer to the Objective-C runtime view controller.
pub objc: ShareId<Object>, pub objc: Id<Object, Shared>,
_t: std::marker::PhantomData<T> _t: std::marker::PhantomData<T>
@ -40,7 +40,7 @@ where
T: T:
impl<T> Layout for ViewHandle<T> { impl<T> Layout for ViewHandle<T> {
fn get_backing_node(&self) -> ShareId<Object> { fn get_backing_node(&self) -> Id<Object, Shared> {
self.objc.clone() self.objc.clone()
} }

View file

@ -1,7 +1,7 @@
use objc::runtime::{Class, Object}; use objc::rc::{Id, Shared};
use objc_id::ShareId; use objc::runtime::{Bool, Class, Object};
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use block::ConcreteBlock; use block::ConcreteBlock;
@ -12,7 +12,7 @@ use core_graphics::{
}; };
use super::icons::*; use super::icons::*;
use crate::foundation::{id, NSData, NSString, NO, NSURL, YES}; use crate::foundation::{id, NSData, NSString, NSURL};
use crate::utils::os; use crate::utils::os;
/// Specifies resizing behavior for image drawing. /// Specifies resizing behavior for image drawing.
@ -119,7 +119,7 @@ pub struct DrawConfig {
/// Wraps `NSImage` under AppKit, and `UIImage` on under UIKit (iOS and tvOS). Can be used to display images, icons, /// Wraps `NSImage` under AppKit, and `UIImage` on under UIKit (iOS and tvOS). Can be used to display images, icons,
/// and so on. /// and so on.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Image(pub ShareId<Object>); pub struct Image(pub Id<Object, Shared>);
impl Image { impl Image {
fn class() -> &'static Class { fn class() -> &'static Class {
@ -133,7 +133,7 @@ impl Image {
/// Wraps a system-returned image, e.g from QuickLook previews. /// Wraps a system-returned image, e.g from QuickLook previews.
pub fn with(image: id) -> Self { pub fn with(image: id) -> Self {
Image(unsafe { ShareId::from_ptr(image) }) Image(unsafe { Id::retain(image).unwrap() })
} }
/// Loads an image from the specified path. /// Loads an image from the specified path.
@ -141,16 +141,16 @@ impl Image {
let file_path = NSString::new(path); let file_path = NSString::new(path);
Image(unsafe { Image(unsafe {
let alloc: id = msg_send![Self::class(), alloc]; let alloc = msg_send_id![Self::class(), alloc];
ShareId::from_ptr(msg_send![alloc, initWithContentsOfFile: file_path]) msg_send_id![alloc, initWithContentsOfFile: &*file_path]
}) })
} }
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub fn with_contents_of_url(url: NSURL) -> Self { pub fn with_contents_of_url(url: NSURL) -> Self {
Image(unsafe { Image(unsafe {
let alloc: id = msg_send![Self::class(), alloc]; let alloc = msg_send_id![Self::class(), alloc];
ShareId::from_ptr(msg_send![alloc, initWithContentsOfURL: url.objc]) msg_send_id![alloc, initWithContentsOfURL: &*url.objc]
}) })
} }
@ -160,8 +160,8 @@ impl Image {
let data = NSData::with_slice(data); let data = NSData::with_slice(data);
Image(unsafe { Image(unsafe {
let alloc: id = msg_send![Self::class(), alloc]; let alloc = msg_send_id![Self::class(), alloc];
ShareId::from_ptr(msg_send![alloc, initWithData: data]) msg_send_id![alloc, initWithData: &*data]
}) })
} }
@ -172,10 +172,8 @@ impl Image {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub fn system_icon(icon: MacSystemIcon) -> Self { pub fn system_icon(icon: MacSystemIcon) -> Self {
Image(unsafe { Image(unsafe {
ShareId::from_ptr({ let icon = icon.to_id();
let icon = icon.to_id(); msg_send_id![Self::class(), imageNamed: icon]
msg_send![Self::class(), imageNamed: icon]
})
}) })
} }
@ -192,19 +190,22 @@ impl Image {
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub fn toolbar_icon(icon: MacSystemIcon, accessibility_description: &str) -> Self { pub fn toolbar_icon(icon: MacSystemIcon, accessibility_description: &str) -> Self {
Image(unsafe { Image(unsafe {
ShareId::from_ptr(match os::is_minimum_version(11) { match os::is_minimum_version(11) {
true => { true => {
let icon = NSString::new(icon.to_sfsymbol_str()); let icon = NSString::new(icon.to_sfsymbol_str());
let desc = NSString::new(accessibility_description); let desc = NSString::new(accessibility_description);
msg_send![Self::class(), imageWithSystemSymbolName:&*icon msg_send_id![
accessibilityDescription:&*desc] Self::class(),
imageWithSystemSymbolName: &*icon,
accessibilityDescription: &*desc,
]
}, },
false => { false => {
let icon = icon.to_id(); let icon = icon.to_id();
msg_send![Self::class(), imageNamed: icon] msg_send_id![Self::class(), imageNamed: icon]
} }
}) }
}) })
} }
@ -226,12 +227,15 @@ impl Image {
let min_version = 13; let min_version = 13;
Image(unsafe { Image(unsafe {
ShareId::from_ptr(match os::is_minimum_version(min_version) { match os::is_minimum_version(min_version) {
true => { true => {
let icon = NSString::new(symbol.to_str()); let icon = NSString::new(symbol.to_str());
let desc = NSString::new(accessibility_description); let desc = NSString::new(accessibility_description);
msg_send![Self::class(), imageWithSystemSymbolName:&*icon msg_send_id![
accessibilityDescription:&*desc] Self::class(),
imageWithSystemSymbolName:&*icon,
accessibilityDescription:&*desc,
]
}, },
false => { false => {
@ -241,7 +245,7 @@ impl Image {
#[cfg(all(feature = "uikit", not(feature = "appkit")))] #[cfg(all(feature = "uikit", not(feature = "appkit")))]
panic!("SFSymbols are only supported on macOS 11.0 and up."); panic!("SFSymbols are only supported on macOS 11.0 and up.");
} }
}) }
}) })
} }
@ -276,20 +280,17 @@ impl Image {
let _: () = msg_send![class!(NSGraphicsContext), restoreGraphicsState]; let _: () = msg_send![class!(NSGraphicsContext), restoreGraphicsState];
match result { Bool::new(result)
true => YES,
false => NO
}
}); });
let block = block.copy(); let block = block.copy();
Image(unsafe { Image(unsafe {
let img: id = msg_send![Self::class(), imageWithSize:target_frame.size msg_send_id![
flipped:YES Self::class(),
drawingHandler:block imageWithSize: target_frame.size,
]; flipped: Bool::YES,
drawingHandler: &*block,
ShareId::from_ptr(img) ]
}) })
} }
} }

View file

@ -1,6 +1,8 @@
use core_foundation::base::TCFType;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::color::Color; use crate::color::Color;
use crate::foundation::{id, nil, NSArray, NSString, NO, YES}; use crate::foundation::{id, nil, NSArray, NSString, NO, YES};
@ -31,7 +33,7 @@ mod icons;
pub use icons::*; pub use icons::*;
/// A helper method for instantiating view classes and applying default settings to them. /// A helper method for instantiating view classes and applying default settings to them.
fn allocate_view(registration_fn: fn() -> *const Class) -> id { fn allocate_view(registration_fn: fn() -> &'static Class) -> id {
unsafe { unsafe {
let view: id = msg_send![registration_fn(), new]; let view: id = msg_send![registration_fn(), new];
@ -140,7 +142,7 @@ impl ImageView {
#[cfg(feature = "autolayout")] #[cfg(feature = "autolayout")]
center_y: LayoutAnchorY::center(view), center_y: LayoutAnchorY::center(view),
layer: Layer::wrap(unsafe { msg_send![view, layer] }), layer: Layer::from_id(unsafe { msg_send_id![view, layer] }),
objc: ObjcProperty::retain(view) objc: ObjcProperty::retain(view)
} }
@ -149,7 +151,7 @@ impl ImageView {
/// Call this to set the background color for the backing layer. /// Call this to set the background color for the backing layer.
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) { pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
self.objc.with_mut(|obj| unsafe { self.objc.with_mut(|obj| unsafe {
let cg = color.as_ref().cg_color(); let cg = color.as_ref().cg_color().as_concrete_TypeRef();
let layer: id = msg_send![obj, layer]; let layer: id = msg_send![obj, layer];
let _: () = msg_send![layer, setBackgroundColor: cg]; let _: () = msg_send![layer, setBackgroundColor: cg];
}); });

View file

@ -5,6 +5,6 @@ use crate::foundation::load_or_register_class;
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we /// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be /// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates. /// used if there's no delegates.
pub(crate) fn register_image_view_class() -> *const Class { pub(crate) fn register_image_view_class() -> &'static Class {
load_or_register_class("UIImageView", "RSTImageView", |decl| unsafe {}) load_or_register_class("UIImageView", "RSTImageView", |decl| unsafe {})
} }

View file

@ -1,79 +1,71 @@
use objc::runtime::{Class, Object, Sel, BOOL}; use objc::rc::{Id, Owned};
use objc::{msg_send, sel, sel_impl}; use objc::runtime::{Bool, Class, Object, Sel};
use objc::{msg_send, sel};
use crate::foundation::{id, load_or_register_class, NSString, NO, YES}; use crate::foundation::{id, load_or_register_class, NSString};
use crate::input::{TextFieldDelegate, TEXTFIELD_DELEGATE_PTR}; use crate::input::{TextFieldDelegate, TEXTFIELD_DELEGATE_PTR};
use crate::utils::load; use crate::utils::load;
/// Called when editing this text field has ended (e.g. user pressed enter). /// Called when editing this text field has ended (e.g. user pressed enter).
extern "C" fn text_did_end_editing<T: TextFieldDelegate>(this: &mut Object, _: Sel, _info: id) { extern "C" fn text_did_end_editing<T: TextFieldDelegate>(this: &Object, _: Sel, _info: id) {
let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR); let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR);
let s = NSString::retain(unsafe { msg_send![this, stringValue] }); let s = NSString::retain(unsafe { msg_send![this, stringValue] });
view.text_did_end_editing(s.to_str()); view.text_did_end_editing(s.to_str());
} }
extern "C" fn text_did_begin_editing<T: TextFieldDelegate>(this: &mut Object, _: Sel, _info: id) { extern "C" fn text_did_begin_editing<T: TextFieldDelegate>(this: &Object, _: Sel, _info: id) {
let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR); let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR);
let s = NSString::retain(unsafe { msg_send![this, stringValue] }); let s = NSString::retain(unsafe { msg_send![this, stringValue] });
view.text_did_begin_editing(s.to_str()); view.text_did_begin_editing(s.to_str());
} }
extern "C" fn text_did_change<T: TextFieldDelegate>(this: &mut Object, _: Sel, _info: id) { extern "C" fn text_did_change<T: TextFieldDelegate>(this: &Object, _: Sel, _info: id) {
let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR); let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR);
let s = NSString::retain(unsafe { msg_send![this, stringValue] }); let s = NSString::retain(unsafe { msg_send![this, stringValue] });
view.text_did_change(s.to_str()); view.text_did_change(s.to_str());
} }
extern "C" fn text_should_begin_editing<T: TextFieldDelegate>(this: &mut Object, _: Sel, _info: id) -> BOOL { extern "C" fn text_should_begin_editing<T: TextFieldDelegate>(this: &Object, _: Sel, _info: id) -> Bool {
let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR); let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR);
let s = NSString::retain(unsafe { msg_send![this, stringValue] }); let s = NSString::retain(unsafe { msg_send![this, stringValue] });
match view.text_should_begin_editing(s.to_str()) { Bool::new(view.text_should_begin_editing(s.to_str()))
true => YES,
false => NO
}
} }
extern "C" fn text_should_end_editing<T: TextFieldDelegate>(this: &mut Object, _: Sel, _info: id) -> BOOL { extern "C" fn text_should_end_editing<T: TextFieldDelegate>(this: &Object, _: Sel, _info: id) -> Bool {
let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR); let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR);
let s = NSString::retain(unsafe { msg_send![this, stringValue] }); let s = NSString::retain(unsafe { msg_send![this, stringValue] });
match view.text_should_end_editing(s.to_str()) { Bool::new(view.text_should_end_editing(s.to_str()))
true => YES,
false => NO
}
} }
/// Injects an `NSTextField` subclass. This is used for the default views that don't use delegates - we /// Injects an `NSTextField` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be /// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates. /// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class { pub(crate) fn register_view_class() -> &'static Class {
load_or_register_class("NSTextField", "RSTTextInputField", |decl| unsafe {}) load_or_register_class("NSTextField", "RSTTextInputField", |decl| unsafe {})
} }
/// Injects an `NSTextField` subclass, with some callback and pointer ivars for what we /// Injects an `NSTextField` subclass, with some callback and pointer ivars for what we
/// need to do. /// need to do.
pub(crate) fn register_view_class_with_delegate<T: TextFieldDelegate>(instance: &T) -> *const Class { pub(crate) fn register_view_class_with_delegate<T: TextFieldDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSTextField", instance.subclass_name(), |decl| unsafe { load_or_register_class("NSTextField", instance.subclass_name(), |decl| unsafe {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't // A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move. // move.
decl.add_ivar::<usize>(TEXTFIELD_DELEGATE_PTR); decl.add_ivar::<usize>(TEXTFIELD_DELEGATE_PTR);
decl.add_method( decl.add_method(sel!(textDidEndEditing:), text_did_end_editing::<T> as extern "C" fn(_, _, _));
sel!(textDidEndEditing:),
text_did_end_editing::<T> as extern "C" fn(&mut Object, _, _)
);
decl.add_method( decl.add_method(
sel!(textDidBeginEditing:), sel!(textDidBeginEditing:),
text_did_begin_editing::<T> as extern "C" fn(&mut Object, _, _) text_did_begin_editing::<T> as extern "C" fn(_, _, _)
); );
decl.add_method(sel!(textDidChange:), text_did_change::<T> as extern "C" fn(&mut Object, _, _)); decl.add_method(sel!(textDidChange:), text_did_change::<T> as extern "C" fn(_, _, _));
decl.add_method( decl.add_method(
sel!(textShouldBeginEditing:), sel!(textShouldBeginEditing:),
text_should_begin_editing::<T> as extern "C" fn(&mut Object, Sel, id) -> BOOL text_should_begin_editing::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(textShouldEndEditing:), sel!(textShouldEndEditing:),
text_should_end_editing::<T> as extern "C" fn(&mut Object, Sel, id) -> BOOL text_should_end_editing::<T> as extern "C" fn(_, _, _) -> _
); );
}) })
} }

View file

@ -43,9 +43,11 @@
//! //!
//! For more information on Autolayout, view the module or check out the examples folder. //! For more information on Autolayout, view the module or check out the examples folder.
use core_foundation::base::TCFType;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use objc_id::ShareId;
use crate::color::Color; use crate::color::Color;
use crate::control::Control; use crate::control::Control;
@ -76,7 +78,7 @@ pub use traits::TextFieldDelegate;
pub(crate) static TEXTFIELD_DELEGATE_PTR: &str = "rstTextFieldDelegatePtr"; pub(crate) static TEXTFIELD_DELEGATE_PTR: &str = "rstTextFieldDelegatePtr";
/// A helper method for instantiating view classes and applying default settings to them. /// A helper method for instantiating view classes and applying default settings to them.
fn common_init(class: *const Class) -> id { fn common_init(class: &Class) -> id {
unsafe { unsafe {
let view: id = msg_send![class, new]; let view: id = msg_send![class, new];
@ -306,7 +308,7 @@ impl<T> TextField<T> {
/// Call this to set the background color for the backing layer. /// Call this to set the background color for the backing layer.
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) { pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
self.objc.with_mut(|obj| unsafe { self.objc.with_mut(|obj| unsafe {
let cg = color.as_ref().cg_color(); let cg = color.as_ref().cg_color().as_concrete_TypeRef();
let layer: id = msg_send![obj, layer]; let layer: id = msg_send![obj, layer];
let _: () = msg_send![layer, setBackgroundColor: cg]; let _: () = msg_send![layer, setBackgroundColor: cg];
}); });

View file

@ -1,71 +1,64 @@
use std::sync::Once; use std::sync::Once;
use objc::declare::ClassDecl; use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel, BOOL}; use objc::runtime::{Bool, Class, Object, Sel};
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use objc_id::Id;
use crate::foundation::{id, load_or_register_class, NSString, NSUInteger, NO, YES}; use crate::foundation::{id, load_or_register_class, NSString, NSUInteger};
use crate::input::{TextFieldDelegate, TEXTFIELD_DELEGATE_PTR}; use crate::input::{TextFieldDelegate, TEXTFIELD_DELEGATE_PTR};
use crate::utils::load; use crate::utils::load;
/// Called when editing this text field has ended (e.g. user pressed enter). /// Called when editing this text field has ended (e.g. user pressed enter).
extern "C" fn text_did_end_editing<T: TextFieldDelegate>(this: &mut Object, _: Sel, _info: id) { extern "C" fn text_did_end_editing<T: TextFieldDelegate>(this: &Object, _: Sel, _info: id) {
let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR); let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR);
let s = NSString::retain(unsafe { msg_send![this, text] }); let s = NSString::retain(unsafe { msg_send![this, text] });
view.text_did_end_editing(s.to_str()); view.text_did_end_editing(s.to_str());
} }
extern "C" fn text_did_begin_editing<T: TextFieldDelegate>(this: &mut Object, _: Sel, _info: id) { extern "C" fn text_did_begin_editing<T: TextFieldDelegate>(this: &Object, _: Sel, _info: id) {
let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR); let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR);
let s = NSString::retain(unsafe { msg_send![this, text] }); let s = NSString::retain(unsafe { msg_send![this, text] });
view.text_did_begin_editing(s.to_str()); view.text_did_begin_editing(s.to_str());
} }
extern "C" fn text_did_change<T: TextFieldDelegate>(this: &mut Object, _: Sel, _info: id) { extern "C" fn text_did_change<T: TextFieldDelegate>(this: &Object, _: Sel, _info: id) {
let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR); let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR);
let s = NSString::retain(unsafe { msg_send![this, text] }); let s = NSString::retain(unsafe { msg_send![this, text] });
view.text_did_change(s.to_str()); view.text_did_change(s.to_str());
} }
extern "C" fn text_should_begin_editing<T: TextFieldDelegate>(this: &mut Object, _: Sel, _info: id) -> BOOL { extern "C" fn text_should_begin_editing<T: TextFieldDelegate>(this: &Object, _: Sel, _info: id) -> Bool {
let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR); let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR);
let s = NSString::retain(unsafe { msg_send![this, text] }); let s = NSString::retain(unsafe { msg_send![this, text] });
match view.text_should_begin_editing(s.to_str()) { Bool::new(view.text_should_begin_editing(s.to_str()))
true => YES,
false => NO
}
} }
extern "C" fn text_should_end_editing<T: TextFieldDelegate>(this: &mut Object, _: Sel, _info: id) -> BOOL { extern "C" fn text_should_end_editing<T: TextFieldDelegate>(this: &Object, _: Sel, _info: id) -> Bool {
let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR); let view = load::<T>(this, TEXTFIELD_DELEGATE_PTR);
let s = NSString::retain(unsafe { msg_send![this, text] }); let s = NSString::retain(unsafe { msg_send![this, text] });
match view.text_should_end_editing(s.to_str()) { Bool::new(view.text_should_end_editing(s.to_str()))
true => YES,
false => NO
}
} }
/// Injects an `UITextField` subclass. This is used for the default views that don't use delegates - we /// Injects an `UITextField` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be /// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates. /// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class { pub(crate) fn register_view_class() -> &'static Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class; static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new(); static INIT: Once = Once::new();
INIT.call_once(|| unsafe { INIT.call_once(|| unsafe {
let superclass = class!(UITextField); let superclass = class!(UITextField);
let decl = ClassDecl::new("RSTTextInputField", superclass).unwrap(); let decl = ClassDecl::new("RSTTextInputField", superclass).unwrap();
VIEW_CLASS = decl.register(); VIEW_CLASS = Some(decl.register());
}); });
unsafe { VIEW_CLASS } unsafe { VIEW_CLASS.unwrap() }
} }
/// Injects an `UITextField` subclass, with some callback and pointer ivars for what we /// Injects an `UITextField` subclass, with some callback and pointer ivars for what we
/// need to do. /// need to do.
pub(crate) fn register_view_class_with_delegate<T: TextFieldDelegate>(instance: &T) -> *const Class { pub(crate) fn register_view_class_with_delegate<T: TextFieldDelegate>(instance: &T) -> &'static Class {
load_or_register_class("UITextField", instance.subclass_name(), |decl| unsafe { load_or_register_class("UITextField", instance.subclass_name(), |decl| unsafe {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't // A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move. // move.
@ -73,23 +66,23 @@ pub(crate) fn register_view_class_with_delegate<T: TextFieldDelegate>(instance:
decl.add_method( decl.add_method(
sel!(textFieldDidEndEditing:), sel!(textFieldDidEndEditing:),
text_did_end_editing::<T> as extern "C" fn(&mut Object, _, _) text_did_end_editing::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(textFieldDidBeginEditing:), sel!(textFieldDidBeginEditing:),
text_did_begin_editing::<T> as extern "C" fn(&mut Object, _, _) text_did_begin_editing::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(textFieldDidChangeSelection:), sel!(textFieldDidChangeSelection:),
text_did_change::<T> as extern "C" fn(&mut Object, _, _) text_did_change::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(textFieldShouldBeginEditing:), sel!(textFieldShouldBeginEditing:),
text_should_begin_editing::<T> as extern "C" fn(&mut Object, Sel, id) -> BOOL text_should_begin_editing::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(textFieldShouldEndEditing:), sel!(textFieldShouldEndEditing:),
text_should_end_editing::<T> as extern "C" fn(&mut Object, Sel, id) -> BOOL text_should_end_editing::<T> as extern "C" fn(_, _, _) -> _
); );
}) })
} }

View file

@ -10,9 +10,9 @@
use std::fmt; use std::fmt;
use objc::rc::{Id, Owned, Shared};
use objc::runtime::{Class, Object, Sel}; use objc::runtime::{Class, Object, Sel};
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::foundation::{id, load_or_register_class}; use crate::foundation::{id, load_or_register_class};
use crate::utils::load; use crate::utils::load;
@ -46,7 +46,7 @@ impl fmt::Debug for Action {
#[derive(Debug)] #[derive(Debug)]
pub struct TargetActionHandler { pub struct TargetActionHandler {
action: Box<Action>, action: Box<Action>,
invoker: ShareId<Object> invoker: Id<Object, Shared>
} }
impl TargetActionHandler { impl TargetActionHandler {
@ -56,18 +56,16 @@ impl TargetActionHandler {
let ptr = Box::into_raw(block); let ptr = Box::into_raw(block);
let invoker = unsafe { let invoker = unsafe {
ShareId::from_ptr({ let invoker = msg_send_id![register_invoker_class::<F>(), alloc];
let invoker: id = msg_send![register_invoker_class::<F>(), alloc]; let mut invoker: Id<Object, Owned> = msg_send_id![invoker, init];
let invoker: id = msg_send![invoker, init]; invoker.set_ivar(ACTION_CALLBACK_PTR, ptr as usize);
(&mut *invoker).set_ivar(ACTION_CALLBACK_PTR, ptr as usize); let _: () = msg_send![control, setAction: sel!(perform:)];
let _: () = msg_send![control, setAction: sel!(perform:)]; let _: () = msg_send![control, setTarget: &*invoker];
let _: () = msg_send![control, setTarget: invoker]; invoker.into()
invoker
})
}; };
TargetActionHandler { TargetActionHandler {
invoker: invoker, invoker,
action: unsafe { Box::from_raw(ptr) } action: unsafe { Box::from_raw(ptr) }
} }
} }
@ -91,9 +89,9 @@ extern "C" fn perform<F: Fn(*const Object) + 'static>(this: &mut Object, _: Sel,
/// The `NSButton` owns this object on instantiation, and will release it /// The `NSButton` owns this object on instantiation, and will release it
/// on drop. We handle the heap copy on the Rust side, so setting the block /// on drop. We handle the heap copy on the Rust side, so setting the block
/// is just an ivar. /// is just an ivar.
pub(crate) fn register_invoker_class<F: Fn(*const Object) + 'static>() -> *const Class { pub(crate) fn register_invoker_class<F: Fn(*const Object) + 'static>() -> &'static Class {
load_or_register_class("NSObject", "RSTTargetActionHandler", |decl| unsafe { load_or_register_class("NSObject", "RSTTargetActionHandler", |decl| unsafe {
decl.add_ivar::<usize>(ACTION_CALLBACK_PTR); decl.add_ivar::<usize>(ACTION_CALLBACK_PTR);
decl.add_method(sel!(perform:), perform::<F> as extern "C" fn(&mut Object, _, id)); decl.add_method(sel!(perform:), perform::<F> as extern "C" fn(_, _, _));
}) })
} }

View file

@ -14,7 +14,9 @@
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use objc::{class, msg_send, sel, sel_impl}; use objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, msg_send_id, sel};
use crate::foundation::id; use crate::foundation::id;
use crate::utils::properties::ObjcProperty; use crate::utils::properties::ObjcProperty;
@ -35,30 +37,26 @@ use crate::utils::properties::ObjcProperty;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Layer { pub struct Layer {
/// The underlying layer pointer. /// The underlying layer pointer.
pub objc: ObjcProperty pub objc: Id<Object, Shared>
} }
impl Layer { impl Layer {
/// Creates a new `CALayer` and retains it. /// Creates a new `CALayer` and retains it.
pub fn new() -> Self { pub fn new() -> Self {
Layer { Layer {
objc: ObjcProperty::retain(unsafe { msg_send![class!(CALayer), new] }) objc: unsafe { msg_send_id![class!(CALayer), new] }
} }
} }
/// Wraps an existing (already retained) `CALayer`. /// Wraps an existing `CALayer`.
pub fn wrap(layer: id) -> Self { pub fn from_id(objc: Id<Object, Shared>) -> Self {
Layer { Layer { objc }
objc: ObjcProperty::from_retained(layer)
}
} }
/// Sets the corner radius (for all four corners). /// Sets the corner radius (for all four corners).
/// ///
/// Note that for performance sensitive contexts, you might want to apply a mask instead. /// Note that for performance sensitive contexts, you might want to apply a mask instead.
pub fn set_corner_radius(&self, radius: f64) { pub fn set_corner_radius(&self, radius: f64) {
self.objc.with_mut(|obj| unsafe { let _: () = unsafe { msg_send![&self.objc, setCornerRadius: radius as CGFloat] };
let _: () = msg_send![obj, setCornerRadius: radius as CGFloat];
});
} }
} }

View file

@ -1,19 +1,19 @@
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::foundation::id; use crate::foundation::id;
/// A wrapper for an animation proxy object in Cocoa that supports basic animations. /// A wrapper for an animation proxy object in Cocoa that supports basic animations.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct LayoutConstraintAnimatorProxy(pub ShareId<Object>); pub struct LayoutConstraintAnimatorProxy(pub Id<Object, Shared>);
impl LayoutConstraintAnimatorProxy { impl LayoutConstraintAnimatorProxy {
/// Wraps and returns a proxy for animation of layout constraint values. /// Wraps and returns a proxy for animation of layout constraint values.
pub fn new(proxy: id) -> Self { pub fn new(proxy: id) -> Self {
Self(unsafe { ShareId::from_ptr(msg_send![proxy, animator]) }) Self(unsafe { msg_send_id![proxy, animator] })
} }
/// Sets the constant (usually referred to as `offset` in Cacao) value for the constraint being animated. /// Sets the constant (usually referred to as `offset` in Cacao) value for the constraint being animated.
@ -23,3 +23,7 @@ impl LayoutConstraintAnimatorProxy {
} }
} }
} }
// TODO: Safety
unsafe impl Send for LayoutConstraintAnimatorProxy {}
unsafe impl Sync for LayoutConstraintAnimatorProxy {}

View file

@ -4,9 +4,9 @@
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use objc_id::ShareId;
use crate::foundation::{id, NO, YES}; use crate::foundation::{id, NO, YES};
@ -20,7 +20,7 @@ use super::LayoutConstraintAnimatorProxy;
pub struct LayoutConstraint { pub struct LayoutConstraint {
/// A shared pointer to the underlying view. Provided your view isn't dropped, this will always /// A shared pointer to the underlying view. Provided your view isn't dropped, this will always
/// be valid. /// be valid.
pub constraint: ShareId<Object>, pub constraint: Id<Object, Shared>,
/// The offset used in computing this constraint. /// The offset used in computing this constraint.
pub offset: f64, pub offset: f64,
@ -43,8 +43,7 @@ impl LayoutConstraint {
LayoutConstraint { LayoutConstraint {
#[cfg(all(feature = "appkit", target_os = "macos"))] #[cfg(all(feature = "appkit", target_os = "macos"))]
animator: LayoutConstraintAnimatorProxy::new(object), animator: LayoutConstraintAnimatorProxy::new(object),
constraint: unsafe { Id::retain(object).unwrap() },
constraint: unsafe { ShareId::from_ptr(object) },
offset: 0.0, offset: 0.0,
multiplier: 0.0, multiplier: 0.0,
priority: 0.0 priority: 0.0
@ -94,7 +93,7 @@ impl LayoutConstraint {
/// Call this with your batch of constraints to activate them. /// Call this with your batch of constraints to activate them.
// If you're astute, you'll note that, yes... this is kind of hacking around some // If you're astute, you'll note that, yes... this is kind of hacking around some
// borrowing rules with how objc_id::Id/objc_id::ShareId works. In this case, to // borrowing rules with how objc::rc::{Id, Owned}/objc::rc::{Id, Shared} works. In this case, to
// support the way autolayout constraints work over in the cocoa runtime, we need to be // support the way autolayout constraints work over in the cocoa runtime, we need to be
// able to clone these and pass them around... while also getting certain references to // able to clone these and pass them around... while also getting certain references to
// them. // them.

View file

@ -1,8 +1,8 @@
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::foundation::{id, nil, NSInteger}; use crate::foundation::{id, nil, NSInteger};
use crate::layout::constraint::LayoutConstraint; use crate::layout::constraint::LayoutConstraint;
@ -12,7 +12,7 @@ use super::attributes::{LayoutAttribute, LayoutRelation};
/// A wrapper for `NSLayoutAnchor`. You should never be creating this yourself - it's more of a /// A wrapper for `NSLayoutAnchor`. You should never be creating this yourself - it's more of a
/// factory/helper for creating `LayoutConstraint` objects based on your views. /// factory/helper for creating `LayoutConstraint` objects based on your views.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct LayoutAnchorDimension2(pub Option<ShareId<Object>>); pub struct LayoutAnchorDimension2(pub Option<Id<Object, Shared>>);
/// A wrapper for `NSLayoutAnchorDimension`, which is typically used to handle `width` and `height` /// A wrapper for `NSLayoutAnchorDimension`, which is typically used to handle `width` and `height`
/// values for how a given view should layout. /// values for how a given view should layout.
@ -22,10 +22,10 @@ pub enum LayoutAnchorDimension {
Uninitialized, Uninitialized,
/// Represents a Width anchor. /// Represents a Width anchor.
Width(ShareId<Object>), Width(Id<Object, Shared>),
/// Represents a Height anchor. /// Represents a Height anchor.
Height(ShareId<Object>) Height(Id<Object, Shared>)
} }
impl Default for LayoutAnchorDimension { impl Default for LayoutAnchorDimension {
@ -38,12 +38,12 @@ impl Default for LayoutAnchorDimension {
impl LayoutAnchorDimension { impl LayoutAnchorDimension {
/// Given a view, returns an anchor for the width anchor. /// Given a view, returns an anchor for the width anchor.
pub(crate) fn width(view: id) -> Self { pub(crate) fn width(view: id) -> Self {
Self::Width(unsafe { ShareId::from_ptr(msg_send![view, widthAnchor]) }) Self::Width(unsafe { msg_send_id![view, widthAnchor] })
} }
/// Given a view, returns an anchor for the height anchor. /// Given a view, returns an anchor for the height anchor.
pub(crate) fn height(view: id) -> Self { pub(crate) fn height(view: id) -> Self {
Self::Height(unsafe { ShareId::from_ptr(msg_send![view, heightAnchor]) }) Self::Height(unsafe { msg_send_id![view, heightAnchor] })
} }
/// Return a constraint equal to a constant value. /// Return a constraint equal to a constant value.
@ -51,7 +51,7 @@ impl LayoutAnchorDimension {
if let Self::Width(obj) | Self::Height(obj) = self { if let Self::Width(obj) | Self::Height(obj) = self {
return LayoutConstraint::new(unsafe { return LayoutConstraint::new(unsafe {
let value = constant as CGFloat; let value = constant as CGFloat;
msg_send![*obj, constraintEqualToConstant: value] msg_send![obj, constraintEqualToConstant: value]
}); });
} }
@ -63,7 +63,7 @@ impl LayoutAnchorDimension {
if let Self::Width(obj) | Self::Height(obj) = self { if let Self::Width(obj) | Self::Height(obj) = self {
return LayoutConstraint::new(unsafe { return LayoutConstraint::new(unsafe {
let value = constant as CGFloat; let value = constant as CGFloat;
msg_send![*obj, constraintGreaterThanOrEqualToConstant: value] msg_send![obj, constraintGreaterThanOrEqualToConstant: value]
}); });
} }
@ -75,7 +75,7 @@ impl LayoutAnchorDimension {
if let Self::Width(obj) | Self::Height(obj) = self { if let Self::Width(obj) | Self::Height(obj) = self {
return LayoutConstraint::new(unsafe { return LayoutConstraint::new(unsafe {
let value = constant as CGFloat; let value = constant as CGFloat;
msg_send![*obj, constraintLessThanOrEqualToConstant: value] msg_send![obj, constraintLessThanOrEqualToConstant: value]
}); });
} }
@ -87,7 +87,7 @@ impl LayoutAnchorDimension {
/// wrong. /// wrong.
fn constraint_with<F>(&self, anchor_to: &LayoutAnchorDimension, handler: F) -> LayoutConstraint fn constraint_with<F>(&self, anchor_to: &LayoutAnchorDimension, handler: F) -> LayoutConstraint
where where
F: Fn(&ShareId<Object>, &ShareId<Object>) -> id F: Fn(&Id<Object, Shared>, &Id<Object, Shared>) -> id
{ {
match (self, anchor_to) { match (self, anchor_to) {
(Self::Width(from), Self::Width(to)) (Self::Width(from), Self::Width(to))
@ -112,21 +112,21 @@ impl LayoutAnchorDimension {
/// Return a constraint equal to another dimension anchor. /// Return a constraint equal to another dimension anchor.
pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorDimension) -> LayoutConstraint { pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorDimension) -> LayoutConstraint {
self.constraint_with(anchor_to, |from, to| unsafe { self.constraint_with(anchor_to, |from, to| unsafe {
msg_send![*from, constraintEqualToAnchor:&**to] msg_send![from, constraintEqualToAnchor:&**to]
}) })
} }
/// Return a constraint greater than or equal to another dimension anchor. /// Return a constraint greater than or equal to another dimension anchor.
pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorDimension) -> LayoutConstraint { pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorDimension) -> LayoutConstraint {
self.constraint_with(anchor_to, |from, to| unsafe { self.constraint_with(anchor_to, |from, to| unsafe {
msg_send![*from, constraintGreaterThanOrEqualToAnchor:&**to] msg_send![from, constraintGreaterThanOrEqualToAnchor:&**to]
}) })
} }
/// Return a constraint less than or equal to another dimension anchor. /// Return a constraint less than or equal to another dimension anchor.
pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorDimension) -> LayoutConstraint { pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorDimension) -> LayoutConstraint {
self.constraint_with(anchor_to, |from, to| unsafe { self.constraint_with(anchor_to, |from, to| unsafe {
msg_send![*from, constraintLessThanOrEqualToAnchor:&**to] msg_send![from, constraintLessThanOrEqualToAnchor:&**to]
}) })
} }
} }

View file

@ -1,6 +1,6 @@
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::foundation::id; use crate::foundation::id;
use crate::layout::constraint::LayoutConstraint; use crate::layout::constraint::LayoutConstraint;
@ -16,19 +16,19 @@ pub enum LayoutAnchorX {
Uninitialized, Uninitialized,
/// Represents a leading anchor; side depends on system orientation. /// Represents a leading anchor; side depends on system orientation.
Leading(ShareId<Object>), Leading(Id<Object, Shared>),
/// Represents a left anchor. /// Represents a left anchor.
Left(ShareId<Object>), Left(Id<Object, Shared>),
/// Represents a trailing anchor; side depends on system orientation. /// Represents a trailing anchor; side depends on system orientation.
Trailing(ShareId<Object>), Trailing(Id<Object, Shared>),
/// Represents a right anchor. /// Represents a right anchor.
Right(ShareId<Object>), Right(Id<Object, Shared>),
/// Represents a center anchor on the X axis. /// Represents a center anchor on the X axis.
Center(ShareId<Object>) Center(Id<Object, Shared>)
} }
impl Default for LayoutAnchorX { impl Default for LayoutAnchorX {
@ -41,27 +41,27 @@ impl Default for LayoutAnchorX {
impl LayoutAnchorX { impl LayoutAnchorX {
/// Given a view, returns an anchor for the leading anchor. /// Given a view, returns an anchor for the leading anchor.
pub(crate) fn leading(view: id) -> Self { pub(crate) fn leading(view: id) -> Self {
Self::Leading(unsafe { ShareId::from_ptr(msg_send![view, leadingAnchor]) }) Self::Leading(unsafe { msg_send_id![view, leadingAnchor] })
} }
/// Given a view, returns an anchor for the left anchor. /// Given a view, returns an anchor for the left anchor.
pub(crate) fn left(view: id) -> Self { pub(crate) fn left(view: id) -> Self {
Self::Left(unsafe { ShareId::from_ptr(msg_send![view, leftAnchor]) }) Self::Left(unsafe { msg_send_id![view, leftAnchor] })
} }
/// Given a view, returns an anchor for the trailing anchor. /// Given a view, returns an anchor for the trailing anchor.
pub(crate) fn trailing(view: id) -> Self { pub(crate) fn trailing(view: id) -> Self {
Self::Trailing(unsafe { ShareId::from_ptr(msg_send![view, trailingAnchor]) }) Self::Trailing(unsafe { msg_send_id![view, trailingAnchor] })
} }
/// Given a view, returns an anchor for the right anchor. /// Given a view, returns an anchor for the right anchor.
pub(crate) fn right(view: id) -> Self { pub(crate) fn right(view: id) -> Self {
Self::Right(unsafe { ShareId::from_ptr(msg_send![view, rightAnchor]) }) Self::Right(unsafe { msg_send_id![view, rightAnchor] })
} }
/// Given a view, returns an anchor for the right anchor. /// Given a view, returns an anchor for the right anchor.
pub(crate) fn center(view: id) -> Self { pub(crate) fn center(view: id) -> Self {
Self::Center(unsafe { ShareId::from_ptr(msg_send![view, centerXAnchor]) }) Self::Center(unsafe { msg_send_id![view, centerXAnchor] })
} }
/// Boilerplate for handling constraint construction and panic'ing with some more helpful /// Boilerplate for handling constraint construction and panic'ing with some more helpful
@ -69,7 +69,7 @@ impl LayoutAnchorX {
/// wrong. /// wrong.
fn constraint_with<F>(&self, anchor_to: &LayoutAnchorX, handler: F) -> LayoutConstraint fn constraint_with<F>(&self, anchor_to: &LayoutAnchorX, handler: F) -> LayoutConstraint
where where
F: Fn(&ShareId<Object>, &ShareId<Object>) -> id F: Fn(&Id<Object, Shared>, &Id<Object, Shared>) -> id
{ {
match (self, anchor_to) { match (self, anchor_to) {
// The anchors that can connect to each other. These blocks could be condensed, but are // The anchors that can connect to each other. These blocks could be condensed, but are
@ -160,21 +160,21 @@ impl LayoutAnchorX {
/// Return a constraint equal to another horizontal anchor. /// Return a constraint equal to another horizontal anchor.
pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint { pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint {
self.constraint_with(anchor_to, |from, to| unsafe { self.constraint_with(anchor_to, |from, to| unsafe {
msg_send![*from, constraintEqualToAnchor:&**to] msg_send![from, constraintEqualToAnchor:&**to]
}) })
} }
/// Return a constraint greater than or equal to another horizontal anchor. /// Return a constraint greater than or equal to another horizontal anchor.
pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint { pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint {
self.constraint_with(anchor_to, |from, to| unsafe { self.constraint_with(anchor_to, |from, to| unsafe {
msg_send![*from, constraintGreaterThanOrEqualToAnchor:&**to] msg_send![from, constraintGreaterThanOrEqualToAnchor:&**to]
}) })
} }
/// Return a constraint less than or equal to another horizontal anchor. /// Return a constraint less than or equal to another horizontal anchor.
pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint { pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint {
self.constraint_with(anchor_to, |from, to| unsafe { self.constraint_with(anchor_to, |from, to| unsafe {
msg_send![*from, constraintLessThanOrEqualToAnchor:&**to] msg_send![from, constraintLessThanOrEqualToAnchor:&**to]
}) })
} }
} }

View file

@ -1,4 +1,4 @@
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, sel};
use crate::foundation::id; use crate::foundation::id;
use crate::layout::{LayoutAnchorDimension, LayoutAnchorX, LayoutAnchorY}; use crate::layout::{LayoutAnchorDimension, LayoutAnchorX, LayoutAnchorY};

View file

@ -4,9 +4,9 @@
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use core_graphics::geometry::{CGPoint, CGRect, CGSize}; use core_graphics::geometry::{CGPoint, CGRect, CGSize};
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, sel};
use objc_id::ShareId;
use crate::foundation::{id, nil, to_bool, NSArray, NSString, NO, YES}; use crate::foundation::{id, nil, to_bool, NSArray, NSString, NO, YES};
use crate::geometry::Rect; use crate::geometry::Rect;
@ -112,7 +112,8 @@ pub trait Layout: ObjcAccess {
.into_iter() .into_iter()
.map(|t| { .map(|t| {
let x: NSString = (*t).into(); let x: NSString = (*t).into();
x.into() // FIXME: We shouldn't use autorelease here
Id::autorelease_return(x.objc)
}) })
.collect::<Vec<id>>() .collect::<Vec<id>>()
.into(); .into();

View file

@ -1,6 +1,6 @@
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::foundation::id; use crate::foundation::id;
use crate::layout::constraint::LayoutConstraint; use crate::layout::constraint::LayoutConstraint;
@ -13,13 +13,13 @@ pub enum LayoutAnchorY {
Uninitialized, Uninitialized,
/// Represents a top anchor. /// Represents a top anchor.
Top(ShareId<Object>), Top(Id<Object, Shared>),
/// Represents a bottom anchor. /// Represents a bottom anchor.
Bottom(ShareId<Object>), Bottom(Id<Object, Shared>),
/// Represents a center anchor for the Y axis. /// Represents a center anchor for the Y axis.
Center(ShareId<Object>) Center(Id<Object, Shared>)
} }
impl Default for LayoutAnchorY { impl Default for LayoutAnchorY {
@ -31,17 +31,17 @@ impl Default for LayoutAnchorY {
impl LayoutAnchorY { impl LayoutAnchorY {
/// Given a view, returns an anchor for the top anchor. /// Given a view, returns an anchor for the top anchor.
pub(crate) fn top(view: id) -> Self { pub(crate) fn top(view: id) -> Self {
Self::Top(unsafe { ShareId::from_ptr(msg_send![view, topAnchor]) }) Self::Top(unsafe { msg_send_id![view, topAnchor] })
} }
/// Given a view, returns an anchor for the bottom anchor. /// Given a view, returns an anchor for the bottom anchor.
pub(crate) fn bottom(view: id) -> Self { pub(crate) fn bottom(view: id) -> Self {
Self::Bottom(unsafe { ShareId::from_ptr(msg_send![view, bottomAnchor]) }) Self::Bottom(unsafe { msg_send_id![view, bottomAnchor] })
} }
/// Given a view, returns an anchor for the center Y anchor. /// Given a view, returns an anchor for the center Y anchor.
pub(crate) fn center(view: id) -> Self { pub(crate) fn center(view: id) -> Self {
Self::Center(unsafe { ShareId::from_ptr(msg_send![view, centerYAnchor]) }) Self::Center(unsafe { msg_send_id![view, centerYAnchor] })
} }
/// Boilerplate for handling constraint construction and panic'ing with some more helpful /// Boilerplate for handling constraint construction and panic'ing with some more helpful
@ -49,7 +49,7 @@ impl LayoutAnchorY {
/// wrong. /// wrong.
fn constraint_with<F>(&self, anchor_to: &LayoutAnchorY, handler: F) -> LayoutConstraint fn constraint_with<F>(&self, anchor_to: &LayoutAnchorY, handler: F) -> LayoutConstraint
where where
F: Fn(&ShareId<Object>, &ShareId<Object>) -> id F: Fn(&Id<Object, Shared>, &Id<Object, Shared>) -> id
{ {
match (self, anchor_to) { match (self, anchor_to) {
(Self::Top(from), Self::Top(to)) (Self::Top(from), Self::Top(to))
@ -79,21 +79,21 @@ impl LayoutAnchorY {
/// Return a constraint equal to another vertical anchor. /// Return a constraint equal to another vertical anchor.
pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorY) -> LayoutConstraint { pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorY) -> LayoutConstraint {
self.constraint_with(anchor_to, |from, to| unsafe { self.constraint_with(anchor_to, |from, to| unsafe {
msg_send![*from, constraintEqualToAnchor:&**to] msg_send![from, constraintEqualToAnchor:&**to]
}) })
} }
/// Return a constraint greater than or equal to another vertical anchor. /// Return a constraint greater than or equal to another vertical anchor.
pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorY) -> LayoutConstraint { pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorY) -> LayoutConstraint {
self.constraint_with(anchor_to, |from, to| unsafe { self.constraint_with(anchor_to, |from, to| unsafe {
msg_send![*from, constraintGreaterThanOrEqualToAnchor:&**to] msg_send![from, constraintGreaterThanOrEqualToAnchor:&**to]
}) })
} }
/// Return a constraint less than or equal to another vertical anchor. /// Return a constraint less than or equal to another vertical anchor.
pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorY) -> LayoutConstraint { pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorY) -> LayoutConstraint {
self.constraint_with(anchor_to, |from, to| unsafe { self.constraint_with(anchor_to, |from, to| unsafe {
msg_send![*from, constraintLessThanOrEqualToAnchor:&**to] msg_send![from, constraintLessThanOrEqualToAnchor:&**to]
}) })
} }
} }

View file

@ -3,6 +3,8 @@
#![cfg_attr(debug_assertions, allow(dead_code, unused_imports))] #![cfg_attr(debug_assertions, allow(dead_code, unused_imports))]
#![cfg_attr(docsrs, deny(rustdoc::broken_intra_doc_links))] #![cfg_attr(docsrs, deny(rustdoc::broken_intra_doc_links))]
#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(docsrs, feature(doc_cfg))]
// Temporary!
#![allow(deprecated)]
// Copyright 2019+, the Cacao developers. // Copyright 2019+, the Cacao developers.
// See the COPYRIGHT file at the top-level directory of this distribution. // See the COPYRIGHT file at the top-level directory of this distribution.
// Dual-licensed under an MIT/MPL-2.0 license, see the LICENSE files in this repository. // Dual-licensed under an MIT/MPL-2.0 license, see the LICENSE files in this repository.

View file

@ -1,6 +1,6 @@
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use block::ConcreteBlock; use block::ConcreteBlock;
@ -39,7 +39,7 @@ impl From<RowActionStyle> for NSUInteger {
/// on a ListViewRow. You return this from the appropriate delegate method, /// on a ListViewRow. You return this from the appropriate delegate method,
/// and the system will handle displaying the necessary pieces for you. /// and the system will handle displaying the necessary pieces for you.
#[derive(Debug)] #[derive(Debug)]
pub struct RowAction(pub Id<Object>); pub struct RowAction(pub Id<Object, Owned>);
impl RowAction { impl RowAction {
/// Creates and returns a new `RowAction`. You'd use this handler to /// Creates and returns a new `RowAction`. You'd use this handler to
@ -56,7 +56,7 @@ impl RowAction {
{ {
let title = NSString::new(title); let title = NSString::new(title);
let block = ConcreteBlock::new(move |action: id, row: NSUInteger| { let block = ConcreteBlock::new(move |action: id, row: NSUInteger| {
let action = RowAction(unsafe { Id::from_ptr(action) }); let action = RowAction(unsafe { Id::retain(action).unwrap() });
handler(action, row as usize); handler(action, row as usize);
}); });
@ -65,10 +65,12 @@ impl RowAction {
RowAction(unsafe { RowAction(unsafe {
let cls = class!(NSTableViewRowAction); let cls = class!(NSTableViewRowAction);
Id::from_ptr(msg_send![cls, rowActionWithStyle:style msg_send_id![
title:&*title cls,
handler:block rowActionWithStyle: style,
]) title: &*title,
handler: &*block,
]
}) })
} }

View file

@ -7,13 +7,13 @@
//! for in the modern era. It also implements a few helpers for things like setting a background //! for in the modern era. It also implements a few helpers for things like setting a background
//! color, and enforcing layer backing by default. //! color, and enforcing layer backing by default.
use objc::runtime::{Class, Object, Sel, BOOL}; use objc::rc::{Id, Owned};
use objc::{msg_send, sel, sel_impl}; use objc::runtime::{Bool, Class, Object, Sel};
use objc_id::Id; use objc::{msg_send, sel};
use crate::appkit::menu::Menu; use crate::appkit::menu::Menu;
use crate::dragdrop::DragInfo; use crate::dragdrop::DragInfo;
use crate::foundation::{id, load_or_register_class, NSArray, NSInteger, NSUInteger, NO, YES}; use crate::foundation::{id, load_or_register_class, NSArray, NSInteger, NSUInteger};
use crate::listview::{ListViewDelegate, RowEdge, LISTVIEW_DELEGATE_PTR}; use crate::listview::{ListViewDelegate, RowEdge, LISTVIEW_DELEGATE_PTR};
use crate::utils::load; use crate::utils::load;
@ -81,10 +81,10 @@ extern "C" fn select_row<T: ListViewDelegate>(
_: Sel, _: Sel,
_table_view: id, _table_view: id,
item: NSInteger item: NSInteger
) -> BOOL { ) -> Bool {
let view = load::<T>(this, LISTVIEW_DELEGATE_PTR); let view = load::<T>(this, LISTVIEW_DELEGATE_PTR);
view.item_selected(item as usize); view.item_selected(item as usize);
YES Bool::YES
}*/ }*/
extern "C" fn selection_did_change<T: ListViewDelegate>(this: &Object, _: Sel, notification: id) { extern "C" fn selection_did_change<T: ListViewDelegate>(this: &Object, _: Sel, notification: id) {
@ -122,41 +122,35 @@ extern "C" fn row_actions_for_row<T: ListViewDelegate>(
} }
/// Enforces normalcy, or: a needlessly cruel method in terms of the name. You get the idea though. /// Enforces normalcy, or: a needlessly cruel method in terms of the name. You get the idea though.
extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> BOOL { extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> Bool {
return YES; return Bool::YES;
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn dragging_entered<T: ListViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger { extern "C" fn dragging_entered<T: ListViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = load::<T>(this, LISTVIEW_DELEGATE_PTR); let view = load::<T>(this, LISTVIEW_DELEGATE_PTR);
view.dragging_entered(DragInfo { view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}) })
.into() .into()
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn prepare_for_drag_operation<T: ListViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL { extern "C" fn prepare_for_drag_operation<T: ListViewDelegate>(this: &mut Object, _: Sel, info: id) -> Bool {
let view = load::<T>(this, LISTVIEW_DELEGATE_PTR); let view = load::<T>(this, LISTVIEW_DELEGATE_PTR);
match view.prepare_for_drag_operation(DragInfo { Bool::new(view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}) { }))
true => YES,
false => NO
}
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn perform_drag_operation<T: ListViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL { extern "C" fn perform_drag_operation<T: ListViewDelegate>(this: &mut Object, _: Sel, info: id) -> Bool {
let view = load::<T>(this, LISTVIEW_DELEGATE_PTR); let view = load::<T>(this, LISTVIEW_DELEGATE_PTR);
match view.perform_drag_operation(DragInfo { Bool::new(view.perform_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}) { }))
true => YES,
false => NO
}
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
@ -164,7 +158,7 @@ extern "C" fn conclude_drag_operation<T: ListViewDelegate>(this: &mut Object, _:
let view = load::<T>(this, LISTVIEW_DELEGATE_PTR); let view = load::<T>(this, LISTVIEW_DELEGATE_PTR);
view.conclude_drag_operation(DragInfo { view.conclude_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}); });
} }
@ -173,7 +167,7 @@ extern "C" fn dragging_exited<T: ListViewDelegate>(this: &mut Object, _: Sel, in
let view = load::<T>(this, LISTVIEW_DELEGATE_PTR); let view = load::<T>(this, LISTVIEW_DELEGATE_PTR);
view.dragging_exited(DragInfo { view.dragging_exited(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}); });
} }
@ -181,7 +175,7 @@ extern "C" fn dragging_exited<T: ListViewDelegate>(this: &mut Object, _: Sel, in
/// need to do. Note that we treat and constrain this as a one-column "list" view to match /// need to do. Note that we treat and constrain this as a one-column "list" view to match
/// `UITableView` semantics; if `NSTableView`'s multi column behavior is needed, then it can /// `UITableView` semantics; if `NSTableView`'s multi column behavior is needed, then it can
/// be added in. /// be added in.
pub(crate) fn register_listview_class() -> *const Class { pub(crate) fn register_listview_class() -> &'static Class {
load_or_register_class("NSTableView", "RSTListView", |decl| unsafe {}) load_or_register_class("NSTableView", "RSTListView", |decl| unsafe {})
} }
@ -189,62 +183,53 @@ pub(crate) fn register_listview_class() -> *const Class {
/// need to do. Note that we treat and constrain this as a one-column "list" view to match /// need to do. Note that we treat and constrain this as a one-column "list" view to match
/// `UITableView` semantics; if `NSTableView`'s multi column behavior is needed, then it can /// `UITableView` semantics; if `NSTableView`'s multi column behavior is needed, then it can
/// be added in. /// be added in.
pub(crate) fn register_listview_class_with_delegate<T: ListViewDelegate>(instance: &T) -> *const Class { pub(crate) fn register_listview_class_with_delegate<T: ListViewDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSTableView", instance.subclass_name(), |decl| unsafe { load_or_register_class("NSTableView", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(LISTVIEW_DELEGATE_PTR); decl.add_ivar::<usize>(LISTVIEW_DELEGATE_PTR);
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
// Tableview-specific // Tableview-specific
decl.add_method( decl.add_method(
sel!(numberOfRowsInTableView:), sel!(numberOfRowsInTableView:),
number_of_items::<T> as extern "C" fn(&Object, _, id) -> NSInteger number_of_items::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(tableView:willDisplayCell:forTableColumn:row:), sel!(tableView:willDisplayCell:forTableColumn:row:),
will_display_cell::<T> as extern "C" fn(&Object, _, id, id, id, NSInteger) will_display_cell::<T> as extern "C" fn(_, _, _, _, _, _)
); );
decl.add_method( decl.add_method(
sel!(tableView:viewForTableColumn:row:), sel!(tableView:viewForTableColumn:row:),
view_for_column::<T> as extern "C" fn(&Object, _, id, id, NSInteger) -> id view_for_column::<T> as extern "C" fn(_, _, _, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(tableViewSelectionDidChange:), sel!(tableViewSelectionDidChange:),
selection_did_change::<T> as extern "C" fn(&Object, _, id) selection_did_change::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(tableView:rowActionsForRow:edge:), sel!(tableView:rowActionsForRow:edge:),
row_actions_for_row::<T> as extern "C" fn(&Object, _, id, NSInteger, NSInteger) -> id row_actions_for_row::<T> as extern "C" fn(_, _, _, _, _) -> _
); );
// A slot for some menu handling; we just let it be done here for now rather than do the // A slot for some menu handling; we just let it be done here for now rather than do the
// whole delegate run, since things are fast enough nowadays to just replace the entire // whole delegate run, since things are fast enough nowadays to just replace the entire
// menu. // menu.
decl.add_method( decl.add_method(sel!(menuNeedsUpdate:), menu_needs_update::<T> as extern "C" fn(_, _, _));
sel!(menuNeedsUpdate:),
menu_needs_update::<T> as extern "C" fn(&Object, _, id)
);
// Drag and drop operations (e.g, accepting files) // Drag and drop operations (e.g, accepting files)
decl.add_method( decl.add_method(sel!(draggingEntered:), dragging_entered::<T> as extern "C" fn(_, _, _) -> _);
sel!(draggingEntered:),
dragging_entered::<T> as extern "C" fn(&mut Object, _, _) -> NSUInteger
);
decl.add_method( decl.add_method(
sel!(prepareForDragOperation:), sel!(prepareForDragOperation:),
prepare_for_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL prepare_for_drag_operation::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(performDragOperation:), sel!(performDragOperation:),
perform_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL perform_drag_operation::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(concludeDragOperation:), sel!(concludeDragOperation:),
conclude_drag_operation::<T> as extern "C" fn(&mut Object, _, _) conclude_drag_operation::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(draggingExited:),
dragging_exited::<T> as extern "C" fn(&mut Object, _, _)
); );
decl.add_method(sel!(draggingExited:), dragging_exited::<T> as extern "C" fn(_, _, _));
}) })
} }

View file

@ -44,10 +44,12 @@
use std::collections::HashMap; use std::collections::HashMap;
use core_foundation::base::TCFType;
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use objc::rc::{Id, Owned, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::color::Color; use crate::color::Color;
use crate::foundation::{id, nil, NSArray, NSInteger, NSString, NSUInteger, NO, YES}; use crate::foundation::{id, nil, NSArray, NSInteger, NSString, NSUInteger, NO, YES};
@ -98,7 +100,7 @@ use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
/// A helper method for instantiating view classes and applying default settings to them. /// A helper method for instantiating view classes and applying default settings to them.
fn common_init(class: *const Class) -> id { fn common_init(class: &Class) -> id {
unsafe { unsafe {
// Note: we do *not* enable AutoLayout here as we're by default placing this in a scroll // Note: we do *not* enable AutoLayout here as we're by default placing this in a scroll
// view, and we want it to just do its thing. // view, and we want it to just do its thing.
@ -439,7 +441,7 @@ impl<T> ListView<T> {
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) { pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
// @TODO: This is wrong. // @TODO: This is wrong.
self.objc.with_mut(|obj| unsafe { self.objc.with_mut(|obj| unsafe {
let color = color.as_ref().cg_color(); let color = color.as_ref().cg_color().as_concrete_TypeRef();
let layer: id = msg_send![obj, layer]; let layer: id = msg_send![obj, layer];
let _: () = msg_send![layer, setBackgroundColor: color]; let _: () = msg_send![layer, setBackgroundColor: color];
}); });
@ -484,14 +486,14 @@ impl<T> ListView<T> {
/// Select the rows at the specified indexes, optionally adding to any existing selections. /// Select the rows at the specified indexes, optionally adding to any existing selections.
pub fn select_row_indexes(&self, indexes: &[usize], extends_existing: bool) { pub fn select_row_indexes(&self, indexes: &[usize], extends_existing: bool) {
unsafe { unsafe {
let index_set: id = msg_send![class!(NSMutableIndexSet), new]; let mut index_set: Id<Object, Owned> = msg_send_id![class!(NSMutableIndexSet), new];
for index in indexes { for index in indexes {
let _: () = msg_send![index_set, addIndex: index]; let _: () = msg_send![&mut index_set, addIndex: index];
} }
self.objc.with_mut(|obj| { self.objc.with_mut(|obj| {
let _: () = msg_send![obj, selectRowIndexes:index_set byExtendingSelection:match extends_existing { let _: () = msg_send![obj, selectRowIndexes: &*index_set, byExtendingSelection: match extends_existing {
true => YES, true => YES,
false => NO false => NO
}]; }];
@ -567,23 +569,24 @@ impl<T> ListView<T> {
pub fn insert_rows(&self, indexes: &[usize], animation: RowAnimation) { pub fn insert_rows(&self, indexes: &[usize], animation: RowAnimation) {
#[cfg(feature = "appkit")] #[cfg(feature = "appkit")]
unsafe { unsafe {
let index_set: id = msg_send![class!(NSMutableIndexSet), new]; let mut index_set: Id<Object, Owned> = msg_send_id![class!(NSMutableIndexSet), new];
for index in indexes { for index in indexes {
let x: NSUInteger = *index as NSUInteger; let x: NSUInteger = *index as NSUInteger;
let _: () = msg_send![index_set, addIndex: x]; let _: () = msg_send![&mut index_set, addIndex: x];
} }
let animation_options: NSUInteger = animation.into(); let animation_options: NSUInteger = animation.into();
// We need to temporarily retain this; it can drop after the underlying NSTableView // We need to temporarily retain this; it can drop after the underlying NSTableView
// has also retained it. // has also retained it.
let x = ShareId::from_ptr(index_set); let index_set: Id<Object, Shared> = index_set.into();
let x = index_set.clone();
// This is done for a very explicit reason; see the comments on the method itself for // This is done for a very explicit reason; see the comments on the method itself for
// an explanation. // an explanation.
self.hack_avoid_dequeue_loop(|obj| { self.hack_avoid_dequeue_loop(|obj| {
let _: () = msg_send![obj, insertRowsAtIndexes:&*x withAnimation:animation_options]; let _: () = msg_send![obj, insertRowsAtIndexes: &*x, withAnimation: animation_options];
}); });
} }
} }
@ -592,21 +595,21 @@ impl<T> ListView<T> {
pub fn reload_rows(&self, indexes: &[usize]) { pub fn reload_rows(&self, indexes: &[usize]) {
#[cfg(feature = "appkit")] #[cfg(feature = "appkit")]
unsafe { unsafe {
let index_set: id = msg_send![class!(NSMutableIndexSet), new]; let mut index_set: Id<Object, Owned> = msg_send_id![class!(NSMutableIndexSet), new];
for index in indexes { for index in indexes {
let x: NSUInteger = *index as NSUInteger; let x: NSUInteger = *index as NSUInteger;
let _: () = msg_send![index_set, addIndex: x]; let _: () = msg_send![&mut index_set, addIndex: x];
} }
let x = ShareId::from_ptr(index_set); let index_set: Id<Object, Shared> = index_set.into();
let x = index_set.clone();
let ye: id = msg_send![class!(NSIndexSet), indexSetWithIndex:0]; let y: Id<Object, Shared> = msg_send_id![class!(NSIndexSet), indexSetWithIndex:0];
let y = ShareId::from_ptr(ye);
// Must use `get` to avoid a double lock. // Must use `get` to avoid a double lock.
self.objc.get(|obj| { self.objc.get(|obj| {
let _: () = msg_send![obj, reloadDataForRowIndexes:&*x columnIndexes:&*y]; let _: () = msg_send![obj, reloadDataForRowIndexes: &*x, columnIndexes: &*y];
}); });
} }
} }
@ -619,20 +622,22 @@ impl<T> ListView<T> {
pub fn remove_rows(&self, indexes: &[usize], animations: RowAnimation) { pub fn remove_rows(&self, indexes: &[usize], animations: RowAnimation) {
#[cfg(feature = "appkit")] #[cfg(feature = "appkit")]
unsafe { unsafe {
let index_set: id = msg_send![class!(NSMutableIndexSet), new]; let mut index_set: Id<Object, Owned> = msg_send_id![class!(NSMutableIndexSet), new];
for index in indexes { for index in indexes {
let x: NSUInteger = *index as NSUInteger; let x: NSUInteger = *index as NSUInteger;
let _: () = msg_send![index_set, addIndex: x]; let _: () = msg_send![&mut index_set, addIndex: x];
} }
let animation_options: NSUInteger = animations.into(); let animation_options: NSUInteger = animations.into();
// We need to temporarily retain this; it can drop after the underlying NSTableView // We need to temporarily retain this; it can drop after the underlying NSTableView
// has also retained it. // has also retained it.
let x = ShareId::from_ptr(index_set); let index_set: Id<Object, Shared> = index_set.into();
let x = index_set.clone();
self.objc.with_mut(|obj| { self.objc.with_mut(|obj| {
let _: () = msg_send![obj, removeRowsAtIndexes:&*x withAnimation:animation_options]; let _: () = msg_send![obj, removeRowsAtIndexes: &*x, withAnimation: animation_options];
}); });
} }
} }

View file

@ -7,51 +7,45 @@
//! for in the modern era. It also implements a few helpers for things like setting a background //! for in the modern era. It also implements a few helpers for things like setting a background
//! color, and enforcing layer backing by default. //! color, and enforcing layer backing by default.
use objc::runtime::{Class, Object, Sel, BOOL}; use objc::rc::{Id, Owned};
use objc::{class, msg_send, sel, sel_impl}; use objc::runtime::{Bool, Class, Object, Sel};
use objc_id::Id; use objc::{class, msg_send, sel};
use crate::dragdrop::DragInfo; use crate::dragdrop::DragInfo;
use crate::foundation::{id, load_or_register_class, nil, NSUInteger, NO, YES}; use crate::foundation::{id, load_or_register_class, nil, NSUInteger};
use crate::listview::row::{ViewDelegate, BACKGROUND_COLOR, LISTVIEW_ROW_DELEGATE_PTR}; use crate::listview::row::{ViewDelegate, BACKGROUND_COLOR, LISTVIEW_ROW_DELEGATE_PTR};
use crate::utils::load; use crate::utils::load;
/// Enforces normalcy, or: a needlessly cruel method in terms of the name. You get the idea though. /// Enforces normalcy, or: a needlessly cruel method in terms of the name. You get the idea though.
extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> BOOL { extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> Bool {
return YES; return Bool::YES;
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger { extern "C" fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR); let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR);
view.dragging_entered(DragInfo { view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}) })
.into() .into()
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn prepare_for_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL { extern "C" fn prepare_for_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> Bool {
let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR); let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR);
match view.prepare_for_drag_operation(DragInfo { Bool::new(view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}) { }))
true => YES,
false => NO
}
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn perform_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL { extern "C" fn perform_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> Bool {
let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR); let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR);
match view.perform_drag_operation(DragInfo { Bool::new(view.perform_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}) { }))
true => YES,
false => NO
}
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
@ -59,7 +53,7 @@ extern "C" fn conclude_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel
let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR); let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR);
view.conclude_drag_operation(DragInfo { view.conclude_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}); });
} }
@ -68,7 +62,7 @@ extern "C" fn dragging_exited<T: ViewDelegate>(this: &mut Object, _: Sel, info:
let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR); let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR);
view.dragging_exited(DragInfo { view.dragging_exited(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}); });
} }
@ -103,47 +97,41 @@ extern "C" fn dealloc<T: ViewDelegate>(this: &Object, _: Sel) {
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we /// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be /// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates. /// used if there's no delegates.
pub(crate) fn register_listview_row_class() -> *const Class { pub(crate) fn register_listview_row_class() -> &'static Class {
load_or_register_class("NSView", "RSTTableViewRow", |decl| unsafe { load_or_register_class("NSView", "RSTTableViewRow", |decl| unsafe {
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
}) })
} }
/// Injects an `NSView` subclass, with some callback and pointer ivars for what we /// Injects an `NSView` subclass, with some callback and pointer ivars for what we
/// need to do. /// need to do.
pub(crate) fn register_listview_row_class_with_delegate<T: ViewDelegate>() -> *const Class { pub(crate) fn register_listview_row_class_with_delegate<T: ViewDelegate>() -> &'static Class {
load_or_register_class("NSView", "RSTableViewRowWithDelegate", |decl| unsafe { load_or_register_class("NSView", "RSTableViewRowWithDelegate", |decl| unsafe {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't // A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move. // move.
decl.add_ivar::<usize>(LISTVIEW_ROW_DELEGATE_PTR); decl.add_ivar::<usize>(LISTVIEW_ROW_DELEGATE_PTR);
decl.add_ivar::<id>(BACKGROUND_COLOR); decl.add_ivar::<id>(BACKGROUND_COLOR);
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(&Object, _)); decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(_, _));
// Drag and drop operations (e.g, accepting files) // Drag and drop operations (e.g, accepting files)
decl.add_method( decl.add_method(sel!(draggingEntered:), dragging_entered::<T> as extern "C" fn(_, _, _) -> _);
sel!(draggingEntered:),
dragging_entered::<T> as extern "C" fn(&mut Object, _, _) -> NSUInteger
);
decl.add_method( decl.add_method(
sel!(prepareForDragOperation:), sel!(prepareForDragOperation:),
prepare_for_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL prepare_for_drag_operation::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(performDragOperation:), sel!(performDragOperation:),
perform_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL perform_drag_operation::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(concludeDragOperation:), sel!(concludeDragOperation:),
conclude_drag_operation::<T> as extern "C" fn(&mut Object, _, _) conclude_drag_operation::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(draggingExited:),
dragging_exited::<T> as extern "C" fn(&mut Object, _, _)
); );
decl.add_method(sel!(draggingExited:), dragging_exited::<T> as extern "C" fn(_, _, _));
// Cleanup // Cleanup
decl.add_method(sel!(dealloc), dealloc::<T> as extern "C" fn(&Object, _)); decl.add_method(sel!(dealloc), dealloc::<T> as extern "C" fn(_, _));
}) })
} }

View file

@ -45,9 +45,9 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use objc::rc::{Id, Owned, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use objc_id::{Id, ShareId};
use crate::color::Color; use crate::color::Color;
use crate::foundation::{id, nil, NSArray, NSString, NO, YES}; use crate::foundation::{id, nil, NSArray, NSString, NO, YES};
@ -77,7 +77,7 @@ pub(crate) static BACKGROUND_COLOR: &str = "cacaoBackgroundColor";
pub(crate) static LISTVIEW_ROW_DELEGATE_PTR: &str = "cacaoListViewRowDelegatePtr"; pub(crate) static LISTVIEW_ROW_DELEGATE_PTR: &str = "cacaoListViewRowDelegatePtr";
/// A helper method for instantiating view classes and applying default settings to them. /// A helper method for instantiating view classes and applying default settings to them.
fn allocate_view(registration_fn: fn() -> *const Class) -> id { fn allocate_view(registration_fn: fn() -> &'static Class) -> id {
unsafe { unsafe {
let view: id = msg_send![registration_fn(), new]; let view: id = msg_send![registration_fn(), new];
@ -442,7 +442,8 @@ impl<T> ListViewRow<T> {
let color: id = color.as_ref().into(); let color: id = color.as_ref().into();
self.objc.with_mut(|obj| unsafe { self.objc.with_mut(|obj| unsafe {
(&mut *obj).set_ivar(BACKGROUND_COLOR, color); // TODO: Fix this unnecessary retain!
(&mut *obj).set_ivar::<id>(BACKGROUND_COLOR, msg_send![color, retain]);
}); });
} }
} }

View file

@ -1,7 +1,7 @@
use objc::declare::ClassDecl; use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel, BOOL}; use objc::runtime::{Class, Object, Sel, BOOL};
use objc::{class, sel, sel_impl}; use objc::{class, sel};
use objc_id::Id; use objc::rc::{Id, Owned};
use crate::dragdrop::DragInfo; use crate::dragdrop::DragInfo;
use crate::foundation::{id, NSUInteger, NO, YES}; use crate::foundation::{id, NSUInteger, NO, YES};
@ -11,13 +11,13 @@ use crate::view::{ViewDelegate, VIEW_DELEGATE_PTR};
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we /// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be /// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates. /// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class { pub(crate) fn register_view_class() -> &'static Class {
load_or_register_class("UIView", "RSTView", |decl| unsafe {}) load_or_register_class("UIView", "RSTView", |decl| unsafe {})
} }
/// Injects an `NSView` subclass, with some callback and pointer ivars for what we /// Injects an `NSView` subclass, with some callback and pointer ivars for what we
/// need to do. /// need to do.
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>() -> *const Class { pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>() -> &'static Class {
load_or_register_class("UIView", "RSTViewWithDelegate", |decl| unsafe { load_or_register_class("UIView", "RSTViewWithDelegate", |decl| unsafe {
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR); decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
}) })

View file

@ -1,28 +1,28 @@
//! A lightweight wrapper over some networking components, like `NSURLRequest` and co. //! A lightweight wrapper over some networking components, like `NSURLRequest` and co.
//! //!
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
/// At the moment, this is mostly used for inspection of objects returned from system /// At the moment, this is mostly used for inspection of objects returned from system
/// calls, as `NSURL` is pervasive in some filesystem references. Over time this may grow to /// calls, as `NSURL` is pervasive in some filesystem references. Over time this may grow to
/// include a proper networking stack, but the expectation for v0.1 is that most apps will want to /// include a proper networking stack, but the expectation for v0.1 is that most apps will want to
/// use their standard Rust networking libraries (however... odd... the async story may be). /// use their standard Rust networking libraries (however... odd... the async story may be).
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, sel};
use objc_id::ShareId;
use crate::foundation::{id, NSString}; use crate::foundation::{id, NSString};
/// A wrapper around `NSURLRequest`. /// A wrapper around `NSURLRequest`.
#[derive(Debug)] #[derive(Debug)]
pub struct URLRequest(ShareId<Object>); pub struct URLRequest(Id<Object, Shared>);
impl URLRequest { impl URLRequest {
/// Wraps and retains an `NSURLRequest`. /// Wraps and retains an `NSURLRequest`.
pub fn with(request: id) -> Self { pub fn with(request: id) -> Self {
URLRequest(unsafe { ShareId::from_ptr(request) }) URLRequest(unsafe { Id::retain(request).unwrap() })
} }
/// Returns the underlying request URL as an owned `String`. /// Returns the underlying request URL as an owned `String`.
pub fn absolute_url(&self) -> String { pub fn absolute_url(&self) -> String {
NSString::from_retained(unsafe { NSString::retain(unsafe {
let url: id = msg_send![&*self.0, URL]; let url: id = msg_send![&*self.0, URL];
msg_send![url, absoluteString] msg_send![url, absoluteString]
}) })
@ -32,7 +32,7 @@ impl URLRequest {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use crate::foundation::{id, NSString}; use crate::foundation::{id, NSString};
use crate::networking::URLRequest; use crate::networking::URLRequest;

View file

@ -16,9 +16,9 @@
//use std::collections::HashMap; //use std::collections::HashMap;
//use lazy_static::lazy_static; //use lazy_static::lazy_static;
//use objc::{class, msg_send, sel, sel_impl}; //use objc::{class, msg_send, msg_send_id, sel};
//use objc::runtime::Object; //use objc::runtime::Object;
//use objc_id::ShareId; //use objc::rc::{Id, Shared};
mod name; mod name;
pub use name::NotificationName; pub use name::NotificationName;
@ -30,7 +30,7 @@ pub use traits::Dispatcher;
pub static ref DefaultNotificationCenter: NotificationCenter = { pub static ref DefaultNotificationCenter: NotificationCenter = {
NotificationCenter { NotificationCenter {
objc: unsafe { objc: unsafe {
ShareId::from_ptr(msg_send![class!(NSNotificationCenter), defaultCenter]) msg_send_id![class!(NSNotificationCenter), defaultCenter]
}, },
subscribers: Mutex::new(HashMap::new()) subscribers: Mutex::new(HashMap::new())
@ -42,7 +42,7 @@ pub use traits::Dispatcher;
// default center; in the future it should aim to support custom variants. // default center; in the future it should aim to support custom variants.
//#[derive(Debug)] //#[derive(Debug)]
//pub struct NotificationCenter { //pub struct NotificationCenter {
// pub objc: ShareId<Object>, // pub objc: Id<Object, Shared>,
//pub subscribers: Mutex<HashMap<String, Vec<Dispatcher>>> //pub subscribers: Mutex<HashMap<String, Vec<Dispatcher>>>
//} //}
@ -52,7 +52,7 @@ pub use traits::Dispatcher;
fn default() -> Self { fn default() -> Self {
NotificationCenter { NotificationCenter {
objc: unsafe { objc: unsafe {
ShareId::from_ptr(msg_send![class!(NSNotificationCenter), defaultCenter]) msg_send_id![class!(NSNotificationCenter), defaultCenter]
} }
} }
} }

View file

@ -15,9 +15,9 @@
use std::path::PathBuf; use std::path::PathBuf;
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::ShareId;
use url::Url; use url::Url;
use crate::error::Error; use crate::error::Error;
@ -28,33 +28,33 @@ pub use types::{PasteboardName, PasteboardType};
/// Represents an `NSPasteboard`, enabling you to handle copy/paste/drag and drop. /// Represents an `NSPasteboard`, enabling you to handle copy/paste/drag and drop.
#[derive(Debug)] #[derive(Debug)]
pub struct Pasteboard(pub ShareId<Object>); pub struct Pasteboard(pub Id<Object, Shared>);
impl Default for Pasteboard { impl Default for Pasteboard {
/// Returns the default system pasteboard (the "general" pasteboard). /// Returns the default system pasteboard (the "general" pasteboard).
fn default() -> Self { fn default() -> Self {
Pasteboard(unsafe { ShareId::from_ptr(msg_send![class!(NSPasteboard), generalPasteboard]) }) Pasteboard(unsafe { msg_send_id![class!(NSPasteboard), generalPasteboard] })
} }
} }
impl Pasteboard { impl Pasteboard {
/// Used internally for wrapping a Pasteboard returned from operations (say, drag and drop). /// Used internally for wrapping a Pasteboard returned from operations (say, drag and drop).
pub(crate) fn with(existing: id) -> Self { pub(crate) fn with(existing: id) -> Self {
Pasteboard(unsafe { ShareId::from_ptr(existing) }) Pasteboard(unsafe { Id::retain(existing).unwrap() })
} }
/// Retrieves the system Pasteboard for the given name/type. /// Retrieves the system Pasteboard for the given name/type.
pub fn named(name: PasteboardName) -> Self { pub fn named(name: PasteboardName) -> Self {
Pasteboard(unsafe { Pasteboard(unsafe {
let name: NSString = name.into(); let name: NSString = name.into();
ShareId::from_ptr(msg_send![class!(NSPasteboard), pasteboardWithName:&*name]) msg_send_id![class!(NSPasteboard), pasteboardWithName:&*name]
}) })
} }
/// Creates and returns a new pasteboard with a name that is guaranteed to be unique with /// Creates and returns a new pasteboard with a name that is guaranteed to be unique with
/// respect to other pasteboards in the system. /// respect to other pasteboards in the system.
pub fn unique() -> Self { pub fn unique() -> Self {
Pasteboard(unsafe { ShareId::from_ptr(msg_send![class!(NSPasteboard), pasteboardWithUniqueName]) }) Pasteboard(unsafe { msg_send_id![class!(NSPasteboard), pasteboardWithUniqueName] })
} }
/// A shorthand helper method for copying some text to the clipboard. /// A shorthand helper method for copying some text to the clipboard.
@ -63,7 +63,7 @@ impl Pasteboard {
let ptype: NSString = PasteboardType::String.into(); let ptype: NSString = PasteboardType::String.into();
unsafe { unsafe {
let _: () = msg_send![&*self.0, setString:&*contents forType:ptype]; let _: () = msg_send![&*self.0, setString: &*contents, forType: &*ptype];
} }
} }
@ -91,7 +91,7 @@ impl Pasteboard {
unsafe { unsafe {
let class: id = msg_send![class!(NSURL), class]; let class: id = msg_send![class!(NSURL), class];
let classes = NSArray::new(&[class]); let classes = NSArray::new(&[class]);
let contents: id = msg_send![&*self.0, readObjectsForClasses:classes options:nil]; let contents: id = msg_send![&*self.0, readObjectsForClasses: &*classes, options: nil];
// This can happen if the Pasteboard server has an error in returning items. // This can happen if the Pasteboard server has an error in returning items.
// In our case, we'll bubble up an error by checking the pasteboard. // In our case, we'll bubble up an error by checking the pasteboard.

View file

@ -17,9 +17,9 @@
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use objc_id::ShareId;
use crate::color::Color; use crate::color::Color;
use crate::foundation::{id, nil, NSUInteger, NO, YES}; use crate::foundation::{id, nil, NSUInteger, NO, YES};

View file

@ -1,9 +1,9 @@
use std::path::Path; use std::path::Path;
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use objc_id::ShareId;
use crate::foundation::{id, NSString, NSUInteger, YES}; use crate::foundation::{id, NSString, NSUInteger, YES};
use crate::utils::CGSize; use crate::utils::CGSize;

View file

@ -1,8 +1,8 @@
use std::path::Path; use std::path::Path;
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::ShareId;
use block::ConcreteBlock; use block::ConcreteBlock;
@ -14,12 +14,12 @@ mod config;
pub use config::{ThumbnailConfig, ThumbnailQuality}; pub use config::{ThumbnailConfig, ThumbnailQuality};
#[derive(Debug)] #[derive(Debug)]
pub struct ThumbnailGenerator(pub ShareId<Object>); pub struct ThumbnailGenerator(pub Id<Object, Shared>);
impl ThumbnailGenerator { impl ThumbnailGenerator {
/// Returns the global shared, wrapped, QLThumbnailGenerator. /// Returns the global shared, wrapped, QLThumbnailGenerator.
pub fn shared() -> Self { pub fn shared() -> Self {
ThumbnailGenerator(unsafe { ShareId::from_ptr(msg_send![class!(QLThumbnailGenerator), sharedGenerator]) }) ThumbnailGenerator(unsafe { msg_send_id![class!(QLThumbnailGenerator), sharedGenerator] })
} }
/// Given a path and config, will generate a preview image, calling back on the provided /// Given a path and config, will generate a preview image, calling back on the provided
@ -48,8 +48,11 @@ impl ThumbnailGenerator {
let request = config.to_request(path); let request = config.to_request(path);
unsafe { unsafe {
let _: () = msg_send![&*self.0, generateRepresentationsForRequest:request let _: () = msg_send![
updateHandler:block]; &*self.0,
generateRepresentationsForRequest: request,
updateHandler: &*block,
];
} }
} }
} }

View file

@ -7,51 +7,45 @@
//! for in the modern era. It also implements a few helpers for things like setting a background //! for in the modern era. It also implements a few helpers for things like setting a background
//! color, and enforcing layer backing by default. //! color, and enforcing layer backing by default.
use objc::runtime::{Class, Object, Sel, BOOL}; use objc::rc::{Id, Owned};
use objc::{sel, sel_impl}; use objc::runtime::{Bool, Class, Object, Sel};
use objc_id::Id; use objc::sel;
use crate::dragdrop::DragInfo; use crate::dragdrop::DragInfo;
use crate::foundation::{id, load_or_register_class, NSUInteger, NO, YES}; use crate::foundation::{id, load_or_register_class, NSUInteger};
use crate::scrollview::{ScrollViewDelegate, SCROLLVIEW_DELEGATE_PTR}; use crate::scrollview::{ScrollViewDelegate, SCROLLVIEW_DELEGATE_PTR};
use crate::utils::load; use crate::utils::load;
/// Enforces normalcy, or: a needlessly cruel method in terms of the name. You get the idea though. /// Enforces normalcy, or: a needlessly cruel method in terms of the name. You get the idea though.
extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> BOOL { extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> Bool {
return YES; return Bool::YES;
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn dragging_entered<T: ScrollViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger { extern "C" fn dragging_entered<T: ScrollViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR); let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR);
view.dragging_entered(DragInfo { view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}) })
.into() .into()
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn prepare_for_drag_operation<T: ScrollViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL { extern "C" fn prepare_for_drag_operation<T: ScrollViewDelegate>(this: &mut Object, _: Sel, info: id) -> Bool {
let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR); let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR);
match view.prepare_for_drag_operation(DragInfo { Bool::new(view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}) { }))
true => YES,
false => NO
}
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn perform_drag_operation<T: ScrollViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL { extern "C" fn perform_drag_operation<T: ScrollViewDelegate>(this: &mut Object, _: Sel, info: id) -> Bool {
let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR); let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR);
match view.perform_drag_operation(DragInfo { Bool::new(view.perform_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}) { }))
true => YES,
false => NO
}
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
@ -59,7 +53,7 @@ extern "C" fn conclude_drag_operation<T: ScrollViewDelegate>(this: &mut Object,
let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR); let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR);
view.conclude_drag_operation(DragInfo { view.conclude_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}); });
} }
@ -68,45 +62,38 @@ extern "C" fn dragging_exited<T: ScrollViewDelegate>(this: &mut Object, _: Sel,
let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR); let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR);
view.dragging_exited(DragInfo { view.dragging_exited(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}); });
} }
/// Injects an `NSScrollView` subclass. /// Injects an `NSScrollView` subclass.
pub(crate) fn register_scrollview_class() -> *const Class { pub(crate) fn register_scrollview_class() -> &'static Class {
load_or_register_class("NSScrollView", "RSTScrollView", |decl| unsafe {}) load_or_register_class("NSScrollView", "RSTScrollView", |decl| unsafe {})
} }
/// Injects an `NSView` subclass, with some callback and pointer ivars for what we /// Injects an `NSView` subclass, with some callback and pointer ivars for what we
/// need to do. /// need to do.
pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -> *const Class { pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -> &'static Class {
load_or_register_class("NSScrollView", "RSTScrollViewWithDelegate", |decl| unsafe { load_or_register_class("NSScrollView", "RSTScrollViewWithDelegate", |decl| unsafe {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't // A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move. // move.
decl.add_ivar::<usize>(SCROLLVIEW_DELEGATE_PTR); decl.add_ivar::<usize>(SCROLLVIEW_DELEGATE_PTR);
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
// Drag and drop operations (e.g, accepting files) // Drag and drop operations (e.g, accepting files)
decl.add_method( decl.add_method(sel!(draggingEntered:), dragging_entered::<T> as extern "C" fn(_, _, _) -> _);
sel!(draggingEntered:),
dragging_entered::<T> as extern "C" fn(&mut Object, _, _) -> NSUInteger
);
decl.add_method( decl.add_method(
sel!(prepareForDragOperation:), sel!(prepareForDragOperation:),
prepare_for_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL prepare_for_drag_operation::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(performDragOperation:), sel!(performDragOperation:),
perform_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL perform_drag_operation::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(concludeDragOperation:), sel!(concludeDragOperation:),
conclude_drag_operation::<T> as extern "C" fn(&mut Object, _, _) conclude_drag_operation::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(draggingExited:),
dragging_exited::<T> as extern "C" fn(&mut Object, _, _)
); );
}) })
} }

View file

@ -42,9 +42,11 @@
//! //!
//! For more information on Autolayout, view the module or check out the examples folder. //! For more information on Autolayout, view the module or check out the examples folder.
use core_foundation::base::TCFType;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, sel};
use objc_id::ShareId;
use crate::color::Color; use crate::color::Color;
use crate::foundation::{id, nil, NSArray, NSString, NO, YES}; use crate::foundation::{id, nil, NSArray, NSString, NO, YES};
@ -73,7 +75,7 @@ pub use traits::ScrollViewDelegate;
pub(crate) static SCROLLVIEW_DELEGATE_PTR: &str = "rstScrollViewDelegatePtr"; pub(crate) static SCROLLVIEW_DELEGATE_PTR: &str = "rstScrollViewDelegatePtr";
/// A helper method for instantiating view classes and applying default settings to them. /// A helper method for instantiating view classes and applying default settings to them.
fn allocate_view(registration_fn: fn() -> *const Class) -> id { fn allocate_view(registration_fn: fn() -> &'static Class) -> id {
unsafe { unsafe {
let view: id = msg_send![registration_fn(), new]; let view: id = msg_send![registration_fn(), new];
@ -296,7 +298,7 @@ impl<T> ScrollView<T> {
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) { pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
// @TODO: This is wrong. // @TODO: This is wrong.
self.objc.with_mut(|obj| unsafe { self.objc.with_mut(|obj| unsafe {
let color = color.as_ref().cg_color(); let color = color.as_ref().cg_color().as_concrete_TypeRef();
let layer: id = msg_send![obj, layer]; let layer: id = msg_send![obj, layer];
let _: () = msg_send![layer, setBackgroundColor: color]; let _: () = msg_send![layer, setBackgroundColor: color];
}); });

View file

@ -10,17 +10,16 @@
use std::sync::Once; use std::sync::Once;
use objc::declare::ClassDecl; use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel, BOOL}; use objc::runtime::{Bool, Class, Object, Sel};
use objc::{class, sel, sel_impl}; use objc::{class, sel};
use objc_id::Id;
use crate::foundation::{id, NSUInteger, NO, YES}; use crate::foundation::{id, NSUInteger};
use crate::scrollview::{ScrollViewDelegate, SCROLLVIEW_DELEGATE_PTR}; use crate::scrollview::{ScrollViewDelegate, SCROLLVIEW_DELEGATE_PTR};
use crate::utils::load; use crate::utils::load;
/// Enforces normalcy, or: a needlessly cruel method in terms of the name. You get the idea though. /// Enforces normalcy, or: a needlessly cruel method in terms of the name. You get the idea though.
extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> BOOL { extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> Bool {
return YES; return Bool::YES;
} }
/* /*
@ -35,27 +34,21 @@ extern "C" fn dragging_entered<T: ScrollViewDelegate>(this: &mut Object, _: Sel,
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn prepare_for_drag_operation<T: ScrollViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL { extern "C" fn prepare_for_drag_operation<T: ScrollViewDelegate>(this: &mut Object, _: Sel, info: id) -> Bool {
let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR); let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR);
match view.prepare_for_drag_operation(DragInfo { Bool::new(view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::from_ptr(info) }
}) { }))
true => YES,
false => NO
}
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn perform_drag_operation<T: ScrollViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL { extern "C" fn perform_drag_operation<T: ScrollViewDelegate>(this: &mut Object, _: Sel, info: id) -> Bool {
let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR); let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR);
match view.perform_drag_operation(DragInfo { Bool::new(view.perform_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::from_ptr(info) }
}) { }))
true => YES,
false => NO
}
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
@ -78,23 +71,23 @@ extern "C" fn dragging_exited<T: ScrollViewDelegate>(this: &mut Object, _: Sel,
*/ */
/// Injects an `UIScrollView` subclass. /// Injects an `UIScrollView` subclass.
pub(crate) fn register_scrollview_class() -> *const Class { pub(crate) fn register_scrollview_class() -> &'static Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class; static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new(); static INIT: Once = Once::new();
INIT.call_once(|| unsafe { INIT.call_once(|| unsafe {
let superclass = class!(UIScrollView); let superclass = class!(UIScrollView);
let decl = ClassDecl::new("RSTScrollView", superclass).unwrap(); let decl = ClassDecl::new("RSTScrollView", superclass).unwrap();
VIEW_CLASS = decl.register(); VIEW_CLASS = Some(decl.register());
}); });
unsafe { VIEW_CLASS } unsafe { VIEW_CLASS.unwrap() }
} }
/// Injects an `NSView` subclass, with some callback and pointer ivars for what we /// Injects an `NSView` subclass, with some callback and pointer ivars for what we
/// need to do. /// need to do.
pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -> *const Class { pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -> &'static Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class; static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new(); static INIT: Once = Once::new();
INIT.call_once(|| unsafe { INIT.call_once(|| unsafe {
@ -105,34 +98,34 @@ pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -
// move. // move.
decl.add_ivar::<usize>(SCROLLVIEW_DELEGATE_PTR); decl.add_ivar::<usize>(SCROLLVIEW_DELEGATE_PTR);
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
/* /*
// Drag and drop operations (e.g, accepting files) // Drag and drop operations (e.g, accepting files)
decl.add_method( decl.add_method(
sel!(draggingEntered:), sel!(draggingEntered:),
dragging_entered::<T> as extern "C" fn(&mut Object, _, _) -> NSUInteger dragging_entered::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(prepareForDragOperation:), sel!(prepareForDragOperation:),
prepare_for_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL prepare_for_drag_operation::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(performDragOperation:), sel!(performDragOperation:),
perform_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL perform_drag_operation::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(concludeDragOperation:), sel!(concludeDragOperation:),
conclude_drag_operation::<T> as extern "C" fn(&mut Object, _, _) conclude_drag_operation::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(
sel!(draggingExited:), sel!(draggingExited:),
dragging_exited::<T> as extern "C" fn(&mut Object, _, _) dragging_exited::<T> as extern "C" fn(_, _, _)
); );
*/ */
VIEW_CLASS = decl.register(); VIEW_CLASS = Some(decl.register());
}); });
unsafe { VIEW_CLASS } unsafe { VIEW_CLASS.unwrap() }
} }

View file

@ -1,9 +1,9 @@
//! Implements a Select-style dropdown. By default this uses NSPopupSelect on macOS. //! Implements a Select-style dropdown. By default this uses NSPopupSelect on macOS.
use core_graphics::geometry::CGRect; use core_graphics::geometry::CGRect;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::control::Control; use crate::control::Control;
use crate::foundation::{id, load_or_register_class, nil, NSInteger, NSString, NO, YES}; use crate::foundation::{id, load_or_register_class, nil, NSInteger, NSString, NO, YES};
@ -142,7 +142,7 @@ impl Select {
/// I cannot stress this enough. /// I cannot stress this enough.
pub fn set_action<F: Fn(*const Object) + Send + Sync + 'static>(&mut self, action: F) { pub fn set_action<F: Fn(*const Object) + Send + Sync + 'static>(&mut self, action: F) {
// @TODO: This probably isn't ideal but gets the job done for now; needs revisiting. // @TODO: This probably isn't ideal but gets the job done for now; needs revisiting.
let this = self.objc.get(|obj| unsafe { ShareId::from_ptr(msg_send![obj, self]) }); let this: Id<Object, Shared> = self.objc.get(|obj| unsafe { msg_send_id![obj, self] });
let handler = TargetActionHandler::new(&*this, action); let handler = TargetActionHandler::new(&*this, action);
self.handler = Some(handler); self.handler = Some(handler);
} }
@ -161,7 +161,7 @@ impl Select {
pub fn add_item(&self, title: &str) { pub fn add_item(&self, title: &str) {
self.objc.with_mut(|obj| unsafe { self.objc.with_mut(|obj| unsafe {
let s = NSString::new(title); let s = NSString::new(title);
let _: () = msg_send![obj, addItemWithTitle: s]; let _: () = msg_send![obj, addItemWithTitle: &*s];
}); });
} }
@ -262,6 +262,6 @@ impl Drop for Select {
/// Registers an `NSSelect` subclass, and configures it to hold some ivars /// Registers an `NSSelect` subclass, and configures it to hold some ivars
/// for various things we need to store. /// for various things we need to store.
fn register_class() -> *const Class { fn register_class() -> &'static Class {
load_or_register_class("NSPopUpButton", "CacaoSelect", |decl| unsafe {}) load_or_register_class("NSPopUpButton", "CacaoSelect", |decl| unsafe {})
} }

View file

@ -1,9 +1,9 @@
//! A wrapper for NSSwitch. Currently the epitome of jank - if you're poking around here, expect //! A wrapper for NSSwitch. Currently the epitome of jank - if you're poking around here, expect
//! that this will change at some point. //! that this will change at some point.
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::foundation::{id, load_or_register_class, nil, NSString, NO}; use crate::foundation::{id, load_or_register_class, nil, NSString, NO};
use crate::invoker::TargetActionHandler; use crate::invoker::TargetActionHandler;
@ -69,7 +69,7 @@ impl Switch {
let title = NSString::new(text); let title = NSString::new(text);
let view: id = unsafe { let view: id = unsafe {
let button: id = msg_send![register_class(), buttonWithTitle:title target:nil action:nil]; let button: id = msg_send![register_class(), buttonWithTitle: &*title, target: nil, action: nil];
#[cfg(feature = "autolayout")] #[cfg(feature = "autolayout")]
let _: () = msg_send![button, setTranslatesAutoresizingMaskIntoConstraints: NO]; let _: () = msg_send![button, setTranslatesAutoresizingMaskIntoConstraints: NO];
@ -132,7 +132,7 @@ impl Switch {
/// best just to message pass or something. /// best just to message pass or something.
pub fn set_action<F: Fn(*const Object) + Send + Sync + 'static>(&mut self, action: F) { pub fn set_action<F: Fn(*const Object) + Send + Sync + 'static>(&mut self, action: F) {
// @TODO: This probably isn't ideal but gets the job done for now; needs revisiting. // @TODO: This probably isn't ideal but gets the job done for now; needs revisiting.
let this = self.objc.get(|obj| unsafe { ShareId::from_ptr(msg_send![obj, self]) }); let this: Id<Object, Shared> = self.objc.get(|obj| unsafe { msg_send_id![obj, self] });
let handler = TargetActionHandler::new(&*this, action); let handler = TargetActionHandler::new(&*this, action);
self.handler = Some(handler); self.handler = Some(handler);
} }
@ -172,6 +172,6 @@ impl Drop for Switch {
/// Registers an `NSButton` subclass, and configures it to hold some ivars /// Registers an `NSButton` subclass, and configures it to hold some ivars
/// for various things we need to store. /// for various things we need to store.
fn register_class() -> *const Class { fn register_class() -> &'static Class {
load_or_register_class("NSButton", "RSTSwitch", |decl| unsafe {}) load_or_register_class("NSButton", "RSTSwitch", |decl| unsafe {})
} }

View file

@ -3,14 +3,13 @@ use std::ops::{Deref, DerefMut, Range};
use std::os::raw::c_char; use std::os::raw::c_char;
use std::{fmt, slice, str}; use std::{fmt, slice, str};
use core_foundation::base::CFRange; use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::color::Color; use crate::color::Color;
use crate::foundation::{id, to_bool, NSString, BOOL, NO, YES}; use crate::foundation::{id, to_bool, NSString, BOOL, NO, YES};
use crate::utils::CFRange;
use super::Font; use super::Font;
@ -22,7 +21,7 @@ extern "C" {
/// A wrapper around `NSMutableAttributedString`, which can be used for more complex text /// A wrapper around `NSMutableAttributedString`, which can be used for more complex text
/// rendering. /// rendering.
/// ///
pub struct AttributedString(pub Id<Object>); pub struct AttributedString(pub Id<Object, Owned>);
impl AttributedString { impl AttributedString {
/// Creates a blank AttributedString. Internally, this allocates an /// Creates a blank AttributedString. Internally, this allocates an
@ -31,8 +30,8 @@ impl AttributedString {
let text = NSString::no_copy(value); let text = NSString::no_copy(value);
Self(unsafe { Self(unsafe {
let alloc: id = msg_send![class!(NSMutableAttributedString), alloc]; let alloc = msg_send_id![class!(NSMutableAttributedString), alloc];
Id::from_ptr(msg_send![alloc, initWithString:&*text]) msg_send_id![alloc, initWithString:&*text]
}) })
} }
@ -40,7 +39,7 @@ impl AttributedString {
/// internal use, but kept available as part of the public API for the more adventurous types /// internal use, but kept available as part of the public API for the more adventurous types
/// who might need it. /// who might need it.
pub fn wrap(value: id) -> Self { pub fn wrap(value: id) -> Self {
Self(unsafe { Id::from_ptr(msg_send![value, mutableCopy]) }) Self(unsafe { msg_send_id![value, mutableCopy] })
} }
/// Sets the text (foreground) color for the specified range. /// Sets the text (foreground) color for the specified range.
@ -49,19 +48,25 @@ impl AttributedString {
let range = CFRange::init(range.start, range.end); let range = CFRange::init(range.start, range.end);
unsafe { unsafe {
let _: () = msg_send![&*self.0, addAttribute:NSForegroundColorAttributeName let _: () = msg_send![
value:color &*self.0,
range:range addAttribute: NSForegroundColorAttributeName,
value: color,
range: range,
]; ];
} }
} }
/// Set the font for the specified range. /// Set the font for the specified range.
pub fn set_font(&mut self, font: Font, range: Range<isize>) { pub fn set_font(&mut self, font: Font, range: Range<isize>) {
let range = CFRange::init(range.start, range.end);
unsafe { unsafe {
let _: () = msg_send![&*self.0, addAttribute:NSFontAttributeName let _: () = msg_send![
value:&*font &*self.0,
range:range addAttribute: NSFontAttributeName,
value: &*font,
range: range,
]; ];
} }
} }
@ -69,7 +74,7 @@ impl AttributedString {
impl fmt::Display for AttributedString { impl fmt::Display for AttributedString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let string = NSString::from_retained(unsafe { msg_send![&*self.0, string] }); let string = NSString::from_id(unsafe { msg_send_id![&*self.0, string] });
write!(f, "{}", string.to_str()) write!(f, "{}", string.to_str())
} }
@ -77,19 +82,12 @@ impl fmt::Display for AttributedString {
impl fmt::Debug for AttributedString { impl fmt::Debug for AttributedString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let string = NSString::from_retained(unsafe { msg_send![&*self.0, string] }); let string = NSString::from_id(unsafe { msg_send_id![&*self.0, string] });
f.debug_struct("AttributedString").field("text", &string.to_str()).finish() f.debug_struct("AttributedString").field("text", &string.to_str()).finish()
} }
} }
impl From<AttributedString> for id {
/// Consumes and returns the pointer to the underlying NSMutableAttributedString instance.
fn from(mut string: AttributedString) -> Self {
&mut *string.0
}
}
impl Deref for AttributedString { impl Deref for AttributedString {
type Target = Object; type Target = Object;

View file

@ -4,9 +4,9 @@ use std::ops::Deref;
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::foundation::{id, nil, NSArray, NSString, NO, YES}; use crate::foundation::{id, nil, NSArray, NSString, NO, YES};
use crate::utils::os; use crate::utils::os;
@ -14,7 +14,7 @@ use crate::utils::os;
/// A `Font` can be constructed and applied to supported controls to control things like text /// A `Font` can be constructed and applied to supported controls to control things like text
/// appearance and size. /// appearance and size.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Font(pub ShareId<Object>); pub struct Font(pub Id<Object, Shared>);
impl Default for Font { impl Default for Font {
/// Returns the default `labelFont` on macOS. /// Returns the default `labelFont` on macOS.
@ -23,10 +23,10 @@ impl Default for Font {
let default_size: id = unsafe { msg_send![cls, labelFontSize] }; let default_size: id = unsafe { msg_send![cls, labelFontSize] };
#[cfg(feature = "appkit")] #[cfg(feature = "appkit")]
let font = Font(unsafe { ShareId::from_ptr(msg_send![cls, labelFontOfSize: default_size]) }); let font = Font(unsafe { msg_send_id![cls, labelFontOfSize: default_size] });
#[cfg(all(feature = "uikit", not(feature = "appkit")))] #[cfg(all(feature = "uikit", not(feature = "appkit")))]
let font = Font(unsafe { ShareId::from_ptr(msg_send![cls, systemFontOfSize: default_size]) }); let font = Font(unsafe { msg_send_id![cls, systemFontOfSize: default_size] });
font font
} }
} }
@ -44,14 +44,14 @@ impl Font {
pub fn system(size: f64) -> Self { pub fn system(size: f64) -> Self {
let size = size as CGFloat; let size = size as CGFloat;
Font(unsafe { ShareId::from_ptr(msg_send![Self::class(), systemFontOfSize: size]) }) Font(unsafe { msg_send_id![Self::class(), systemFontOfSize: size] })
} }
/// Creates and returns a default bold system font at the specified size. /// Creates and returns a default bold system font at the specified size.
pub fn bold_system(size: f64) -> Self { pub fn bold_system(size: f64) -> Self {
let size = size as CGFloat; let size = size as CGFloat;
Font(unsafe { ShareId::from_ptr(msg_send![Self::class(), boldSystemFontOfSize: size]) }) Font(unsafe { msg_send_id![Self::class(), boldSystemFontOfSize: size] })
} }
/// Creates and returns a monospace system font at the specified size and weight /// Creates and returns a monospace system font at the specified size and weight
@ -67,9 +67,9 @@ impl Font {
let weight = weight as CGFloat; let weight = weight as CGFloat;
if os::is_minimum_semversion(10, 15, 0) { if os::is_minimum_semversion(10, 15, 0) {
Font(unsafe { ShareId::from_ptr(msg_send![class!(NSFont), monospacedSystemFontOfSize: size weight: weight]) }) Font(unsafe { msg_send_id![class!(NSFont), monospacedSystemFontOfSize: size, weight: weight] })
} else { } else {
Font(unsafe { ShareId::from_ptr(msg_send![class!(NSFont), systemFontOfSize: size weight: weight ]) }) Font(unsafe { msg_send_id![class!(NSFont), systemFontOfSize: size, weight: weight] })
} }
} }
} }

View file

@ -15,13 +15,13 @@ use crate::text::label::{LabelDelegate, LABEL_DELEGATE_PTR};
/// Injects an `NSTextField` subclass. This is used for the default views that don't use delegates - we /// Injects an `NSTextField` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be /// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates. /// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class { pub(crate) fn register_view_class() -> &'static Class {
load_or_register_class("NSTextField", "RSTTextField", |decl| unsafe {}) load_or_register_class("NSTextField", "RSTTextField", |decl| unsafe {})
} }
/// Injects an `NSTextField` subclass, with some callback and pointer ivars for what we /// Injects an `NSTextField` subclass, with some callback and pointer ivars for what we
/// need to do. /// need to do.
pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> *const Class { pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> &'static Class {
load_or_register_class("NSView", "RSTTextFieldWithDelegate", |decl| unsafe { load_or_register_class("NSView", "RSTTextFieldWithDelegate", |decl| unsafe {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't // A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move. // move.

View file

@ -43,9 +43,11 @@
//! //!
//! For more information on Autolayout, view the module or check out the examples folder. //! For more information on Autolayout, view the module or check out the examples folder.
use core_foundation::base::TCFType;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::color::Color; use crate::color::Color;
use crate::foundation::{id, nil, NSArray, NSInteger, NSString, NSUInteger, NO, YES}; use crate::foundation::{id, nil, NSArray, NSInteger, NSString, NSUInteger, NO, YES};
@ -76,7 +78,7 @@ pub use traits::LabelDelegate;
pub(crate) static LABEL_DELEGATE_PTR: &str = "rstLabelDelegatePtr"; pub(crate) static LABEL_DELEGATE_PTR: &str = "rstLabelDelegatePtr";
/// A helper method for instantiating view classes and applying default settings to them. /// A helper method for instantiating view classes and applying default settings to them.
fn allocate_view(registration_fn: fn() -> *const Class) -> id { fn allocate_view(registration_fn: fn() -> &'static Class) -> id {
unsafe { unsafe {
#[cfg(feature = "appkit")] #[cfg(feature = "appkit")]
let view: id = { let view: id = {
@ -249,7 +251,7 @@ impl Label {
#[cfg(feature = "autolayout")] #[cfg(feature = "autolayout")]
center_y: LayoutAnchorY::center(view), center_y: LayoutAnchorY::center(view),
layer: Layer::wrap(unsafe { msg_send![view, layer] }), layer: Layer::from_id(unsafe { msg_send_id![view, layer] }),
objc: ObjcProperty::retain(view) objc: ObjcProperty::retain(view)
} }
@ -324,7 +326,7 @@ impl<T> Label<T> {
// @TODO: This is wrong. // @TODO: This is wrong.
// Needs to set ivar and such, akin to View. // Needs to set ivar and such, akin to View.
self.objc.with_mut(|obj| unsafe { self.objc.with_mut(|obj| unsafe {
let color = color.as_ref().cg_color(); let color = color.as_ref().cg_color().as_concrete_TypeRef();
let layer: id = msg_send![obj, layer]; let layer: id = msg_send![obj, layer];
let _: () = msg_send![layer, setBackgroundColor: color]; let _: () = msg_send![layer, setBackgroundColor: color];
}); });

View file

@ -2,8 +2,7 @@ use std::sync::Once;
use objc::declare::ClassDecl; use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel, BOOL}; use objc::runtime::{Class, Object, Sel, BOOL};
use objc::{class, sel, sel_impl}; use objc::{class, sel};
use objc_id::Id;
use crate::foundation::{id, NSUInteger, NO, YES}; use crate::foundation::{id, NSUInteger, NO, YES};
use crate::text::label::{LabelDelegate, LABEL_DELEGATE_PTR}; use crate::text::label::{LabelDelegate, LABEL_DELEGATE_PTR};
@ -11,23 +10,23 @@ use crate::text::label::{LabelDelegate, LABEL_DELEGATE_PTR};
/// Injects an `UILabel` subclass. This is used for the default views that don't use delegates - we /// Injects an `UILabel` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be /// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates. /// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class { pub(crate) fn register_view_class() -> &'static Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class; static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new(); static INIT: Once = Once::new();
INIT.call_once(|| unsafe { INIT.call_once(|| unsafe {
let superclass = class!(UILabel); let superclass = class!(UILabel);
let decl = ClassDecl::new("RSTTextField", superclass).unwrap(); let decl = ClassDecl::new("RSTTextField", superclass).unwrap();
VIEW_CLASS = decl.register(); VIEW_CLASS = Some(decl.register());
}); });
unsafe { VIEW_CLASS } unsafe { VIEW_CLASS.unwrap() }
} }
/// Injects an `UILabel` subclass, with some callback and pointer ivars for what we /// Injects an `UILabel` subclass, with some callback and pointer ivars for what we
/// need to do. /// need to do.
pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> *const Class { pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> &'static Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class; static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new(); static INIT: Once = Once::new();
INIT.call_once(|| unsafe { INIT.call_once(|| unsafe {
@ -38,8 +37,8 @@ pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> *const Cl
// move. // move.
decl.add_ivar::<usize>(LABEL_DELEGATE_PTR); decl.add_ivar::<usize>(LABEL_DELEGATE_PTR);
VIEW_CLASS = decl.register(); VIEW_CLASS = Some(decl.register());
}); });
unsafe { VIEW_CLASS } unsafe { VIEW_CLASS.unwrap() }
} }

View file

@ -7,7 +7,7 @@ use objc::runtime::Class;
use crate::foundation::load_or_register_class_with_optional_generated_suffix; use crate::foundation::load_or_register_class_with_optional_generated_suffix;
/// Used for injecting a custom UIApplication. Currently does nothing. /// Used for injecting a custom UIApplication. Currently does nothing.
pub(crate) fn register_app_class() -> *const Class { pub(crate) fn register_app_class() -> &'static Class {
let should_generate_suffix = false; let should_generate_suffix = false;
load_or_register_class_with_optional_generated_suffix("UIApplication", "RSTApplication", should_generate_suffix, |decl| {}) load_or_register_class_with_optional_generated_suffix("UIApplication", "RSTApplication", should_generate_suffix, |decl| {})

View file

@ -2,11 +2,12 @@
//! creates a custom `UIApplication` subclass that currently does nothing; this is meant as a hook //! creates a custom `UIApplication` subclass that currently does nothing; this is meant as a hook
//! for potential future use. //! for potential future use.
use objc::runtime::{Class, Object, Sel}; use objc::rc::Id;
use objc::{sel, sel_impl}; use objc::runtime::{Bool, Class, Object, Sel};
use objc::sel;
//use crate::error::Error; //use crate::error::Error;
use crate::foundation::{id, load_or_register_class_with_optional_generated_suffix, BOOL, YES}; use crate::foundation::{id, load_or_register_class_with_optional_generated_suffix};
use crate::uikit::app::{AppDelegate, APP_DELEGATE}; use crate::uikit::app::{AppDelegate, APP_DELEGATE};
use crate::uikit::scene::{SceneConnectionOptions, SceneSession}; use crate::uikit::scene::{SceneConnectionOptions, SceneSession};
@ -27,37 +28,39 @@ fn app<T>(this: &Object) -> &T {
} }
/// Fires when the Application Delegate receives a `applicationDidFinishLaunching` notification. /// Fires when the Application Delegate receives a `applicationDidFinishLaunching` notification.
extern "C" fn did_finish_launching<T: AppDelegate>(this: &Object, _: Sel, _: id, _: id) -> BOOL { extern "C" fn did_finish_launching<T: AppDelegate>(this: &Object, _: Sel, _: id, _: id) -> Bool {
app::<T>(this).did_finish_launching(); app::<T>(this).did_finish_launching();
YES Bool::YES
} }
extern "C" fn configuration_for_scene_session<T: AppDelegate>(this: &Object, _: Sel, _: id, session: id, opts: id) -> id { extern "C" fn configuration_for_scene_session<T: AppDelegate>(this: &Object, _: Sel, _: id, session: id, opts: id) -> id {
app::<T>(this) Id::autorelease_return(
.config_for_scene_session(SceneSession::with(session), SceneConnectionOptions::with(opts)) app::<T>(this)
.into_inner() .config_for_scene_session(SceneSession::with(session), SceneConnectionOptions::with(opts))
.0
)
} }
/// Registers an `NSObject` application delegate, and configures it for the various callbacks and /// Registers an `NSObject` application delegate, and configures it for the various callbacks and
/// pointers we need to have. /// pointers we need to have.
pub(crate) fn register_app_delegate_class<T: AppDelegate>() -> *const Class { pub(crate) fn register_app_delegate_class<T: AppDelegate>() -> &'static Class {
let should_generate_suffix = false; let should_generate_suffix = false;
load_or_register_class_with_optional_generated_suffix("NSObject", "RSTAppDelegate", should_generate_suffix, |decl| unsafe { load_or_register_class_with_optional_generated_suffix("NSObject", "RSTAppDelegate", should_generate_suffix, |decl| unsafe {
// Launching Applications // Launching Applications
decl.add_method( decl.add_method(
sel!(application:didFinishLaunchingWithOptions:), sel!(application:didFinishLaunchingWithOptions:),
did_finish_launching::<T> as extern "C" fn(&Object, _, _, id) -> BOOL did_finish_launching::<T> as extern "C" fn(_, _, _, _) -> _
); );
// Scenes // Scenes
decl.add_method( decl.add_method(
sel!(application:configurationForConnectingSceneSession:options:), sel!(application:configurationForConnectingSceneSession:options:),
configuration_for_scene_session::<T> as extern "C" fn(&Object, _, _, id, id) -> id configuration_for_scene_session::<T> as extern "C" fn(_, _, _, _, _) -> _
); );
/*decl.add_method( /*decl.add_method(
sel!(application:didDiscardSceneSessions:), sel!(application:didDiscardSceneSessions:),
did_discard_scene_sessions::<T> as extern "C" fn(&Object, _, _, id) did_discard_scene_sessions::<T> as extern "C" fn(_, _, _, _)
);*/ );*/
}) })
} }

View file

@ -38,7 +38,7 @@ use libc::{c_char, c_int};
use std::ffi::CString; use std::ffi::CString;
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use crate::foundation::{id, nil, AutoReleasePool, NSString, NSUInteger, NO, YES}; use crate::foundation::{id, nil, AutoReleasePool, NSString, NSUInteger, NO, YES};
use crate::notification_center::Dispatcher; use crate::notification_center::Dispatcher;

View file

@ -1,6 +1,6 @@
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::foundation::{id, load_or_register_class, ClassMap, NSString}; use crate::foundation::{id, load_or_register_class, ClassMap, NSString};
@ -10,7 +10,7 @@ use crate::uikit::scene::SessionRole;
/// ///
/// Due to the way we have to implement this, you likely never need to touch this. /// Due to the way we have to implement this, you likely never need to touch this.
#[derive(Debug)] #[derive(Debug)]
pub struct SceneConfig(Id<Object>); pub struct SceneConfig(pub Id<Object, Owned>);
impl SceneConfig { impl SceneConfig {
/// Creates a new `UISceneConfiguration` with the specified name and session role, retains it, /// Creates a new `UISceneConfiguration` with the specified name and session role, retains it,
@ -24,20 +24,15 @@ impl SceneConfig {
let role = NSString::from(role); let role = NSString::from(role);
let cls = class!(UISceneConfiguration); let cls = class!(UISceneConfiguration);
let config: id = msg_send![cls, configurationWithName:name sessionRole:role]; let mut config = msg_send_id![cls, configurationWithName: &*name, sessionRole: &*role];
let _: () = msg_send![config, setSceneClass: class!(UIWindowScene)]; let _: () = msg_send![&mut config, setSceneClass: class!(UIWindowScene)];
// TODO: use register_window_scene_delegate_class rather than load_or_register_class. // TODO: use register_window_scene_delegate_class rather than load_or_register_class.
let window_delegate = load_or_register_class("UIResponder", "RSTWindowSceneDelegate", |decl| unsafe {}); let window_delegate = load_or_register_class("UIResponder", "RSTWindowSceneDelegate", |decl| unsafe {});
let _: () = msg_send![config, setDelegateClass: window_delegate]; let _: () = msg_send![&mut config, setDelegateClass: window_delegate];
Id::from_ptr(config) config
}) })
} }
/// Consumes and returns the underlying `UISceneConfiguration`.
pub fn into_inner(mut self) -> id {
&mut *self.0
}
} }

View file

@ -1,5 +1,5 @@
use objc::runtime::{Class, Object, Protocol, Sel}; use objc::runtime::{Class, Object, Protocol, Sel};
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use crate::foundation::{id, load_or_register_class_with_optional_generated_suffix}; use crate::foundation::{id, load_or_register_class_with_optional_generated_suffix};
use crate::uikit::app::SCENE_DELEGATE_VENDOR; use crate::uikit::app::SCENE_DELEGATE_VENDOR;
@ -9,9 +9,9 @@ use crate::utils::load;
pub(crate) static WINDOW_SCENE_PTR: &str = "rstWindowSceneDelegatePtr"; pub(crate) static WINDOW_SCENE_PTR: &str = "rstWindowSceneDelegatePtr";
/// ///
extern "C" fn init<T: WindowSceneDelegate, F: Fn() -> Box<T>>(this: &mut Object, _: Sel) -> id { extern "C" fn init<T: WindowSceneDelegate, F: Fn() -> Box<T>>(mut this: &mut Object, _: Sel) -> id {
let x = unsafe { let x = unsafe {
*this = msg_send![super(this, class!(UIResponder)), init]; this = msg_send![super(this, class!(UIResponder)), init];
let scene_delegate_vendor = SCENE_DELEGATE_VENDOR as *const F; let scene_delegate_vendor = SCENE_DELEGATE_VENDOR as *const F;
let factory: &F = &*scene_delegate_vendor; let factory: &F = &*scene_delegate_vendor;
@ -44,7 +44,7 @@ extern "C" fn scene_will_connect_to_session_with_options<T: WindowSceneDelegate>
/// Registers an `NSObject` application delegate, and configures it for the various callbacks and /// Registers an `NSObject` application delegate, and configures it for the various callbacks and
/// pointers we need to have. /// pointers we need to have.
pub(crate) fn register_window_scene_delegate_class<T: WindowSceneDelegate, F: Fn() -> Box<T>>() -> *const Class { pub(crate) fn register_window_scene_delegate_class<T: WindowSceneDelegate, F: Fn() -> Box<T>>() -> &'static Class {
let should_generate_suffix = false; let should_generate_suffix = false;
load_or_register_class_with_optional_generated_suffix("UIResponder", "RSTWindowSceneDelegate", false, |decl| unsafe { load_or_register_class_with_optional_generated_suffix("UIResponder", "RSTWindowSceneDelegate", false, |decl| unsafe {
@ -55,12 +55,12 @@ pub(crate) fn register_window_scene_delegate_class<T: WindowSceneDelegate, F: Fn
decl.add_protocol(p); decl.add_protocol(p);
// Override the `init` call to handle creating and attaching a WindowSceneDelegate. // Override the `init` call to handle creating and attaching a WindowSceneDelegate.
decl.add_method(sel!(init), init::<T, F> as extern "C" fn(&mut Object, _) -> id); decl.add_method(sel!(init), init::<T, F> as extern "C" fn(_, _) -> _);
// UIWindowSceneDelegate API // UIWindowSceneDelegate API
decl.add_method( decl.add_method(
sel!(scene:willConnectToSession:options:), sel!(scene:willConnectToSession:options:),
scene_will_connect_to_session_with_options::<T> as extern "C" fn(&Object, _, _, _, _) scene_will_connect_to_session_with_options::<T> as extern "C" fn(_, _, _, _, _)
); );
}) })
} }

View file

@ -5,9 +5,9 @@
use core_graphics::geometry::CGRect; use core_graphics::geometry::CGRect;
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use objc_id::Id;
use crate::foundation::id; use crate::foundation::id;
use crate::geometry::Rect; use crate::geometry::Rect;
@ -31,11 +31,11 @@ mod session;
pub use session::*; pub use session::*;
#[derive(Debug)] #[derive(Debug)]
pub struct Scene(pub Id<Object>); pub struct Scene(pub Id<Object, Owned>);
impl Scene { impl Scene {
pub fn with(scene: id) -> Self { pub fn with(scene: id) -> Self {
Scene(unsafe { Id::from_ptr(scene) }) Scene(unsafe { Id::retain(scene).unwrap() })
} }
// This is temporary - I'm not wrapping `coordinateSpace` until I'm happy with the ergonomics // This is temporary - I'm not wrapping `coordinateSpace` until I'm happy with the ergonomics
@ -48,8 +48,4 @@ impl Scene {
} }
.into() .into()
} }
pub fn into_inner(mut self) -> id {
&mut *self.0
}
} }

View file

@ -1,6 +1,6 @@
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use objc_id::Id;
use crate::foundation::{id, NSString}; use crate::foundation::{id, NSString};
@ -8,15 +8,10 @@ use crate::foundation::{id, NSString};
/// ///
/// Due to the way we have to implement this, you likely never need to touch this. /// Due to the way we have to implement this, you likely never need to touch this.
#[derive(Debug)] #[derive(Debug)]
pub struct SceneConnectionOptions(Id<Object>); pub struct SceneConnectionOptions(Id<Object, Owned>);
impl SceneConnectionOptions { impl SceneConnectionOptions {
pub fn with(opts: id) -> Self { pub fn with(opts: id) -> Self {
SceneConnectionOptions(unsafe { Id::from_ptr(opts) }) SceneConnectionOptions(unsafe { Id::retain(opts).unwrap() })
}
/// Consumes and returns the underlying `UISceneConfiguration`.
pub fn into_inner(mut self) -> id {
&mut *self.0
} }
} }

View file

@ -1,19 +1,19 @@
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::foundation::{id, NSString}; use crate::foundation::{id, NSString};
use crate::uikit::scene::enums::SessionRole; use crate::uikit::scene::enums::SessionRole;
#[derive(Debug)] #[derive(Debug)]
pub struct SceneSession(pub Id<Object>); pub struct SceneSession(pub Id<Object, Owned>);
impl SceneSession { impl SceneSession {
pub fn with(session: id) -> Self { pub fn with(session: id) -> Self {
SceneSession(unsafe { Id::from_ptr(session) }) SceneSession(unsafe { Id::retain(session).unwrap() })
} }
pub fn role(&self) -> SessionRole { pub fn role(&self) -> SessionRole {
NSString::from_retained(unsafe { msg_send![&*self.0, role] }).into() NSString::from_id(unsafe { msg_send_id![&*self.0, role] }).into()
} }
} }

View file

@ -1,8 +1,8 @@
use core_graphics::geometry::CGRect; use core_graphics::geometry::CGRect;
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::foundation::id; use crate::foundation::id;
use crate::geometry::Rect; use crate::geometry::Rect;
@ -10,20 +10,20 @@ use crate::uikit::Scene;
use crate::utils::Controller; use crate::utils::Controller;
#[derive(Debug)] #[derive(Debug)]
pub struct Window(pub Id<Object>); pub struct Window(pub Id<Object, Owned>);
impl Window { impl Window {
pub fn new(frame: Rect) -> Self { pub fn new(frame: Rect) -> Self {
Window(unsafe { Window(unsafe {
let rect: CGRect = frame.into(); let rect: CGRect = frame.into();
let alloc: id = msg_send![class!(UIWindow), alloc]; let alloc = msg_send_id![class!(UIWindow), alloc];
Id::from_ptr(msg_send![alloc, initWithFrame: rect]) msg_send_id![alloc, initWithFrame: rect]
}) })
} }
pub fn set_window_scene(&mut self, scene: Scene) { pub fn set_window_scene(&mut self, scene: Scene) {
unsafe { unsafe {
let _: () = msg_send![&*self.0, setWindowScene:scene.into_inner()]; let _: () = msg_send![&*self.0, setWindowScene: &*scene.0];
} }
} }

View file

@ -2,19 +2,19 @@
//! //!
//! This is primarily used in handling app handoff between devices. //! This is primarily used in handling app handoff between devices.
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc_id::ShareId;
use crate::foundation::id; use crate::foundation::id;
/// Represents an `NSUserActivity`, which acts as a lightweight method to capture /// Represents an `NSUserActivity`, which acts as a lightweight method to capture
/// the state of your app. /// the state of your app.
#[derive(Debug)] #[derive(Debug)]
pub struct UserActivity(pub ShareId<Object>); pub struct UserActivity(pub Id<Object, Shared>);
impl UserActivity { impl UserActivity {
/// An internal method for wrapping a system-provided activity. /// An internal method for wrapping a system-provided activity.
pub(crate) fn with_inner(object: id) -> Self { pub(crate) fn with_inner(object: id) -> Self {
UserActivity(unsafe { ShareId::from_ptr(object) }) UserActivity(unsafe { Id::retain(object).unwrap() })
} }
} }

View file

@ -6,7 +6,7 @@
use block::ConcreteBlock; use block::ConcreteBlock;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use uuid::Uuid; use uuid::Uuid;
use crate::foundation::{id, nil, NSString, NSUInteger}; use crate::foundation::{id, nil, NSString, NSUInteger};
@ -27,7 +27,7 @@ impl NotificationCenter {
unsafe { unsafe {
// @TODO: Revisit. // @TODO: Revisit.
let block = ConcreteBlock::new(|_: id, error: id| { let block = ConcreteBlock::new(|_: id, error: id| {
let localized_description = NSString::new(msg_send![error, localizedDescription]); let localized_description = NSString::retain(msg_send![error, localizedDescription]);
let e = localized_description.to_str(); let e = localized_description.to_str();
if e != "" { if e != "" {
println!("{:?}", e); println!("{:?}", e);
@ -41,7 +41,11 @@ impl NotificationCenter {
} }
let center: id = msg_send![class!(UNUserNotificationCenter), currentNotificationCenter]; let center: id = msg_send![class!(UNUserNotificationCenter), currentNotificationCenter];
let _: () = msg_send![center, requestAuthorizationWithOptions:opts completionHandler:block.copy()]; let _: () = msg_send![
center,
requestAuthorizationWithOptions:opts,
completionHandler: &*block.copy(),
];
} }
} }
@ -51,8 +55,12 @@ impl NotificationCenter {
unsafe { unsafe {
let identifier = NSString::new(&uuidentifier); let identifier = NSString::new(&uuidentifier);
let request: id = let request: id = msg_send![
msg_send![class!(UNNotificationRequest), requestWithIdentifier:identifier content:&*notification.0 trigger:nil]; class!(UNNotificationRequest),
requestWithIdentifier: &*identifier,
content: &*notification.0,
trigger: nil,
];
let center: id = msg_send![class!(UNUserNotificationCenter), currentNotificationCenter]; let center: id = msg_send![class!(UNUserNotificationCenter), currentNotificationCenter];
let _: () = msg_send![center, addNotificationRequest: request]; let _: () = msg_send![center, addNotificationRequest: request];
} }

View file

@ -1,16 +1,16 @@
//! Acts as a (currently dumb) wrapper for `UNMutableNotificationContent`, which is what you mostly //! Acts as a (currently dumb) wrapper for `UNMutableNotificationContent`, which is what you mostly
//! need to pass to the notification center for things to work. //! need to pass to the notification center for things to work.
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, msg_send_id, sel};
use objc_id::Id;
use crate::foundation::{id, NSString}; use crate::foundation::{id, NSString};
/// A wrapper for `UNMutableNotificationContent`. Retains the pointer from the Objective C side, /// A wrapper for `UNMutableNotificationContent`. Retains the pointer from the Objective C side,
/// and is ultimately dropped upon sending. /// and is ultimately dropped upon sending.
#[derive(Debug)] #[derive(Debug)]
pub struct Notification(pub Id<Object>); pub struct Notification(pub Id<Object, Owned>);
impl Notification { impl Notification {
/// Constructs a new `Notification`. This allocates `NSString`'s, as it has to do so for the /// Constructs a new `Notification`. This allocates `NSString`'s, as it has to do so for the
@ -20,10 +20,10 @@ impl Notification {
let body = NSString::new(body); let body = NSString::new(body);
Notification(unsafe { Notification(unsafe {
let content: id = msg_send![class!(UNMutableNotificationContent), new]; let mut content = msg_send_id![class!(UNMutableNotificationContent), new];
let _: () = msg_send![content, setTitle: title]; let _: () = msg_send![&mut content, setTitle: &*title];
let _: () = msg_send![content, setBody: body]; let _: () = msg_send![&mut content, setBody: &*body];
Id::from_ptr(content) content
}) })
} }
} }

View file

@ -2,13 +2,14 @@
//! belong to. These are typically internal, and if you rely on them... well, don't be surprised if //! belong to. These are typically internal, and if you rely on them... well, don't be surprised if
//! they go away one day. //! they go away one day.
use core_foundation::base::CFIndex;
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use objc::{class, msg_send, sel, sel_impl}; use objc::{class, msg_send, sel};
use objc::rc::{Id, Shared};
use objc::runtime::Object; use objc::runtime::Object;
use objc::{Encode, Encoding}; use objc::{Encode, Encoding};
use objc_id::ShareId;
use crate::foundation::{id, BOOL, NO, YES}; use crate::foundation::{id, BOOL, NO, YES};
@ -22,7 +23,7 @@ pub mod properties;
/// a guard for whether something is a (View|Window|etc)Controller. /// a guard for whether something is a (View|Window|etc)Controller.
pub trait Controller { pub trait Controller {
/// Returns the underlying Objective-C object. /// Returns the underlying Objective-C object.
fn get_backing_node(&self) -> ShareId<Object>; fn get_backing_node(&self) -> Id<Object, Shared>;
} }
/// Utility method for taking a pointer and grabbing the corresponding delegate in Rust. This is /// Utility method for taking a pointer and grabbing the corresponding delegate in Rust. This is
@ -92,14 +93,29 @@ impl CGSize {
} }
unsafe impl Encode for CGSize { unsafe impl Encode for CGSize {
/// Adds support for CGSize Objective-C encoding. const ENCODING: Encoding = Encoding::Struct("CGSize", &[CGFloat::ENCODING, CGFloat::ENCODING]);
fn encode() -> Encoding { }
let encoding = format!("{{CGSize={}{}}}", CGFloat::encode().as_str(), CGFloat::encode().as_str());
unsafe { Encoding::from_str(&encoding) } #[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct CFRange {
pub location: CFIndex,
pub length: CFIndex
}
impl CFRange {
pub fn init(location: CFIndex, length: CFIndex) -> CFRange {
CFRange {
location: location,
length: length
}
} }
} }
unsafe impl Encode for CFRange {
const ENCODING: Encoding = Encoding::Struct("CFRange", &[CFIndex::ENCODING, CFIndex::ENCODING]);
}
/// A helper method for ensuring that Cocoa is running in multi-threaded mode. /// A helper method for ensuring that Cocoa is running in multi-threaded mode.
/// ///
/// Why do we need this? According to Apple, if you're going to make use of standard POSIX threads, /// Why do we need this? According to Apple, if you're going to make use of standard POSIX threads,

View file

@ -1,8 +1,8 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use objc::rc::{Id, Owned};
use objc::runtime::Object; use objc::runtime::Object;
use objc_id::Id;
use crate::foundation::id; use crate::foundation::id;
@ -15,17 +15,12 @@ use crate::foundation::id;
/// It is possible we could remove the `Id` wrapper in here if we're just doing this ourselves, and /// It is possible we could remove the `Id` wrapper in here if we're just doing this ourselves, and
/// is probably worth investigating at some point. /// is probably worth investigating at some point.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ObjcProperty(Rc<RefCell<Id<Object>>>); pub struct ObjcProperty(Rc<RefCell<Id<Object, Owned>>>);
impl ObjcProperty { impl ObjcProperty {
/// Given an Objective-C object, retains it and wraps it as a `Property`. /// Given an Objective-C object, retains it and wraps it as a `Property`.
pub fn retain(obj: id) -> Self { pub fn retain(obj: id) -> Self {
ObjcProperty(Rc::new(RefCell::new(unsafe { Id::from_ptr(obj) }))) ObjcProperty(Rc::new(RefCell::new(unsafe { Id::retain(obj).unwrap() })))
}
/// Given an Objective-C object, retains it and wraps it as a `Property`.
pub fn from_retained(obj: id) -> Self {
ObjcProperty(Rc::new(RefCell::new(unsafe { Id::from_retained_ptr(obj) })))
} }
/// Runs a handler with mutable access for the underlying Objective-C object. /// Runs a handler with mutable access for the underlying Objective-C object.

View file

@ -1,18 +1,18 @@
use core_graphics::base::CGFloat; use core_graphics::base::CGFloat;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object}; use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl}; use objc::{msg_send, msg_send_id, sel};
use objc_id::ShareId;
use crate::foundation::id; use crate::foundation::id;
/// A wrapper for an animation proxy object in Cocoa that supports basic animations. /// A wrapper for an animation proxy object in Cocoa that supports basic animations.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ViewAnimatorProxy(pub ShareId<Object>); pub struct ViewAnimatorProxy(pub Id<Object, Shared>);
impl ViewAnimatorProxy { impl ViewAnimatorProxy {
pub fn new(proxy: id) -> Self { pub fn new(proxy: id) -> Self {
Self(unsafe { ShareId::from_ptr(msg_send![proxy, animator]) }) Self(unsafe { msg_send_id![proxy, animator] })
} }
/// Sets the alpha value for the view being animated. /// Sets the alpha value for the view being animated.
@ -22,3 +22,7 @@ impl ViewAnimatorProxy {
} }
} }
} }
// TODO: Safety
unsafe impl Send for ViewAnimatorProxy {}
unsafe impl Sync for ViewAnimatorProxy {}

View file

@ -8,51 +8,45 @@
//! color, and enforcing layer backing by default. //! color, and enforcing layer backing by default.
use objc::declare::ClassDecl; use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel, BOOL}; use objc::rc::{Id, Owned};
use objc::{class, msg_send, sel, sel_impl}; use objc::runtime::{Bool, Class, Object, Sel};
use objc_id::Id; use objc::{class, msg_send, sel};
use crate::dragdrop::DragInfo; use crate::dragdrop::DragInfo;
use crate::foundation::{id, load_or_register_class, nil, NSUInteger, NO, YES}; use crate::foundation::{id, load_or_register_class, nil, NSUInteger};
use crate::utils::load; use crate::utils::load;
use crate::view::{ViewDelegate, BACKGROUND_COLOR, VIEW_DELEGATE_PTR}; use crate::view::{ViewDelegate, BACKGROUND_COLOR, VIEW_DELEGATE_PTR};
/// Enforces normalcy, or: a needlessly cruel method in terms of the name. You get the idea though. /// Enforces normalcy, or: a needlessly cruel method in terms of the name. You get the idea though.
extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> BOOL { extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> Bool {
return YES; return Bool::YES;
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger { extern "C" fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = load::<T>(this, VIEW_DELEGATE_PTR); let view = load::<T>(this, VIEW_DELEGATE_PTR);
view.dragging_entered(DragInfo { view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}) })
.into() .into()
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn prepare_for_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL { extern "C" fn prepare_for_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> Bool {
let view = load::<T>(this, VIEW_DELEGATE_PTR); let view = load::<T>(this, VIEW_DELEGATE_PTR);
match view.prepare_for_drag_operation(DragInfo { Bool::new(view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}) { }))
true => YES,
false => NO
}
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
extern "C" fn perform_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL { extern "C" fn perform_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> Bool {
let view = load::<T>(this, VIEW_DELEGATE_PTR); let view = load::<T>(this, VIEW_DELEGATE_PTR);
match view.perform_drag_operation(DragInfo { Bool::new(view.perform_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}) { }))
true => YES,
false => NO
}
} }
/// Called when a drag/drop operation has entered this view. /// Called when a drag/drop operation has entered this view.
@ -60,7 +54,7 @@ extern "C" fn conclude_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel
let view = load::<T>(this, VIEW_DELEGATE_PTR); let view = load::<T>(this, VIEW_DELEGATE_PTR);
view.conclude_drag_operation(DragInfo { view.conclude_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}); });
} }
@ -69,7 +63,7 @@ extern "C" fn dragging_exited<T: ViewDelegate>(this: &mut Object, _: Sel, info:
let view = load::<T>(this, VIEW_DELEGATE_PTR); let view = load::<T>(this, VIEW_DELEGATE_PTR);
view.dragging_exited(DragInfo { view.dragging_exited(DragInfo {
info: unsafe { Id::from_ptr(info) } info: unsafe { Id::retain(info).unwrap() }
}); });
} }
@ -89,11 +83,11 @@ extern "C" fn update_layer(this: &Object, _: Sel) {
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we /// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be /// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates. /// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class { pub(crate) fn register_view_class() -> &'static Class {
load_or_register_class("NSView", "RSTView", |decl| unsafe { load_or_register_class("NSView", "RSTView", |decl| unsafe {
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(&Object, _)); decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(_, _));
decl.add_method(sel!(wantsUpdateLayer), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); decl.add_method(sel!(wantsUpdateLayer), enforce_normalcy as extern "C" fn(_, _) -> _);
decl.add_ivar::<id>(BACKGROUND_COLOR); decl.add_ivar::<id>(BACKGROUND_COLOR);
}) })
@ -101,43 +95,37 @@ pub(crate) fn register_view_class() -> *const Class {
/// Injects an `NSView` subclass, with some callback and pointer ivars for what we /// Injects an `NSView` subclass, with some callback and pointer ivars for what we
/// need to do. /// need to do.
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 { load_or_register_class("NSView", instance.subclass_name(), |decl| unsafe {
// A pointer to the ViewDelegate instance on the Rust side. // A pointer to the ViewDelegate instance on the Rust side.
// It's expected that this doesn't move. // It's expected that this doesn't move.
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR); decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
decl.add_ivar::<id>(BACKGROUND_COLOR); decl.add_ivar::<id>(BACKGROUND_COLOR);
decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(&Object, _)); decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(_, _));
decl.add_method(sel!(wantsUpdateLayer), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); decl.add_method(sel!(wantsUpdateLayer), enforce_normalcy as extern "C" fn(_, _) -> _);
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
// Drag and drop operations (e.g, accepting files) // Drag and drop operations (e.g, accepting files)
decl.add_method( decl.add_method(sel!(draggingEntered:), dragging_entered::<T> as extern "C" fn(_, _, _) -> _);
sel!(draggingEntered:),
dragging_entered::<T> as extern "C" fn(&mut Object, _, _) -> NSUInteger
);
decl.add_method( decl.add_method(
sel!(prepareForDragOperation:), sel!(prepareForDragOperation:),
prepare_for_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL prepare_for_drag_operation::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(performDragOperation:), sel!(performDragOperation:),
perform_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL perform_drag_operation::<T> as extern "C" fn(_, _, _) -> _
); );
decl.add_method( decl.add_method(
sel!(concludeDragOperation:), sel!(concludeDragOperation:),
conclude_drag_operation::<T> as extern "C" fn(&mut Object, _, _) conclude_drag_operation::<T> as extern "C" fn(_, _, _)
); );
decl.add_method( decl.add_method(sel!(draggingExited:), dragging_exited::<T> as extern "C" fn(_, _, _));
sel!(draggingExited:),
dragging_exited::<T> as extern "C" fn(&mut Object, _, _)
);
}) })
} }

Some files were not shown because too many files have changed in this diff Show more