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_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),
}
@ -293,7 +291,8 @@ impl<T> View<T> {
#[cfg(target_os = "macos")]
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")]
@ -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.
``` rust
pub(crate) fn register_view_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_view_class() -> &'static Class {
static mut VIEW_CLASS: Option<'static Class> = None;
static INIT: Once = Once::new();
INIT.call_once(|| unsafe {
let superclass = class!(NSView);
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);
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:
``` rust
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>(instance: &T) -> *const Class {
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSView", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
decl.add_ivar::<id>(BACKGROUND_COLOR);
decl.add_method(
sel!(isFlipped),
enforce_normalcy as extern "C" fn(&Object, _) -> BOOL
enforce_normalcy as extern "C" fn(_, _) -> _,
);
decl.add_method(
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`:
``` rust
extern "C" fn is_flipped(_: &Object, _: Sel) -> BOOL {
return YES;
extern "C" fn is_flipped(_: &Object, _: Sel) -> Bool {
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
extern "C" fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = utils::load::<T>(this, VIEW_DELEGATE_PTR);
view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) }
info: unsafe { Id::retain(info).unwrap() }
}).into()
}
```

View file

@ -20,15 +20,16 @@ rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
bitmask-enum = "2.2.1"
block = "0.1.6"
core-foundation = "0.9"
core-graphics = "0.23"
objc = { version = "=0.3.0-beta.2", package = "objc2" }
block = { version = "=0.2.0-alpha.6", package = "block2" }
# 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"
infer = { version = "0.15", optional = true }
lazy_static = "1.4.0"
libc = "0.2"
objc = "0.2.7"
objc_id = "0.1.1"
os_info = "3.0.1"
url = "2.1.1"
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::input::{TextField, TextFieldDelegate};
@ -35,12 +35,12 @@ impl BrowserToolbar {
let back_button = Button::new("Back");
let mut back_item = ToolbarItem::new(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 mut forwards_item = ToolbarItem::new(FWDS_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_item = ToolbarItem::new(URL_BAR);

View file

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

View file

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

View file

@ -7,6 +7,6 @@ use objc::runtime::Class;
use crate::foundation::load_or_register_class;
/// 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 {})
}

View file

@ -5,8 +5,8 @@
use std::ffi::c_void;
use block::Block;
use objc::runtime::{Class, Object, Sel};
use objc::{msg_send, sel, sel_impl};
use objc::runtime::{Bool, Class, Object, Sel};
use objc::{msg_send, sel};
use url::Url;
use crate::appkit::app::{AppDelegate, APP_PTR};
@ -14,7 +14,7 @@ use crate::appkit::printing::PrintSettings;
#[cfg(feature = "cloudkit")]
use crate::cloudkit::share::CKShareMetaData;
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;
/// 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
/// `applicationShouldHandleReopen:hasVisibleWindows:` notification.
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)) {
true => YES,
false => NO
}
extern "C" fn should_handle_reopen<T: AppDelegate>(this: &Object, _: Sel, _: id, has_visible_windows: Bool) -> Bool {
Bool::new(app::<T>(this).should_handle_reopen(has_visible_windows.as_bool()))
}
/// 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:`
/// 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);
match app::<T>(this).will_continue_user_activity(activity.to_str()) {
true => YES,
false => NO
}
Bool::new(app::<T>(this).will_continue_user_activity(activity.to_str()))
}
/// 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
// much `NSObject` retainping we want to do here. For now, pass the handler for whenever it's
// useful.
let activity = UserActivity::with_inner(activity);
match app::<T>(this).continue_user_activity(activity, || unsafe {
let handler = handler as *const Block<(id,), c_void>;
Bool::new(app::<T>(this).continue_user_activity(activity, || unsafe {
let handler = handler as *const Block<(id,), ()>;
(*handler).call((nil,));
}) {
true => YES,
false => NO
}
}))
}
/// 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.
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);
match app::<T>(this).open_file_without_ui(filename.to_str()) {
true => YES,
false => NO
}
Bool::new(app::<T>(this).open_file_without_ui(filename.to_str()))
}
/// Fired when the application receives an `applicationShouldOpenUntitledFile:` message.
extern "C" fn should_open_untitled_file<T: AppDelegate>(this: &Object, _: Sel, _: id) -> BOOL {
match app::<T>(this).should_open_untitled_file() {
true => YES,
false => NO
}
extern "C" fn should_open_untitled_file<T: AppDelegate>(this: &Object, _: Sel, _: id) -> Bool {
Bool::new(app::<T>(this).should_open_untitled_file())
}
/// Fired when the application receives an `applicationShouldTerminateAfterLastWindowClosed:` message.
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() {
true => YES,
false => NO
}
extern "C" fn should_terminate_after_last_window_closed<T: AppDelegate>(this: &Object, _: Sel, _: id) -> Bool {
Bool::new(app::<T>(this).should_terminate_after_last_window_closed())
}
/// Fired when the application receives an `applicationOpenUntitledFile:` message.
extern "C" fn open_untitled_file<T: AppDelegate>(this: &Object, _: Sel, _: id) -> BOOL {
match app::<T>(this).open_untitled_file() {
true => YES,
false => NO
}
extern "C" fn open_untitled_file<T: AppDelegate>(this: &Object, _: Sel, _: id) -> Bool {
Bool::new(app::<T>(this).open_untitled_file())
}
/// 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);
match app::<T>(this).open_temp_file(filename.to_str()) {
true => YES,
false => NO
}
Bool::new(app::<T>(this).open_temp_file(filename.to_str()))
}
/// 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);
match app::<T>(this).print_file(filename.to_str()) {
true => YES,
false => NO
}
Bool::new(app::<T>(this).print_file(filename.to_str()))
}
/// Fired when the application receives an `application:printFiles:withSettings:showPrintPanels:`
@ -260,7 +233,7 @@ extern "C" fn print_files<T: AppDelegate>(
_: id,
files: id,
settings: id,
show_print_panels: BOOL
show_print_panels: Bool
) -> NSUInteger {
let files = NSArray::retain(files)
.iter()
@ -269,7 +242,9 @@ extern "C" fn print_files<T: AppDelegate>(
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.
@ -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.
/// Note: this may not fire in sandboxed applications. Apple's documentation is unclear on the
/// 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);
match app::<T>(this).delegate_handles_key(key.to_str()) {
true => YES,
false => NO
}
Bool::new(app::<T>(this).delegate_handles_key(key.to_str()))
}
/// Registers an `NSObject` application delegate, and configures it for the various callbacks and
/// pointers we need to have.
pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> *const Class {
pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> &'static Class {
load_or_register_class("NSObject", "RSTAppDelegate", |decl| unsafe {
decl.add_ivar::<usize>(APP_PTR);
// Launching Applications
decl.add_method(
sel!(applicationWillFinishLaunching:),
will_finish_launching::<T> as extern "C" fn(&Object, _, _)
will_finish_launching::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(applicationDidFinishLaunching:),
did_finish_launching::<T> as extern "C" fn(&Object, _, _)
did_finish_launching::<T> as extern "C" fn(_, _, _)
);
// Managing Active Status
decl.add_method(
sel!(applicationWillBecomeActive:),
will_become_active::<T> as extern "C" fn(&Object, _, _)
will_become_active::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(applicationDidBecomeActive:),
did_become_active::<T> as extern "C" fn(&Object, _, _)
did_become_active::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(applicationWillResignActive:),
will_resign_active::<T> as extern "C" fn(&Object, _, _)
will_resign_active::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(applicationDidResignActive:),
did_resign_active::<T> as extern "C" fn(&Object, _, _)
did_resign_active::<T> as extern "C" fn(_, _, _)
);
// Terminating Applications
decl.add_method(
sel!(applicationShouldTerminate:),
should_terminate::<T> as extern "C" fn(&Object, _, _) -> NSUInteger
);
decl.add_method(
sel!(applicationWillTerminate:),
will_terminate::<T> as extern "C" fn(&Object, _, _)
should_terminate::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(sel!(applicationWillTerminate:), will_terminate::<T> as extern "C" fn(_, _, _));
decl.add_method(
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
decl.add_method(sel!(applicationWillHide:), will_hide::<T> as extern "C" fn(&Object, _, _));
decl.add_method(sel!(applicationDidHide:), did_hide::<T> as extern "C" fn(&Object, _, _));
decl.add_method(sel!(applicationWillUnhide:), will_unhide::<T> as extern "C" fn(&Object, _, _));
decl.add_method(sel!(applicationDidUnhide:), did_unhide::<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(_, _, _));
decl.add_method(sel!(applicationWillUnhide:), will_unhide::<T> as extern "C" fn(_, _, _));
decl.add_method(sel!(applicationDidUnhide:), did_unhide::<T> as extern "C" fn(_, _, _));
// Managing Windows
decl.add_method(sel!(applicationWillUpdate:), will_update::<T> as extern "C" fn(&Object, _, _));
decl.add_method(sel!(applicationDidUpdate:), did_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(_, _, _));
decl.add_method(
sel!(applicationShouldHandleReopen:hasVisibleWindows:),
should_handle_reopen::<T> as extern "C" fn(&Object, _, _, BOOL) -> BOOL
should_handle_reopen::<T> as extern "C" fn(_, _, _, _) -> _
);
// Dock Menu
decl.add_method(
sel!(applicationDockMenu:),
dock_menu::<T> as extern "C" fn(&Object, _, _) -> id
);
decl.add_method(sel!(applicationDockMenu:), dock_menu::<T> as extern "C" fn(_, _, _) -> _);
// Displaying Errors
decl.add_method(
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
decl.add_method(
sel!(applicationDidChangeScreenParameters:),
did_change_screen_parameters::<T> as extern "C" fn(&Object, _, _)
did_change_screen_parameters::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(applicationDidChangeOcclusionState:),
did_change_occlusion_state::<T> as extern "C" fn(&Object, _, _)
did_change_occlusion_state::<T> as extern "C" fn(_, _, _)
);
// User Activities
decl.add_method(
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(
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(
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(
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
decl.add_method(
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(
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(
sel!(application:didReceiveRemoteNotification:),
did_receive_remote_notification::<T> as extern "C" fn(&Object, _, _, id)
did_receive_remote_notification::<T> as extern "C" fn(_, _, _, _)
);
// CloudKit
#[cfg(feature = "cloudkit")]
decl.add_method(
sel!(application:userDidAcceptCloudKitShareWithMetadata:),
accepted_cloudkit_share::<T> as extern "C" fn(&Object, _, _, id)
accepted_cloudkit_share::<T> as extern "C" fn(_, _, _, _)
);
// Opening Files
decl.add_method(
sel!(application:openURLs:),
open_urls::<T> as extern "C" fn(&Object, _, _, id)
);
decl.add_method(sel!(application:openURLs:), open_urls::<T> as extern "C" fn(_, _, _, _));
decl.add_method(
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(
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(
sel!(applicationOpenUntitledFile:),
open_untitled_file::<T> as extern "C" fn(&Object, _, _) -> BOOL
open_untitled_file::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(
sel!(application:openTempFile:),
open_temp_file::<T> as extern "C" fn(&Object, _, _, id) -> BOOL
open_temp_file::<T> as extern "C" fn(_, _, _, _) -> _
);
// Printing
decl.add_method(
sel!(application:printFile:),
print_file::<T> as extern "C" fn(&Object, _, _, id) -> BOOL
print_file::<T> as extern "C" fn(_, _, _, _) -> _
);
decl.add_method(
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
@ -450,7 +413,7 @@ pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> *co
// Scripting
decl.add_method(
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 objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
use crate::appkit::menu::Menu;
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.
pub struct App<T = (), M = ()> {
/// The underlying Objective-C Object.
pub objc: Id<Object>,
pub objc: Id<Object, Owned>,
/// The underlying Objective-C Object, which in this case is a delegate that forwards to the
/// app delegate.
pub objc_delegate: Id<Object>,
pub objc_delegate: Id<Object, Owned>,
/// The stored `AppDelegate`.
pub delegate: Box<T>,
@ -144,20 +144,17 @@ where
let pool = AutoReleasePool::new();
let objc = unsafe {
let app: id = msg_send![register_app_class(), sharedApplication];
Id::from_ptr(app)
};
let objc: Id<_, _> = unsafe { msg_send_id![register_app_class(), sharedApplication] };
let app_delegate = Box::new(delegate);
let objc_delegate = unsafe {
let delegate_class = register_app_delegate_class::<T>();
let delegate: id = msg_send![delegate_class, new];
let mut delegate: Id<Object, Owned> = msg_send_id![delegate_class, new];
let delegate_ptr: *const T = &*app_delegate;
(&mut *delegate).set_ivar(APP_PTR, delegate_ptr as usize);
let _: () = msg_send![&*objc, setDelegate: delegate];
Id::from_ptr(delegate)
delegate.set_ivar(APP_PTR, delegate_ptr as usize);
let _: () = msg_send![&*objc, setDelegate: &*delegate];
delegate
};
App {

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};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -7,9 +7,9 @@ use std::cell::RefCell;
use std::rc::Rc;
use objc::declare::ClassDecl;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object, Sel};
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, msg_send_id, sel};
use crate::color::Color;
use crate::control::Control;
@ -171,7 +171,7 @@ impl SegmentedControl {
pub fn set_tooltip_segment(&mut self, index: NSUInteger, tooltip: &str) {
self.objc.with_mut(|obj| unsafe {
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.
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.
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 selected: i32 = msg_send![obj, selectedSegment];
action(selected)

View file

@ -3,11 +3,12 @@
use std::sync::Once;
use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel};
use objc::{class, msg_send, sel, sel_impl};
use objc::rc::Id;
use objc::runtime::{Bool, Class, Object, Sel};
use objc::{class, msg_send, sel};
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;
/// 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>>()
.into();
identifiers.into()
Id::autorelease_return(identifiers.0)
}
/// 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>>()
.into();
identifiers.into()
Id::autorelease_return(identifiers.0)
}
/// 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>>()
.into();
identifiers.into()
Id::autorelease_return(identifiers.0)
}
/// Loads the controller, grabs whatever item is for this identifier, and returns what the
/// 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 identifier = NSString::from_retained(identifier);
let identifier = NSString::retain(identifier);
let item = toolbar.item_for(identifier.to_str());
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
/// to store. We use it as our delegate as well, just to cut down on moving pieces.
pub(crate) fn register_toolbar_class<T: ToolbarDelegate>(instance: &T) -> *const Class {
pub(crate) fn register_toolbar_class<T: ToolbarDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSObject", instance.subclass_name(), |decl| unsafe {
// For callbacks
decl.add_ivar::<usize>(TOOLBAR_PTR);
@ -73,19 +74,19 @@ pub(crate) fn register_toolbar_class<T: ToolbarDelegate>(instance: &T) -> *const
// Add callback methods
decl.add_method(
sel!(toolbarAllowedItemIdentifiers:),
allowed_item_identifiers::<T> as extern "C" fn(&Object, _, _) -> id
allowed_item_identifiers::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(
sel!(toolbarDefaultItemIdentifiers:),
default_item_identifiers::<T> as extern "C" fn(&Object, _, _) -> id
default_item_identifiers::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(
sel!(toolbarSelectableItemIdentifiers:),
selectable_item_identifiers::<T> as extern "C" fn(&Object, _, _) -> id
selectable_item_identifiers::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(
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.
use objc::rc::Id;
use crate::foundation::{id, NSString, NSUInteger};
/// Represents the display mode(s) a Toolbar can render in.
@ -95,7 +97,8 @@ impl ItemIdentifier {
pub(crate) fn to_nsstring(&self) -> id {
unsafe {
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::FlexibleSpace => NSToolbarFlexibleSpaceItemIdentifier,
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
// 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 std::fmt;
use objc::rc::{Id, Owned, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::{Id, ShareId};
use objc::{class, msg_send, msg_send_id, sel};
use crate::appkit::segmentedcontrol::SegmentedControl;
use crate::button::{BezelStyle, Button};
@ -20,7 +20,7 @@ use crate::invoker::TargetActionHandler;
#[derive(Debug)]
pub struct ToolbarItem {
pub identifier: String,
pub objc: Id<Object>,
pub objc: Id<Object, Owned>,
pub button: Option<Button>,
pub segmented_control: Option<SegmentedControl>,
pub image: Option<Image>,
@ -34,10 +34,9 @@ impl ToolbarItem {
let identifier = identifier.into();
let objc = unsafe {
let identifr = NSString::new(&identifier);
let alloc: id = msg_send![class!(NSToolbarItem), alloc];
let item: id = msg_send![alloc, initWithItemIdentifier: identifr];
Id::from_ptr(item)
let identifer = NSString::new(&identifier);
let alloc = msg_send_id![class!(NSToolbarItem), alloc];
msg_send_id![alloc, initWithItemIdentifier: &*identifer]
};
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.
pub fn set_title(&mut self, title: &str) {
unsafe {

View file

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

View file

@ -6,22 +6,19 @@ use std::sync::Once;
use core_graphics::base::CGFloat;
use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel};
use objc::{class, sel, sel_impl};
use objc::runtime::{Bool, Class, Object, Sel};
use objc::{class, sel};
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};
/// Called when an `NSWindowDelegate` receives a `windowWillClose:` event.
/// 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);
match window.should_close() {
true => YES,
false => NO
}
Bool::new(window.should_close())
}
/// 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
/// 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 {
decl.add_ivar::<usize>(WINDOW_DELEGATE_PTR);
// NSWindowDelegate methods
decl.add_method(
sel!(windowShouldClose:),
should_close::<T> as extern "C" fn(&Object, _, _) -> BOOL
);
decl.add_method(sel!(windowWillClose:), will_close::<T> as extern "C" fn(&Object, _, _));
decl.add_method(sel!(windowShouldClose:), should_close::<T> as extern "C" fn(_, _, _) -> _);
decl.add_method(sel!(windowWillClose:), will_close::<T> as extern "C" fn(_, _, _));
// Sizing
decl.add_method(
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(
sel!(windowWillStartLiveResize:),
will_start_live_resize::<T> as extern "C" fn(&Object, _, _)
will_start_live_resize::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(windowDidEndLiveResize:),
did_end_live_resize::<T> as extern "C" fn(&Object, _, _)
did_end_live_resize::<T> as extern "C" fn(_, _, _)
);
// Minimizing
decl.add_method(
sel!(windowWillMiniaturize:),
will_miniaturize::<T> as extern "C" fn(&Object, _, _)
);
decl.add_method(
sel!(windowDidMiniaturize:),
did_miniaturize::<T> as extern "C" fn(&Object, _, _)
);
decl.add_method(sel!(windowWillMiniaturize:), will_miniaturize::<T> as extern "C" fn(_, _, _));
decl.add_method(sel!(windowDidMiniaturize:), did_miniaturize::<T> as extern "C" fn(_, _, _));
decl.add_method(
sel!(windowDidDeminiaturize:),
did_deminiaturize::<T> as extern "C" fn(&Object, _, _)
did_deminiaturize::<T> as extern "C" fn(_, _, _)
);
// Full Screen
decl.add_method(
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(
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(
sel!(windowWillEnterFullScreen:),
will_enter_full_screen::<T> as extern "C" fn(&Object, _, _)
will_enter_full_screen::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(windowDidEnterFullScreen:),
did_enter_full_screen::<T> as extern "C" fn(&Object, _, _)
did_enter_full_screen::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(windowWillExitFullScreen:),
will_exit_full_screen::<T> as extern "C" fn(&Object, _, _)
will_exit_full_screen::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(windowDidExitFullScreen:),
did_exit_full_screen::<T> as extern "C" fn(&Object, _, _)
did_exit_full_screen::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
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(
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
decl.add_method(sel!(windowDidBecomeKey:), did_become_key::<T> as extern "C" fn(&Object, _, _));
decl.add_method(sel!(windowDidResignKey:), did_resign_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(_, _, _));
// Main status
decl.add_method(
sel!(windowDidBecomeMain:),
did_become_main::<T> as extern "C" fn(&Object, _, _)
);
decl.add_method(
sel!(windowDidResignMain:),
did_resign_main::<T> as extern "C" fn(&Object, _, _)
);
decl.add_method(sel!(windowDidBecomeMain:), did_become_main::<T> as extern "C" fn(_, _, _));
decl.add_method(sel!(windowDidResignMain:), did_resign_main::<T> as extern "C" fn(_, _, _));
// Moving Windows
decl.add_method(sel!(windowWillMove:), will_move::<T> as extern "C" fn(&Object, _, _));
decl.add_method(sel!(windowDidMove:), did_move::<T> as extern "C" fn(&Object, _, _));
decl.add_method(
sel!(windowDidChangeScreen:),
did_change_screen::<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(_, _, _));
decl.add_method(sel!(windowDidChangeScreen:), did_change_screen::<T> as extern "C" fn(_, _, _));
decl.add_method(
sel!(windowDidChangeScreenProfile:),
did_change_screen_profile::<T> as extern "C" fn(&Object, _, _)
did_change_screen_profile::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
sel!(windowDidChangeBackingProperties:),
did_change_backing_properties::<T> as extern "C" fn(&Object, _, _)
did_change_backing_properties::<T> as extern "C" fn(_, _, _)
);
// Random
decl.add_method(
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!(windowDidUpdate:), did_update::<T> as extern "C" fn(&Object, _, _));
decl.add_method(sel!(cancelOperation:), cancel::<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(_, _, _));
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
/// 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 {
decl.add_ivar::<usize>(WINDOW_DELEGATE_PTR);
})

View file

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

View file

@ -13,9 +13,9 @@ use block::ConcreteBlock;
use core_graphics::base::CGFloat;
use core_graphics::geometry::{CGRect, CGSize};
use objc::rc::{Id, Owned, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, msg_send_id, sel};
use crate::appkit::toolbar::{Toolbar, ToolbarDelegate};
use crate::color::Color;
@ -47,7 +47,7 @@ pub(crate) static WINDOW_DELEGATE_PTR: &str = "rstWindowDelegate";
#[derive(Debug)]
pub struct Window<T = ()> {
/// Represents an `NS/UIWindow` in the Objective-C runtime.
pub objc: ShareId<Object>,
pub objc: Id<Object, Shared>,
/// A delegate for this window.
pub delegate: Option<Box<T>>
@ -72,40 +72,38 @@ impl Window {
// apps that would use this toolkit wouldn't be tab-oriented...
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
// NeXTSTEP era, and are outright deprecated... so we don't allow setting them.
let buffered: NSUInteger = 2;
let dimensions: CGRect = config.initial_dimensions.into();
let window: id = msg_send![alloc, initWithContentRect:dimensions
styleMask:config.style
backing:buffered
let window: Id<_, _> = msg_send_id![
msg_send_id![class!(NSWindow), alloc],
initWithContentRect: dimensions,
styleMask: config.style,
backing: buffered,
defer: match config.defer {
true => YES,
false => NO
}
},
];
let _: () = msg_send![window, autorelease];
// 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
// Objective-C runtime gets out of sync by releasing the window out from underneath of
// 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.
//
// Why this isn't a setting on the Toolbar itself I'll never know.
if os::is_minimum_version(11) {
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 {
@ -116,7 +114,7 @@ impl Window {
pub(crate) unsafe fn existing(window: *mut Object) -> Window {
Window {
objc: ShareId::from_ptr(window),
objc: Id::retain(window).unwrap(),
delegate: None
}
}
@ -134,51 +132,49 @@ where
let class = register_window_class_with_delegate::<T>(&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
// apps that would use this toolkit wouldn't be tab-oriented...
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
// NeXTSTEP era, and are outright deprecated... so we don't allow setting them.
let buffered: NSUInteger = 2;
let dimensions: CGRect = config.initial_dimensions.into();
let window: id = msg_send![alloc, initWithContentRect:dimensions
styleMask:config.style
backing:buffered
let mut window: Id<Object, Owned> = msg_send_id![
msg_send_id![class, alloc],
initWithContentRect: dimensions,
styleMask: config.style,
backing: buffered,
defer: match config.defer {
true => YES,
false => NO
}
},
];
let delegate_ptr: *const T = &*delegate;
(&mut *window).set_ivar(WINDOW_DELEGATE_PTR, delegate_ptr as usize);
let _: () = msg_send![window, autorelease];
window.set_ivar(WINDOW_DELEGATE_PTR, delegate_ptr as usize);
// 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
// Objective-C runtime gets out of sync by releasing the window out from underneath of
// 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`.
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.
//
// Why this isn't a setting on the Toolbar itself I'll never know.
if os::is_minimum_version(11) {
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) {
unsafe {
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 {
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) {
unsafe {
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.
pub fn toolbar(&self) -> ShareId<Object> {
unsafe {
let o: *mut Object = msg_send![&*self.objc, toolbar];
ShareId::from_ptr(o)
}
pub fn toolbar(&self) -> Id<Object, Shared> {
unsafe { msg_send_id![&self.objc, toolbar] }
}
/// 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();
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::mem;
use objc::{class, msg_send, sel, sel_impl, Encode, Encoding, EncodeArguments, Message};
use objc::runtime::{Class, Sel, Method, Object, Imp};
use objc::runtime::{
objc_getClass,
class_addMethod,
class_getInstanceMethod,
method_exchangeImplementations
};
use objc::ffi;
use objc::runtime::{Class, Imp, Object, Sel};
use objc::{class, msg_send, sel, Encode, EncodeArguments, Encoding, Message};
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 cls = objc_getClass(name.as_ptr());
let cls = ffi::objc_getClass(name.as_ptr());
// let mut cls = class!(NSBundle) as *mut Class;
// Class::get("NSBundle").unwrap();
// let types = format!("{}{}{}", Encoding::String, <*mut Object>::ENCODING, Sel::ENCODING);
let added = class_addMethod(
cls as *mut Class,
sel!(__bundleIdentifier),
let added = ffi::class_addMethod(
cls as *mut ffi::objc_class,
sel!(__bundleIdentifier).as_ptr(),
func.imp(),
CString::new("*@:").unwrap().as_ptr()
CString::new("*@:").unwrap().as_ptr(),
);
let method1 = class_getInstanceMethod(cls, sel!(bundleIdentifier)) as *mut Method;
let method2 = class_getInstanceMethod(cls, sel!(__bundleIdentifier)) as *mut Method;
method_exchangeImplementations(method1, method2);
let method1 = ffi::class_getInstanceMethod(cls, sel!(bundleIdentifier).as_ptr()) as *mut ffi::objc_method;
let method2 = ffi::class_getInstanceMethod(cls, sel!(__bundleIdentifier).as_ptr()) as *mut ffi::objc_method;
ffi::method_exchangeImplementations(method1, method2);
}
pub fn set_bundle_id(bundle_id: &str) {

View file

@ -21,9 +21,9 @@
//! my_view.add_subview(&button);
//! ```
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, msg_send_id, sel};
pub use enums::*;
@ -214,7 +214,7 @@ impl Button {
/// best just to message pass or something.
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.
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);
self.handler = Some(handler);
}
@ -352,7 +352,7 @@ impl Drop for Button {
/// Registers an `NSButton` subclass, and configures it to hold some ivars
/// for various things we need to store.
fn register_class() -> *const Class {
fn register_class() -> &'static Class {
#[cfg(feature = "appkit")]
let super_class = "NSButton";
#[cfg(all(feature = "uikit", not(feature = "appkit")))]

View file

@ -1,7 +1,7 @@
//! This module includes wrappers for `CKShare` and `CKShareMetaData`.
use objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc_id::ShareId;
use crate::foundation::id;
@ -9,14 +9,14 @@ use crate::foundation::id;
/// to, say, handle accepting an invite for a share.
#[derive(Clone, Debug)]
pub struct CKShareMetaData {
pub inner: ShareId<Object>
pub inner: Id<Object, Shared>
}
impl CKShareMetaData {
/// Internal method for wrapping a system-provided `CKShareMetaData` object.
pub(crate) fn with_inner(object: id) -> Self {
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 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::utils::os;
@ -253,95 +253,68 @@ extern "C" fn color_with_system_effect(this: &Object, _: Sel, effect: NSInteger)
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 {
// 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(
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(
sel!(colorUsingColorSpaceName:),
color_using_color_space_name as extern "C" fn(&Object, _, id) -> id
);
decl.add_method(
sel!(numberOfComponents),
number_of_components as extern "C" fn(&Object, _) -> NSInteger
color_using_color_space_name as extern "C" fn(_, _, _) -> _
);
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!(getRed:green:blue:alpha:),
get_rgba as extern "C" fn(&Object, _, CGFloat, CGFloat, CGFloat, CGFloat)
);
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!(getComponents:), get_components as extern "C" fn(_, _, _));
decl.add_method(sel!(getRed:green:blue:alpha:), get_rgba as extern "C" fn(_, _, _, _, _, _));
decl.add_method(sel!(redComponent), red_component as extern "C" fn(_, _) -> _);
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!(hueComponent), hue_component as extern "C" fn(&Object, _) -> CGFloat);
decl.add_method(
sel!(saturationComponent),
saturation_component as extern "C" fn(&Object, _) -> CGFloat
);
decl.add_method(
sel!(brightnessComponent),
brightness_component as extern "C" fn(&Object, _) -> CGFloat
);
decl.add_method(sel!(hueComponent), hue_component as extern "C" fn(_, _) -> _);
decl.add_method(sel!(saturationComponent), saturation_component as extern "C" fn(_, _) -> _);
decl.add_method(sel!(brightnessComponent), brightness_component as extern "C" fn(_, _) -> _);
decl.add_method(
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!(getWhite:alpha:),
get_white as extern "C" fn(&Object, _, CGFloat, CGFloat)
);
decl.add_method(sel!(whiteComponent), white_component as extern "C" fn(_, _) -> _);
decl.add_method(sel!(getWhite:alpha:), get_white as extern "C" fn(_, _, _, _));
decl.add_method(sel!(cyanComponent), cyan_component as extern "C" fn(&Object, _) -> CGFloat);
decl.add_method(
sel!(magentaComponent),
magenta_component as extern "C" fn(&Object, _) -> CGFloat
);
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(sel!(cyanComponent), cyan_component as extern "C" fn(_, _) -> _);
decl.add_method(sel!(magentaComponent), magenta_component as extern "C" fn(_, _) -> _);
decl.add_method(sel!(yellowComponent), yellow_component as extern "C" fn(_, _) -> _);
decl.add_method(sel!(blackComponent), black_component as extern "C" fn(_, _) -> _);
decl.add_method(
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!(setStroke), set_stroke as extern "C" fn(&Object, _));
decl.add_method(sel!(setFill), set_fill as extern "C" fn(&Object, _));
decl.add_method(sel!(set), call_set as extern "C" fn(&Object, _));
decl.add_method(sel!(CGColor), cg_color as extern "C" fn(_, _) -> _);
decl.add_method(sel!(setStroke), set_stroke as extern "C" fn(_, _));
decl.add_method(sel!(setFill), set_fill as extern "C" fn(_, _));
decl.add_method(sel!(set), call_set as extern "C" fn(_, _));
decl.add_method(
sel!(highlightWithLevel:),
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(sel!(highlightWithLevel:), highlight_with_level as extern "C" fn(_, _, _) -> _);
decl.add_method(sel!(shadowWithLevel:), shadow_with_level as extern "C" fn(_, _, _) -> _);
decl.add_method(
sel!(colorWithAlphaComponent:),
color_with_alpha_component as extern "C" fn(&Object, _, CGFloat) -> id
color_with_alpha_component as extern "C" fn(_, _, _) -> _
);
decl.add_method(
sel!(blendedColorWithFraction:ofColor:),
blended_color as extern "C" fn(&Object, _, CGFloat, id) -> id
blended_color as extern "C" fn(_, _, _, _) -> _
);
decl.add_method(
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);

View file

@ -15,12 +15,13 @@
/// @TODO: bundle iOS/tvOS support.
use std::sync::{Arc, RwLock};
use core_foundation::base::TCFType;
use core_graphics::base::CGFloat;
use core_graphics::color::CGColor;
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
use crate::foundation::id;
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
/// 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.
SystemBlack,
@ -247,9 +248,9 @@ impl Color {
let b = blue as CGFloat / 255.0;
let a = alpha as CGFloat / 255.0;
#[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")))]
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)))
}
@ -271,12 +272,18 @@ impl Color {
Color::Custom(Arc::new(RwLock::new(unsafe {
#[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")))]
{
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 {
#[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")))]
{
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
// it and PR it.
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, {
let color: id = handler(Style {
color.set_ivar(AQUA_LIGHT_COLOR_NORMAL_CONTRAST, {
to_objc(&handler(Style {
theme: Theme::Light,
contrast: Contrast::Normal
})
.into();
color
}))
});
(&mut *color).set_ivar(AQUA_LIGHT_COLOR_HIGH_CONTRAST, {
let color: id = handler(Style {
color.set_ivar(AQUA_LIGHT_COLOR_HIGH_CONTRAST, {
to_objc(&handler(Style {
theme: Theme::Light,
contrast: Contrast::High
})
.into();
color
}))
});
(&mut *color).set_ivar(AQUA_DARK_COLOR_NORMAL_CONTRAST, {
let color: id = handler(Style {
color.set_ivar(AQUA_DARK_COLOR_NORMAL_CONTRAST, {
to_objc(&handler(Style {
theme: Theme::Dark,
contrast: Contrast::Normal
})
.into();
color
}))
});
(&mut *color).set_ivar(AQUA_DARK_COLOR_HIGH_CONTRAST, {
let color: id = handler(Style {
color.set_ivar(AQUA_DARK_COLOR_HIGH_CONTRAST, {
to_objc(&handler(Style {
theme: Theme::Light,
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
/// in every context it's used in.
pub fn cg_color(&self) -> CGColor {
// @TODO: This should probably return a CGColorRef...
unsafe {
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 {
/// Consumes and returns the pointer to the underlying Color.
/// Returns the pointer to the underlying Color.
fn from(color: &Color) -> Self {
unsafe { to_objc(color) }
}

View file

@ -1,5 +1,5 @@
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::objc_access::ObjcAccess;

View file

@ -34,9 +34,9 @@
use std::collections::HashMap;
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
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.
#[derive(Debug)]
pub struct UserDefaults(pub Id<Object>);
pub struct UserDefaults(pub Id<Object, Owned>);
impl Default for UserDefaults {
/// Equivalent to calling `UserDefaults::standard()`.
@ -71,7 +71,7 @@ impl UserDefaults {
/// let _ = defaults.get("test");
/// ```
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
@ -89,8 +89,8 @@ impl UserDefaults {
let name = NSString::new(named);
UserDefaults(unsafe {
let alloc: id = msg_send![class!(NSUserDefaults), alloc];
Id::from_ptr(msg_send![alloc, initWithSuiteName:&*name])
let alloc = msg_send_id![class!(NSUserDefaults), alloc];
msg_send_id![alloc, initWithSuiteName:&*name]
})
}
@ -130,10 +130,10 @@ impl UserDefaults {
/// ```
pub fn insert<K: AsRef<str>>(&mut self, key: K, value: Value) {
let key = NSString::new(key.as_ref());
let value: id = value.into();
let value: id = &mut *value.into_id();
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/
if NSNumber::is(result) {
let number = NSNumber::wrap(result);
let number = NSNumber::retain(result);
return match number.objc_type() {
"c" => Some(Value::Bool(number.as_bool())),

View file

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

View file

@ -2,9 +2,9 @@
//! across the codebase, hence why they're here - they're not currently exhaustive, so feel free to
//! tinker and pull request.
use objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, sel};
use crate::foundation::NSUInteger;
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.
#[derive(Clone, Debug)]
pub struct DragInfo {
pub info: ShareId<Object>
pub info: Id<Object, Shared>
}
impl DragInfo {

View file

@ -7,7 +7,7 @@
use std::error;
use std::fmt;
use objc::{class, msg_send, sel, sel_impl};
use objc::{class, msg_send, sel};
use crate::foundation::{id, nil, NSInteger, NSString};
@ -58,7 +58,7 @@ impl Error {
unsafe {
let domain = NSString::new(&self.domain);
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::sync::{Arc, RwLock};
use objc::rc::{Id, Owned};
use objc::runtime::{Object, BOOL};
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
use url::Url;
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 -
/// 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)]
pub struct FileManager(pub Arc<RwLock<Id<Object>>>);
pub struct FileManager(pub Arc<RwLock<Id<Object, Owned>>>);
impl Default for FileManager {
/// 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.
fn default() -> Self {
FileManager(Arc::new(RwLock::new(unsafe {
let manager: id = msg_send![class!(NSFileManager), defaultManager];
Id::from_ptr(manager)
msg_send_id![class!(NSFileManager), defaultManager]
})))
}
}
@ -36,10 +35,7 @@ impl Default for FileManager {
impl FileManager {
/// Returns a new FileManager that opts in to delegate methods.
pub fn new() -> Self {
FileManager(Arc::new(RwLock::new(unsafe {
let manager: id = msg_send![class!(NSFileManager), new];
Id::from_ptr(manager)
})))
FileManager(Arc::new(RwLock::new(unsafe { msg_send_id![class!(NSFileManager), new] })))
}
/// Given a directory/domain combination, will attempt to get the directory that matches.

View file

@ -4,19 +4,19 @@
use block::ConcreteBlock;
use objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, msg_send_id, sel};
use crate::foundation::{id, nil, NSInteger, NSString, NO, YES};
#[derive(Debug)]
pub struct FileSavePanel {
/// The internal Objective C `NSOpenPanel` instance.
pub panel: ShareId<Object>,
pub panel: Id<Object, Shared>,
/// 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`.
pub can_create_directories: bool
@ -35,11 +35,10 @@ impl FileSavePanel {
FileSavePanel {
panel: unsafe {
let cls = class!(NSSavePanel);
let x: id = msg_send![cls, savePanel];
ShareId::from_ptr(x)
msg_send_id![cls, savePanel]
},
delegate: unsafe { ShareId::from_ptr(msg_send![class!(NSObject), new]) },
delegate: unsafe { msg_send_id![class!(NSObject), new] },
can_create_directories: true
}
@ -95,7 +94,7 @@ impl FileSavePanel {
let _: () = msg_send![&*self.panel, runModal];
completion.call((1,));
//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 objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, msg_send_id, sel};
use crate::filesystem::enums::ModalResponse;
use crate::foundation::{id, nil, NSInteger, NSString, NO, NSURL, YES};
@ -19,10 +19,10 @@ use crate::appkit::window::{Window, WindowDelegate};
#[derive(Debug)]
pub struct FileSelectPanel {
/// The internal Objective C `NSOpenPanel` instance.
pub panel: ShareId<Object>,
pub panel: Id<Object, Shared>,
/// 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`.
pub can_choose_files: bool,
@ -54,11 +54,10 @@ impl FileSelectPanel {
FileSelectPanel {
panel: unsafe {
let cls = class!(NSOpenPanel);
let x: id = msg_send![cls, openPanel];
ShareId::from_ptr(x)
msg_send_id![cls, openPanel]
},
delegate: unsafe { ShareId::from_ptr(msg_send![class!(NSObject), new]) },
delegate: unsafe { msg_send_id![class!(NSObject), new] },
can_choose_files: true,
can_choose_directories: false,
@ -148,7 +147,7 @@ impl FileSelectPanel {
});
unsafe {
let _: () = msg_send![&*self.panel, beginWithCompletionHandler:completion.copy()];
let _: () = msg_send![&*self.panel, beginWithCompletionHandler: &*completion.copy()];
}
}
@ -184,7 +183,11 @@ impl FileSelectPanel {
});
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 objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
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
/// still...).
#[derive(Debug)]
pub struct NSArray(pub Id<Object>);
pub struct NSArray(pub Id<Object, Owned>);
impl NSArray {
/// Given a set of `Object`s, creates and retains an `NSArray` that holds them.
pub fn new(objects: &[id]) -> Self {
NSArray(unsafe {
Id::from_ptr(msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
msg_send_id![
class!(NSArray),
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.
/// This handles that case.
pub fn retain(array: id) -> Self {
NSArray(unsafe { Id::from_ptr(array) })
}
/// 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) })
NSArray(unsafe { Id::retain(array).unwrap() })
}
/// 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.
fn from(objects: Vec<&Object>) -> Self {
NSArray(unsafe {
Id::from_ptr(msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
count:objects.len()
])
msg_send_id![
class!(NSArray),
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.
fn from(objects: Vec<id>) -> Self {
NSArray(unsafe {
Id::from_ptr(msg_send![class!(NSArray),
arrayWithObjects:objects.as_ptr()
msg_send_id![
class!(NSArray),
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 {
type Target = Object;

View file

@ -1,6 +1,6 @@
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
/// 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.
@ -8,13 +8,13 @@ use objc_id::Id;
/// 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.
#[derive(Debug)]
pub struct AutoReleasePool(pub Id<Object>);
pub struct AutoReleasePool(pub Id<Object, Owned>);
impl AutoReleasePool {
/// Creates and returns a new `AutoReleasePool`. You need to take care to keep this alive for
/// as long as you need it.
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.

View file

@ -9,7 +9,8 @@ use std::time::Instant;
use lazy_static::lazy_static;
use objc::declare::ClassDecl;
use objc::runtime::{objc_getClass, Class};
use objc::ffi;
use objc::runtime::Class;
lazy_static! {
static ref CLASSES: ClassMap = ClassMap::new();
@ -59,7 +60,7 @@ impl ClassMap {
}
/// 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)
}
@ -67,12 +68,12 @@ impl ClassMap {
///
/// This checks our internal map first, and then calls out to the Objective-C runtime to ensure
/// 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();
if let Some(entry) = (*reader).get(&(class_name, superclass_name)) {
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
// that already exists but we can't see.
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
// 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.
@ -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
/// > the moment.
#[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
F: Fn(&mut ClassDecl) + 'static
{
@ -155,7 +156,7 @@ pub fn load_or_register_class_with_optional_generated_suffix<F>(
subclass_name: &'static str,
should_append_random_subclass_name_suffix: bool,
config: F
) -> *const Class
) -> &'static Class
where
F: Fn(&mut ClassDecl) + 'static
{
@ -188,7 +189,7 @@ where
false => format!("{}_{}", subclass_name, superclass_name)
};
match ClassDecl::new(&objc_subclass_name, unsafe { &*superclass }) {
match ClassDecl::new(&objc_subclass_name, superclass) {
Some(mut decl) => {
config(&mut decl);

View file

@ -5,9 +5,9 @@ use std::slice;
use block::{Block, ConcreteBlock};
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
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.
#[derive(Debug)]
pub struct NSData(pub Id<Object>);
pub struct NSData(pub Id<Object, Owned>);
impl 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;
unsafe {
let obj: id = msg_send![class!(NSData), alloc];
let obj: id = msg_send![obj, initWithBytesNoCopy:bytes_ptr
length:bytes.len()
deallocator:dealloc];
let obj = msg_send_id![class!(NSData), alloc];
let obj = msg_send_id![
obj,
initWithBytesNoCopy: bytes_ptr,
length: bytes.len(),
deallocator: dealloc,
];
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;
unsafe {
let obj: id = msg_send![class!(NSData), dataWithBytes:bytes_ptr length:bytes.len()];
NSData(Id::from_ptr(obj))
let obj = msg_send_id![
class!(NSData),
dataWithBytes: bytes_ptr,
length: bytes.len(),
];
NSData(obj)
}
}
/// Given a (presumably) `NSData`, wraps and retains it.
pub fn retain(data: id) -> Self {
NSData(unsafe { Id::from_ptr(data) })
}
/// 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) })
NSData(unsafe { Id::retain(data).unwrap() })
}
/// 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 {
type Target = Object;

View file

@ -1,15 +1,15 @@
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
use crate::foundation::{id, NSString};
/// A wrapper for `NSMutableDictionary`.
#[derive(Debug)]
pub struct NSMutableDictionary(pub Id<Object>);
pub struct NSMutableDictionary(pub Id<Object, Owned>);
impl Default for 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
/// `unsafe {}` block... so you'll know you're in special territory then.
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.
@ -37,11 +37,6 @@ impl NSMutableDictionary {
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 {

View file

@ -1,9 +1,9 @@
use std::ffi::CStr;
use std::os::raw::c_char;
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
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
/// objects in and out of certain situations (e.g, `UserDefaults`).
#[derive(Debug)]
pub struct NSNumber(pub Id<Object>);
pub struct NSNumber(pub Id<Object, Owned>);
impl NSNumber {
/// 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.
pub fn retain(data: id) -> Self {
NSNumber(unsafe { Id::from_ptr(data) })
}
/// 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) })
NSNumber(unsafe { Id::retain(data).unwrap() })
}
/// Constructs a `numberWithBool` instance of `NSNumber` and retains it.
pub fn bool(value: bool) -> Self {
NSNumber(unsafe {
Id::from_retained_ptr(msg_send![class!(NSNumber), numberWithBool:match value {
msg_send_id![class!(NSNumber), numberWithBool:match value {
true => YES,
false => NO
}])
}]
})
}
/// Constructs a `numberWithInteger` instance of `NSNumber` and retains it.
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.
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
@ -96,10 +90,3 @@ impl NSNumber {
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::{fmt, slice, str};
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
use crate::foundation::{id, to_bool, BOOL, NO, YES};
@ -18,7 +18,7 @@ const UTF8_ENCODING: usize = 4;
#[derive(Debug)]
pub struct NSString<'a> {
/// A reference to the backing `NSString`.
pub objc: Id<Object>,
pub objc: Id<Object, Owned>,
phantom: PhantomData<&'a ()>
}
@ -27,11 +27,12 @@ impl<'a> NSString<'a> {
pub fn new(s: &str) -> Self {
NSString {
objc: unsafe {
let nsstring: *mut Object = msg_send![class!(NSString), alloc];
Id::from_ptr(msg_send![nsstring, initWithBytes:s.as_ptr()
length:s.len()
encoding:UTF8_ENCODING
])
msg_send_id![
msg_send_id![class!(NSString), alloc],
initWithBytes: s.as_ptr(),
length: s.len(),
encoding: UTF8_ENCODING,
]
},
phantom: PhantomData
@ -42,12 +43,14 @@ impl<'a> NSString<'a> {
pub fn no_copy(s: &'a str) -> Self {
NSString {
objc: unsafe {
let nsstring: id = msg_send![class!(NSString), alloc];
Id::from_ptr(msg_send![nsstring, initWithBytesNoCopy:s.as_ptr()
length:s.len()
encoding:UTF8_ENCODING
freeWhenDone:NO
])
let nsstring = msg_send_id![class!(NSString), alloc];
msg_send_id![
nsstring,
initWithBytesNoCopy: s.as_ptr(),
length: s.len(),
encoding: UTF8_ENCODING,
freeWhenDone: NO,
]
},
phantom: PhantomData
@ -58,15 +61,14 @@ impl<'a> NSString<'a> {
/// retain it.
pub fn retain(object: id) -> Self {
NSString {
objc: unsafe { Id::from_ptr(object) },
objc: unsafe { Id::retain(object).unwrap() },
phantom: PhantomData
}
}
/// In some cases, we want to wrap a system-provided NSString without retaining it.
pub fn from_retained(object: id) -> Self {
NSString {
objc: unsafe { Id::from_retained_ptr(object) },
pub fn from_id(objc: Id<Object, Owned>) -> Self {
Self {
objc,
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<'_> {
type Target = Object;

View file

@ -3,9 +3,9 @@ use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::path::PathBuf;
use objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, msg_send_id, sel};
use crate::foundation::{id, nil, NSData, NSString, NSUInteger};
@ -31,7 +31,7 @@ pub use resource_keys::{NSURLFileResource, NSURLResourceKey, NSUbiquitousItemDow
#[derive(Clone, Debug)]
pub struct NSURL<'a> {
/// A reference to the backing `NSURL`.
pub objc: ShareId<Object>,
pub objc: Id<Object, Shared>,
phantom: PhantomData<&'a ()>
}
@ -40,15 +40,7 @@ impl<'a> NSURL<'a> {
/// retain it.
pub fn retain(object: id) -> Self {
NSURL {
objc: unsafe { ShareId::from_ptr(object) },
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) },
objc: unsafe { Id::retain(object).unwrap() },
phantom: PhantomData
}
}
@ -58,7 +50,7 @@ impl<'a> NSURL<'a> {
let url = NSString::new(url);
Self {
objc: unsafe { ShareId::from_ptr(msg_send![class!(NSURL), URLWithString:&*url]) },
objc: unsafe { msg_send_id![class!(NSURL), URLWithString:&*url] },
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.
let bookmark_data = NSData::retain(match relative_to_url {
Some(relative_url) => unsafe {
msg_send![&*self.objc, bookmarkDataWithOptions:opts
includingResourceValuesForKeys:resource_keys
relativeToURL:relative_url
error:nil
msg_send![
&*self.objc,
bookmarkDataWithOptions: opts,
includingResourceValuesForKeys: resource_keys,
relativeToURL: &*relative_url,
error: nil,
]
},
None => unsafe {
msg_send![&*self.objc, bookmarkDataWithOptions:opts
includingResourceValuesForKeys:resource_keys
relativeToURL:nil
error:nil
msg_send![
&*self.objc,
bookmarkDataWithOptions: opts,
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<'_> {
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
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// 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 {
//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;
/// Views get passed these, and can
#[derive(Debug)]
pub struct ViewHandle<T> {
/// A pointer to the Objective-C runtime view controller.
pub objc: ShareId<Object>,
pub objc: Id<Object, Shared>,
_t: std::marker::PhantomData<T>
@ -40,7 +40,7 @@ where
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()
}

View file

@ -1,7 +1,7 @@
use objc::runtime::{Class, Object};
use objc_id::ShareId;
use objc::rc::{Id, Shared};
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;
@ -12,7 +12,7 @@ use core_graphics::{
};
use super::icons::*;
use crate::foundation::{id, NSData, NSString, NO, NSURL, YES};
use crate::foundation::{id, NSData, NSString, NSURL};
use crate::utils::os;
/// 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,
/// and so on.
#[derive(Clone, Debug)]
pub struct Image(pub ShareId<Object>);
pub struct Image(pub Id<Object, Shared>);
impl Image {
fn class() -> &'static Class {
@ -133,7 +133,7 @@ impl Image {
/// Wraps a system-returned image, e.g from QuickLook previews.
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.
@ -141,16 +141,16 @@ impl Image {
let file_path = NSString::new(path);
Image(unsafe {
let alloc: id = msg_send![Self::class(), alloc];
ShareId::from_ptr(msg_send![alloc, initWithContentsOfFile: file_path])
let alloc = msg_send_id![Self::class(), alloc];
msg_send_id![alloc, initWithContentsOfFile: &*file_path]
})
}
#[cfg(target_os = "macos")]
pub fn with_contents_of_url(url: NSURL) -> Self {
Image(unsafe {
let alloc: id = msg_send![Self::class(), alloc];
ShareId::from_ptr(msg_send![alloc, initWithContentsOfURL: url.objc])
let alloc = msg_send_id![Self::class(), alloc];
msg_send_id![alloc, initWithContentsOfURL: &*url.objc]
})
}
@ -160,8 +160,8 @@ impl Image {
let data = NSData::with_slice(data);
Image(unsafe {
let alloc: id = msg_send![Self::class(), alloc];
ShareId::from_ptr(msg_send![alloc, initWithData: data])
let alloc = msg_send_id![Self::class(), alloc];
msg_send_id![alloc, initWithData: &*data]
})
}
@ -172,10 +172,8 @@ impl Image {
#[cfg(target_os = "macos")]
pub fn system_icon(icon: MacSystemIcon) -> Self {
Image(unsafe {
ShareId::from_ptr({
let icon = icon.to_id();
msg_send![Self::class(), imageNamed: icon]
})
msg_send_id![Self::class(), imageNamed: icon]
})
}
@ -192,19 +190,22 @@ impl Image {
#[cfg(target_os = "macos")]
pub fn toolbar_icon(icon: MacSystemIcon, accessibility_description: &str) -> Self {
Image(unsafe {
ShareId::from_ptr(match os::is_minimum_version(11) {
match os::is_minimum_version(11) {
true => {
let icon = NSString::new(icon.to_sfsymbol_str());
let desc = NSString::new(accessibility_description);
msg_send![Self::class(), imageWithSystemSymbolName:&*icon
accessibilityDescription:&*desc]
msg_send_id![
Self::class(),
imageWithSystemSymbolName: &*icon,
accessibilityDescription: &*desc,
]
},
false => {
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;
Image(unsafe {
ShareId::from_ptr(match os::is_minimum_version(min_version) {
match os::is_minimum_version(min_version) {
true => {
let icon = NSString::new(symbol.to_str());
let desc = NSString::new(accessibility_description);
msg_send![Self::class(), imageWithSystemSymbolName:&*icon
accessibilityDescription:&*desc]
msg_send_id![
Self::class(),
imageWithSystemSymbolName:&*icon,
accessibilityDescription:&*desc,
]
},
false => {
@ -241,7 +245,7 @@ impl Image {
#[cfg(all(feature = "uikit", not(feature = "appkit")))]
panic!("SFSymbols are only supported on macOS 11.0 and up.");
}
})
}
})
}
@ -276,20 +280,17 @@ impl Image {
let _: () = msg_send![class!(NSGraphicsContext), restoreGraphicsState];
match result {
true => YES,
false => NO
}
Bool::new(result)
});
let block = block.copy();
Image(unsafe {
let img: id = msg_send![Self::class(), imageWithSize:target_frame.size
flipped:YES
drawingHandler:block
];
ShareId::from_ptr(img)
msg_send_id![
Self::class(),
imageWithSize: target_frame.size,
flipped: Bool::YES,
drawingHandler: &*block,
]
})
}
}

View file

@ -1,6 +1,8 @@
use core_foundation::base::TCFType;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, msg_send_id, sel};
use crate::color::Color;
use crate::foundation::{id, nil, NSArray, NSString, NO, YES};
@ -31,7 +33,7 @@ mod icons;
pub use icons::*;
/// 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 {
let view: id = msg_send![registration_fn(), new];
@ -140,7 +142,7 @@ impl ImageView {
#[cfg(feature = "autolayout")]
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)
}
@ -149,7 +151,7 @@ impl ImageView {
/// Call this to set the background color for the backing layer.
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
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 _: () = 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
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// 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 {})
}

View file

@ -1,79 +1,71 @@
use objc::runtime::{Class, Object, Sel, BOOL};
use objc::{msg_send, sel, sel_impl};
use objc::rc::{Id, Owned};
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::utils::load;
/// 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 s = NSString::retain(unsafe { msg_send![this, stringValue] });
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 s = NSString::retain(unsafe { msg_send![this, stringValue] });
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 s = NSString::retain(unsafe { msg_send![this, stringValue] });
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 s = NSString::retain(unsafe { msg_send![this, stringValue] });
match view.text_should_begin_editing(s.to_str()) {
true => YES,
false => NO
}
Bool::new(view.text_should_begin_editing(s.to_str()))
}
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 s = NSString::retain(unsafe { msg_send![this, stringValue] });
match view.text_should_end_editing(s.to_str()) {
true => YES,
false => NO
}
Bool::new(view.text_should_end_editing(s.to_str()))
}
/// 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
/// 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 {})
}
/// Injects an `NSTextField` subclass, with some callback and pointer ivars for what we
/// 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 {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move.
decl.add_ivar::<usize>(TEXTFIELD_DELEGATE_PTR);
decl.add_method(
sel!(textDidEndEditing:),
text_did_end_editing::<T> as extern "C" fn(&mut Object, _, _)
);
decl.add_method(sel!(textDidEndEditing:), text_did_end_editing::<T> as extern "C" fn(_, _, _));
decl.add_method(
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(
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(
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.
use core_foundation::base::TCFType;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object};
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, sel};
use crate::color::Color;
use crate::control::Control;
@ -76,7 +78,7 @@ pub use traits::TextFieldDelegate;
pub(crate) static TEXTFIELD_DELEGATE_PTR: &str = "rstTextFieldDelegatePtr";
/// 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 {
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.
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
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 _: () = msg_send![layer, setBackgroundColor: cg];
});

View file

@ -1,71 +1,64 @@
use std::sync::Once;
use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel, BOOL};
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::runtime::{Bool, Class, Object, Sel};
use objc::{class, msg_send, sel};
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::utils::load;
/// 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 s = NSString::retain(unsafe { msg_send![this, text] });
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 s = NSString::retain(unsafe { msg_send![this, text] });
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 s = NSString::retain(unsafe { msg_send![this, text] });
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 s = NSString::retain(unsafe { msg_send![this, text] });
match view.text_should_begin_editing(s.to_str()) {
true => YES,
false => NO
}
Bool::new(view.text_should_begin_editing(s.to_str()))
}
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 s = NSString::retain(unsafe { msg_send![this, text] });
match view.text_should_end_editing(s.to_str()) {
true => YES,
false => NO
}
Bool::new(view.text_should_end_editing(s.to_str()))
}
/// 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
/// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_view_class() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();
INIT.call_once(|| unsafe {
let superclass = class!(UITextField);
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
/// 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 {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move.
@ -73,23 +66,23 @@ pub(crate) fn register_view_class_with_delegate<T: TextFieldDelegate>(instance:
decl.add_method(
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(
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(
sel!(textFieldDidChangeSelection:),
text_did_change::<T> as extern "C" fn(&mut Object, _, _)
text_did_change::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
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(
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 objc::rc::{Id, Owned, Shared};
use objc::runtime::{Class, Object, Sel};
use objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, msg_send_id, sel};
use crate::foundation::{id, load_or_register_class};
use crate::utils::load;
@ -46,7 +46,7 @@ impl fmt::Debug for Action {
#[derive(Debug)]
pub struct TargetActionHandler {
action: Box<Action>,
invoker: ShareId<Object>
invoker: Id<Object, Shared>
}
impl TargetActionHandler {
@ -56,18 +56,16 @@ impl TargetActionHandler {
let ptr = Box::into_raw(block);
let invoker = unsafe {
ShareId::from_ptr({
let invoker: id = msg_send![register_invoker_class::<F>(), alloc];
let invoker: id = msg_send![invoker, init];
(&mut *invoker).set_ivar(ACTION_CALLBACK_PTR, ptr as usize);
let invoker = msg_send_id![register_invoker_class::<F>(), alloc];
let mut invoker: Id<Object, Owned> = msg_send_id![invoker, init];
invoker.set_ivar(ACTION_CALLBACK_PTR, ptr as usize);
let _: () = msg_send![control, setAction: sel!(perform:)];
let _: () = msg_send![control, setTarget: invoker];
invoker
})
let _: () = msg_send![control, setTarget: &*invoker];
invoker.into()
};
TargetActionHandler {
invoker: invoker,
invoker,
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
/// on drop. We handle the heap copy on the Rust side, so setting the block
/// 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 {
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 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::utils::properties::ObjcProperty;
@ -35,30 +37,26 @@ use crate::utils::properties::ObjcProperty;
#[derive(Clone, Debug)]
pub struct Layer {
/// The underlying layer pointer.
pub objc: ObjcProperty
pub objc: Id<Object, Shared>
}
impl Layer {
/// Creates a new `CALayer` and retains it.
pub fn new() -> Self {
Layer {
objc: ObjcProperty::retain(unsafe { msg_send![class!(CALayer), new] })
objc: unsafe { msg_send_id![class!(CALayer), new] }
}
}
/// Wraps an existing (already retained) `CALayer`.
pub fn wrap(layer: id) -> Self {
Layer {
objc: ObjcProperty::from_retained(layer)
}
/// Wraps an existing `CALayer`.
pub fn from_id(objc: Id<Object, Shared>) -> Self {
Layer { objc }
}
/// Sets the corner radius (for all four corners).
///
/// Note that for performance sensitive contexts, you might want to apply a mask instead.
pub fn set_corner_radius(&self, radius: f64) {
self.objc.with_mut(|obj| unsafe {
let _: () = msg_send![obj, setCornerRadius: radius as CGFloat];
});
let _: () = unsafe { msg_send![&self.objc, setCornerRadius: radius as CGFloat] };
}
}

View file

@ -1,19 +1,19 @@
use core_graphics::base::CGFloat;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, msg_send_id, sel};
use crate::foundation::id;
/// A wrapper for an animation proxy object in Cocoa that supports basic animations.
#[derive(Clone, Debug)]
pub struct LayoutConstraintAnimatorProxy(pub ShareId<Object>);
pub struct LayoutConstraintAnimatorProxy(pub Id<Object, Shared>);
impl LayoutConstraintAnimatorProxy {
/// Wraps and returns a proxy for animation of layout constraint values.
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.
@ -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 objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, sel};
use crate::foundation::{id, NO, YES};
@ -20,7 +20,7 @@ use super::LayoutConstraintAnimatorProxy;
pub struct LayoutConstraint {
/// A shared pointer to the underlying view. Provided your view isn't dropped, this will always
/// be valid.
pub constraint: ShareId<Object>,
pub constraint: Id<Object, Shared>,
/// The offset used in computing this constraint.
pub offset: f64,
@ -43,8 +43,7 @@ impl LayoutConstraint {
LayoutConstraint {
#[cfg(all(feature = "appkit", target_os = "macos"))]
animator: LayoutConstraintAnimatorProxy::new(object),
constraint: unsafe { ShareId::from_ptr(object) },
constraint: unsafe { Id::retain(object).unwrap() },
offset: 0.0,
multiplier: 0.0,
priority: 0.0
@ -94,7 +93,7 @@ impl LayoutConstraint {
/// 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
// 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
// able to clone these and pass them around... while also getting certain references to
// them.

View file

@ -1,8 +1,8 @@
use core_graphics::base::CGFloat;
use objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, msg_send_id, sel};
use crate::foundation::{id, nil, NSInteger};
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
/// factory/helper for creating `LayoutConstraint` objects based on your views.
#[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`
/// values for how a given view should layout.
@ -22,10 +22,10 @@ pub enum LayoutAnchorDimension {
Uninitialized,
/// Represents a Width anchor.
Width(ShareId<Object>),
Width(Id<Object, Shared>),
/// Represents a Height anchor.
Height(ShareId<Object>)
Height(Id<Object, Shared>)
}
impl Default for LayoutAnchorDimension {
@ -38,12 +38,12 @@ impl Default for LayoutAnchorDimension {
impl LayoutAnchorDimension {
/// Given a view, returns an anchor for the width anchor.
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.
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.
@ -51,7 +51,7 @@ impl LayoutAnchorDimension {
if let Self::Width(obj) | Self::Height(obj) = self {
return LayoutConstraint::new(unsafe {
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 {
return LayoutConstraint::new(unsafe {
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 {
return LayoutConstraint::new(unsafe {
let value = constant as CGFloat;
msg_send![*obj, constraintLessThanOrEqualToConstant: value]
msg_send![obj, constraintLessThanOrEqualToConstant: value]
});
}
@ -87,7 +87,7 @@ impl LayoutAnchorDimension {
/// wrong.
fn constraint_with<F>(&self, anchor_to: &LayoutAnchorDimension, handler: F) -> LayoutConstraint
where
F: Fn(&ShareId<Object>, &ShareId<Object>) -> id
F: Fn(&Id<Object, Shared>, &Id<Object, Shared>) -> id
{
match (self, anchor_to) {
(Self::Width(from), Self::Width(to))
@ -112,21 +112,21 @@ impl LayoutAnchorDimension {
/// Return a constraint equal to another dimension anchor.
pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorDimension) -> LayoutConstraint {
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.
pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorDimension) -> LayoutConstraint {
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.
pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorDimension) -> LayoutConstraint {
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::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, msg_send_id, sel};
use crate::foundation::id;
use crate::layout::constraint::LayoutConstraint;
@ -16,19 +16,19 @@ pub enum LayoutAnchorX {
Uninitialized,
/// Represents a leading anchor; side depends on system orientation.
Leading(ShareId<Object>),
Leading(Id<Object, Shared>),
/// Represents a left anchor.
Left(ShareId<Object>),
Left(Id<Object, Shared>),
/// Represents a trailing anchor; side depends on system orientation.
Trailing(ShareId<Object>),
Trailing(Id<Object, Shared>),
/// Represents a right anchor.
Right(ShareId<Object>),
Right(Id<Object, Shared>),
/// Represents a center anchor on the X axis.
Center(ShareId<Object>)
Center(Id<Object, Shared>)
}
impl Default for LayoutAnchorX {
@ -41,27 +41,27 @@ impl Default for LayoutAnchorX {
impl LayoutAnchorX {
/// Given a view, returns an anchor for the leading anchor.
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.
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.
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.
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.
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
@ -69,7 +69,7 @@ impl LayoutAnchorX {
/// wrong.
fn constraint_with<F>(&self, anchor_to: &LayoutAnchorX, handler: F) -> LayoutConstraint
where
F: Fn(&ShareId<Object>, &ShareId<Object>) -> id
F: Fn(&Id<Object, Shared>, &Id<Object, Shared>) -> id
{
match (self, anchor_to) {
// 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.
pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint {
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.
pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint {
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.
pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorX) -> LayoutConstraint {
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::layout::{LayoutAnchorDimension, LayoutAnchorX, LayoutAnchorY};

View file

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

View file

@ -1,6 +1,6 @@
use objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, msg_send_id, sel};
use crate::foundation::id;
use crate::layout::constraint::LayoutConstraint;
@ -13,13 +13,13 @@ pub enum LayoutAnchorY {
Uninitialized,
/// Represents a top anchor.
Top(ShareId<Object>),
Top(Id<Object, Shared>),
/// Represents a bottom anchor.
Bottom(ShareId<Object>),
Bottom(Id<Object, Shared>),
/// Represents a center anchor for the Y axis.
Center(ShareId<Object>)
Center(Id<Object, Shared>)
}
impl Default for LayoutAnchorY {
@ -31,17 +31,17 @@ impl Default for LayoutAnchorY {
impl LayoutAnchorY {
/// Given a view, returns an anchor for the top anchor.
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.
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.
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
@ -49,7 +49,7 @@ impl LayoutAnchorY {
/// wrong.
fn constraint_with<F>(&self, anchor_to: &LayoutAnchorY, handler: F) -> LayoutConstraint
where
F: Fn(&ShareId<Object>, &ShareId<Object>) -> id
F: Fn(&Id<Object, Shared>, &Id<Object, Shared>) -> id
{
match (self, anchor_to) {
(Self::Top(from), Self::Top(to))
@ -79,21 +79,21 @@ impl LayoutAnchorY {
/// Return a constraint equal to another vertical anchor.
pub fn constraint_equal_to(&self, anchor_to: &LayoutAnchorY) -> LayoutConstraint {
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.
pub fn constraint_greater_than_or_equal_to(&self, anchor_to: &LayoutAnchorY) -> LayoutConstraint {
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.
pub fn constraint_less_than_or_equal_to(&self, anchor_to: &LayoutAnchorY) -> LayoutConstraint {
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(docsrs, deny(rustdoc::broken_intra_doc_links))]
#![cfg_attr(docsrs, feature(doc_cfg))]
// Temporary!
#![allow(deprecated)]
// Copyright 2019+, the Cacao developers.
// 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.

View file

@ -1,6 +1,6 @@
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
use block::ConcreteBlock;
@ -39,7 +39,7 @@ impl From<RowActionStyle> for NSUInteger {
/// on a ListViewRow. You return this from the appropriate delegate method,
/// and the system will handle displaying the necessary pieces for you.
#[derive(Debug)]
pub struct RowAction(pub Id<Object>);
pub struct RowAction(pub Id<Object, Owned>);
impl RowAction {
/// Creates and returns a new `RowAction`. You'd use this handler to
@ -56,7 +56,7 @@ impl RowAction {
{
let title = NSString::new(title);
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);
});
@ -65,10 +65,12 @@ impl RowAction {
RowAction(unsafe {
let cls = class!(NSTableViewRowAction);
Id::from_ptr(msg_send![cls, rowActionWithStyle:style
title:&*title
handler:block
])
msg_send_id![
cls,
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
//! color, and enforcing layer backing by default.
use objc::runtime::{Class, Object, Sel, BOOL};
use objc::{msg_send, sel, sel_impl};
use objc_id::Id;
use objc::rc::{Id, Owned};
use objc::runtime::{Bool, Class, Object, Sel};
use objc::{msg_send, sel};
use crate::appkit::menu::Menu;
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::utils::load;
@ -81,10 +81,10 @@ extern "C" fn select_row<T: ListViewDelegate>(
_: Sel,
_table_view: id,
item: NSInteger
) -> BOOL {
) -> Bool {
let view = load::<T>(this, LISTVIEW_DELEGATE_PTR);
view.item_selected(item as usize);
YES
Bool::YES
}*/
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.
extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> BOOL {
return YES;
extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> Bool {
return Bool::YES;
}
/// Called when a drag/drop operation has entered this view.
extern "C" fn dragging_entered<T: ListViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = load::<T>(this, LISTVIEW_DELEGATE_PTR);
view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) }
info: unsafe { Id::retain(info).unwrap() }
})
.into()
}
/// 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);
match view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
Bool::new(view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::retain(info).unwrap() }
}))
}
/// 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);
match view.perform_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
Bool::new(view.perform_drag_operation(DragInfo {
info: unsafe { Id::retain(info).unwrap() }
}))
}
/// 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);
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);
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
/// `UITableView` semantics; if `NSTableView`'s multi column behavior is needed, then it can
/// 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 {})
}
@ -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
/// `UITableView` semantics; if `NSTableView`'s multi column behavior is needed, then it can
/// 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 {
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
decl.add_method(
sel!(numberOfRowsInTableView:),
number_of_items::<T> as extern "C" fn(&Object, _, id) -> NSInteger
number_of_items::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(
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(
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(
sel!(tableViewSelectionDidChange:),
selection_did_change::<T> as extern "C" fn(&Object, _, id)
selection_did_change::<T> as extern "C" fn(_, _, _)
);
decl.add_method(
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
// whole delegate run, since things are fast enough nowadays to just replace the entire
// menu.
decl.add_method(
sel!(menuNeedsUpdate:),
menu_needs_update::<T> as extern "C" fn(&Object, _, id)
);
decl.add_method(sel!(menuNeedsUpdate:), menu_needs_update::<T> as extern "C" fn(_, _, _));
// Drag and drop operations (e.g, accepting files)
decl.add_method(
sel!(draggingEntered:),
dragging_entered::<T> as extern "C" fn(&mut Object, _, _) -> NSUInteger
);
decl.add_method(sel!(draggingEntered:), dragging_entered::<T> as extern "C" fn(_, _, _) -> _);
decl.add_method(
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(
sel!(performDragOperation:),
perform_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL
perform_drag_operation::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(
sel!(concludeDragOperation:),
conclude_drag_operation::<T> as extern "C" fn(&mut Object, _, _)
);
decl.add_method(
sel!(draggingExited:),
dragging_exited::<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(_, _, _));
})
}

View file

@ -44,10 +44,12 @@
use std::collections::HashMap;
use core_foundation::base::TCFType;
use core_graphics::base::CGFloat;
use objc::rc::{Id, Owned, Shared};
use objc::runtime::{Class, Object};
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, msg_send_id, sel};
use crate::color::Color;
use crate::foundation::{id, nil, NSArray, NSInteger, NSString, NSUInteger, NO, YES};
@ -98,7 +100,7 @@ use std::cell::RefCell;
use std::rc::Rc;
/// 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 {
// 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.
@ -439,7 +441,7 @@ impl<T> ListView<T> {
pub fn set_background_color<C: AsRef<Color>>(&self, color: C) {
// @TODO: This is wrong.
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 _: () = 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.
pub fn select_row_indexes(&self, indexes: &[usize], extends_existing: bool) {
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 {
let _: () = msg_send![index_set, addIndex: index];
let _: () = msg_send![&mut index_set, addIndex: index];
}
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,
false => NO
}];
@ -567,23 +569,24 @@ impl<T> ListView<T> {
pub fn insert_rows(&self, indexes: &[usize], animation: RowAnimation) {
#[cfg(feature = "appkit")]
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 {
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();
// We need to temporarily retain this; it can drop after the underlying NSTableView
// 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
// an explanation.
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]) {
#[cfg(feature = "appkit")]
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 {
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 = ShareId::from_ptr(ye);
let y: Id<Object, Shared> = msg_send_id![class!(NSIndexSet), indexSetWithIndex:0];
// Must use `get` to avoid a double lock.
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) {
#[cfg(feature = "appkit")]
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 {
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();
// We need to temporarily retain this; it can drop after the underlying NSTableView
// 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| {
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
//! color, and enforcing layer backing by default.
use objc::runtime::{Class, Object, Sel, BOOL};
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::rc::{Id, Owned};
use objc::runtime::{Bool, Class, Object, Sel};
use objc::{class, msg_send, sel};
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::utils::load;
/// 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 {
return YES;
extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> Bool {
return Bool::YES;
}
/// Called when a drag/drop operation has entered this view.
extern "C" fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = load::<T>(this, LISTVIEW_ROW_DELEGATE_PTR);
view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) }
info: unsafe { Id::retain(info).unwrap() }
})
.into()
}
/// 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);
match view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
Bool::new(view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::retain(info).unwrap() }
}))
}
/// 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);
match view.perform_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
Bool::new(view.perform_drag_operation(DragInfo {
info: unsafe { Id::retain(info).unwrap() }
}))
}
/// 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);
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);
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
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// 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 {
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
/// 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 {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move.
decl.add_ivar::<usize>(LISTVIEW_ROW_DELEGATE_PTR);
decl.add_ivar::<id>(BACKGROUND_COLOR);
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL);
decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(&Object, _));
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(_, _));
// Drag and drop operations (e.g, accepting files)
decl.add_method(
sel!(draggingEntered:),
dragging_entered::<T> as extern "C" fn(&mut Object, _, _) -> NSUInteger
);
decl.add_method(sel!(draggingEntered:), dragging_entered::<T> as extern "C" fn(_, _, _) -> _);
decl.add_method(
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(
sel!(performDragOperation:),
perform_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL
perform_drag_operation::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(
sel!(concludeDragOperation:),
conclude_drag_operation::<T> as extern "C" fn(&mut Object, _, _)
);
decl.add_method(
sel!(draggingExited:),
dragging_exited::<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(_, _, _));
// 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::rc::Rc;
use objc::rc::{Id, Owned, Shared};
use objc::runtime::{Class, Object};
use objc::{class, msg_send, sel, sel_impl};
use objc_id::{Id, ShareId};
use objc::{class, msg_send, sel};
use crate::color::Color;
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";
/// 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 {
let view: id = msg_send![registration_fn(), new];
@ -442,7 +442,8 @@ impl<T> ListViewRow<T> {
let color: id = color.as_ref().into();
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::runtime::{Class, Object, Sel, BOOL};
use objc::{class, sel, sel_impl};
use objc_id::Id;
use objc::{class, sel};
use objc::rc::{Id, Owned};
use crate::dragdrop::DragInfo;
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
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// 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 {})
}
/// Injects an `NSView` subclass, with some callback and pointer ivars for what we
/// 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 {
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
})

View file

@ -1,28 +1,28 @@
//! A lightweight wrapper over some networking components, like `NSURLRequest` and co.
//!
use objc::rc::{Id, Shared};
use objc::runtime::Object;
/// 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
/// 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 objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, sel};
use crate::foundation::{id, NSString};
/// A wrapper around `NSURLRequest`.
#[derive(Debug)]
pub struct URLRequest(ShareId<Object>);
pub struct URLRequest(Id<Object, Shared>);
impl URLRequest {
/// Wraps and retains an `NSURLRequest`.
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`.
pub fn absolute_url(&self) -> String {
NSString::from_retained(unsafe {
NSString::retain(unsafe {
let url: id = msg_send![&*self.0, URL];
msg_send![url, absoluteString]
})
@ -32,7 +32,7 @@ impl URLRequest {
#[cfg(test)]
mod tests {
use objc::{class, msg_send, sel, sel_impl};
use objc::{class, msg_send, sel};
use crate::foundation::{id, NSString};
use crate::networking::URLRequest;

View file

@ -16,9 +16,9 @@
//use std::collections::HashMap;
//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_id::ShareId;
//use objc::rc::{Id, Shared};
mod name;
pub use name::NotificationName;
@ -30,7 +30,7 @@ pub use traits::Dispatcher;
pub static ref DefaultNotificationCenter: NotificationCenter = {
NotificationCenter {
objc: unsafe {
ShareId::from_ptr(msg_send![class!(NSNotificationCenter), defaultCenter])
msg_send_id![class!(NSNotificationCenter), defaultCenter]
},
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.
//#[derive(Debug)]
//pub struct NotificationCenter {
// pub objc: ShareId<Object>,
// pub objc: Id<Object, Shared>,
//pub subscribers: Mutex<HashMap<String, Vec<Dispatcher>>>
//}
@ -52,7 +52,7 @@ pub use traits::Dispatcher;
fn default() -> Self {
NotificationCenter {
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 objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, msg_send_id, sel};
use url::Url;
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.
#[derive(Debug)]
pub struct Pasteboard(pub ShareId<Object>);
pub struct Pasteboard(pub Id<Object, Shared>);
impl Default for Pasteboard {
/// Returns the default system pasteboard (the "general" pasteboard).
fn default() -> Self {
Pasteboard(unsafe { ShareId::from_ptr(msg_send![class!(NSPasteboard), generalPasteboard]) })
Pasteboard(unsafe { msg_send_id![class!(NSPasteboard), generalPasteboard] })
}
}
impl Pasteboard {
/// Used internally for wrapping a Pasteboard returned from operations (say, drag and drop).
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.
pub fn named(name: PasteboardName) -> Self {
Pasteboard(unsafe {
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
/// respect to other pasteboards in the system.
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.
@ -63,7 +63,7 @@ impl Pasteboard {
let ptype: NSString = PasteboardType::String.into();
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 {
let class: id = msg_send![class!(NSURL), 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.
// 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 objc::rc::{Id, Shared};
use objc::runtime::{Class, Object};
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, sel};
use crate::color::Color;
use crate::foundation::{id, nil, NSUInteger, NO, YES};

View file

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

View file

@ -1,8 +1,8 @@
use std::path::Path;
use objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, msg_send_id, sel};
use block::ConcreteBlock;
@ -14,12 +14,12 @@ mod config;
pub use config::{ThumbnailConfig, ThumbnailQuality};
#[derive(Debug)]
pub struct ThumbnailGenerator(pub ShareId<Object>);
pub struct ThumbnailGenerator(pub Id<Object, Shared>);
impl ThumbnailGenerator {
/// Returns the global shared, wrapped, QLThumbnailGenerator.
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
@ -48,8 +48,11 @@ impl ThumbnailGenerator {
let request = config.to_request(path);
unsafe {
let _: () = msg_send![&*self.0, generateRepresentationsForRequest:request
updateHandler:block];
let _: () = msg_send![
&*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
//! color, and enforcing layer backing by default.
use objc::runtime::{Class, Object, Sel, BOOL};
use objc::{sel, sel_impl};
use objc_id::Id;
use objc::rc::{Id, Owned};
use objc::runtime::{Bool, Class, Object, Sel};
use objc::sel;
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::utils::load;
/// 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 {
return YES;
extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> Bool {
return Bool::YES;
}
/// Called when a drag/drop operation has entered this view.
extern "C" fn dragging_entered<T: ScrollViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = load::<T>(this, SCROLLVIEW_DELEGATE_PTR);
view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) }
info: unsafe { Id::retain(info).unwrap() }
})
.into()
}
/// 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);
match view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
Bool::new(view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::retain(info).unwrap() }
}))
}
/// 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);
match view.perform_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
Bool::new(view.perform_drag_operation(DragInfo {
info: unsafe { Id::retain(info).unwrap() }
}))
}
/// 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);
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);
view.dragging_exited(DragInfo {
info: unsafe { Id::from_ptr(info) }
info: unsafe { Id::retain(info).unwrap() }
});
}
/// 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 {})
}
/// Injects an `NSView` subclass, with some callback and pointer ivars for what we
/// 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 {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move.
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)
decl.add_method(
sel!(draggingEntered:),
dragging_entered::<T> as extern "C" fn(&mut Object, _, _) -> NSUInteger
);
decl.add_method(sel!(draggingEntered:), dragging_entered::<T> as extern "C" fn(_, _, _) -> _);
decl.add_method(
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(
sel!(performDragOperation:),
perform_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL
perform_drag_operation::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(
sel!(concludeDragOperation:),
conclude_drag_operation::<T> as extern "C" fn(&mut Object, _, _)
);
decl.add_method(
sel!(draggingExited:),
dragging_exited::<T> as extern "C" fn(&mut Object, _, _)
conclude_drag_operation::<T> as extern "C" fn(_, _, _)
);
})
}

View file

@ -42,9 +42,11 @@
//!
//! 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::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, sel};
use crate::color::Color;
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";
/// 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 {
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) {
// @TODO: This is wrong.
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 _: () = msg_send![layer, setBackgroundColor: color];
});

View file

@ -10,17 +10,16 @@
use std::sync::Once;
use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel, BOOL};
use objc::{class, sel, sel_impl};
use objc_id::Id;
use objc::runtime::{Bool, Class, Object, Sel};
use objc::{class, sel};
use crate::foundation::{id, NSUInteger, NO, YES};
use crate::foundation::{id, NSUInteger};
use crate::scrollview::{ScrollViewDelegate, SCROLLVIEW_DELEGATE_PTR};
use crate::utils::load;
/// 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 {
return YES;
extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> Bool {
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.
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);
match view.prepare_for_drag_operation(DragInfo {
Bool::new(view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
}))
}
/// 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);
match view.perform_drag_operation(DragInfo {
Bool::new(view.perform_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
}))
}
/// 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.
pub(crate) fn register_scrollview_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_scrollview_class() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();
INIT.call_once(|| unsafe {
let superclass = class!(UIScrollView);
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
/// need to do.
pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();
INIT.call_once(|| unsafe {
@ -105,34 +98,34 @@ pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -
// move.
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)
decl.add_method(
sel!(draggingEntered:),
dragging_entered::<T> as extern "C" fn(&mut Object, _, _) -> NSUInteger
dragging_entered::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(
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(
sel!(performDragOperation:),
perform_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL
perform_drag_operation::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(
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, _, _)
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.
use core_graphics::geometry::CGRect;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, msg_send_id, sel};
use crate::control::Control;
use crate::foundation::{id, load_or_register_class, nil, NSInteger, NSString, NO, YES};
@ -142,7 +142,7 @@ impl Select {
/// I cannot stress this enough.
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.
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);
self.handler = Some(handler);
}
@ -161,7 +161,7 @@ impl Select {
pub fn add_item(&self, title: &str) {
self.objc.with_mut(|obj| unsafe {
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
/// 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 {})
}

View file

@ -1,9 +1,9 @@
//! A wrapper for NSSwitch. Currently the epitome of jank - if you're poking around here, expect
//! that this will change at some point.
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, msg_send_id, sel};
use crate::foundation::{id, load_or_register_class, nil, NSString, NO};
use crate::invoker::TargetActionHandler;
@ -69,7 +69,7 @@ impl Switch {
let title = NSString::new(text);
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")]
let _: () = msg_send![button, setTranslatesAutoresizingMaskIntoConstraints: NO];
@ -132,7 +132,7 @@ impl Switch {
/// best just to message pass or something.
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.
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);
self.handler = Some(handler);
}
@ -172,6 +172,6 @@ impl Drop for Switch {
/// Registers an `NSButton` subclass, and configures it to hold some ivars
/// 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 {})
}

View file

@ -3,14 +3,13 @@ use std::ops::{Deref, DerefMut, Range};
use std::os::raw::c_char;
use std::{fmt, slice, str};
use core_foundation::base::CFRange;
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
use crate::color::Color;
use crate::foundation::{id, to_bool, NSString, BOOL, NO, YES};
use crate::utils::CFRange;
use super::Font;
@ -22,7 +21,7 @@ extern "C" {
/// A wrapper around `NSMutableAttributedString`, which can be used for more complex text
/// rendering.
///
pub struct AttributedString(pub Id<Object>);
pub struct AttributedString(pub Id<Object, Owned>);
impl AttributedString {
/// Creates a blank AttributedString. Internally, this allocates an
@ -31,8 +30,8 @@ impl AttributedString {
let text = NSString::no_copy(value);
Self(unsafe {
let alloc: id = msg_send![class!(NSMutableAttributedString), alloc];
Id::from_ptr(msg_send![alloc, initWithString:&*text])
let alloc = msg_send_id![class!(NSMutableAttributedString), alloc];
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
/// who might need it.
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.
@ -49,19 +48,25 @@ impl AttributedString {
let range = CFRange::init(range.start, range.end);
unsafe {
let _: () = msg_send![&*self.0, addAttribute:NSForegroundColorAttributeName
value:color
range:range
let _: () = msg_send![
&*self.0,
addAttribute: NSForegroundColorAttributeName,
value: color,
range: range,
];
}
}
/// Set the font for the specified range.
pub fn set_font(&mut self, font: Font, range: Range<isize>) {
let range = CFRange::init(range.start, range.end);
unsafe {
let _: () = msg_send![&*self.0, addAttribute:NSFontAttributeName
value:&*font
range:range
let _: () = msg_send![
&*self.0,
addAttribute: NSFontAttributeName,
value: &*font,
range: range,
];
}
}
@ -69,7 +74,7 @@ impl AttributedString {
impl fmt::Display for AttributedString {
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())
}
@ -77,19 +82,12 @@ impl fmt::Display for AttributedString {
impl fmt::Debug for AttributedString {
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()
}
}
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 {
type Target = Object;

View file

@ -4,9 +4,9 @@ use std::ops::Deref;
use core_graphics::base::CGFloat;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object};
use objc::{class, msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{class, msg_send, msg_send_id, sel};
use crate::foundation::{id, nil, NSArray, NSString, NO, YES};
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
/// appearance and size.
#[derive(Clone, Debug)]
pub struct Font(pub ShareId<Object>);
pub struct Font(pub Id<Object, Shared>);
impl Default for Font {
/// Returns the default `labelFont` on macOS.
@ -23,10 +23,10 @@ impl Default for Font {
let default_size: id = unsafe { msg_send![cls, labelFontSize] };
#[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")))]
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
}
}
@ -44,14 +44,14 @@ impl Font {
pub fn system(size: f64) -> Self {
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.
pub fn bold_system(size: f64) -> Self {
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
@ -67,9 +67,9 @@ impl Font {
let weight = weight as CGFloat;
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 {
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
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// 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 {})
}
/// Injects an `NSTextField` subclass, with some callback and pointer ivars for what we
/// 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 {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move.

View file

@ -43,9 +43,11 @@
//!
//! 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::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, msg_send_id, sel};
use crate::color::Color;
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";
/// 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 {
#[cfg(feature = "appkit")]
let view: id = {
@ -249,7 +251,7 @@ impl Label {
#[cfg(feature = "autolayout")]
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)
}
@ -324,7 +326,7 @@ impl<T> Label<T> {
// @TODO: This is wrong.
// Needs to set ivar and such, akin to View.
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 _: () = msg_send![layer, setBackgroundColor: color];
});

View file

@ -2,8 +2,7 @@ use std::sync::Once;
use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel, BOOL};
use objc::{class, sel, sel_impl};
use objc_id::Id;
use objc::{class, sel};
use crate::foundation::{id, NSUInteger, NO, YES};
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
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_view_class() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();
INIT.call_once(|| unsafe {
let superclass = class!(UILabel);
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
/// need to do.
pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();
INIT.call_once(|| unsafe {
@ -38,8 +37,8 @@ pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> *const Cl
// move.
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;
/// 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;
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
//! for potential future use.
use objc::runtime::{Class, Object, Sel};
use objc::{sel, sel_impl};
use objc::rc::Id;
use objc::runtime::{Bool, Class, Object, Sel};
use objc::sel;
//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::scene::{SceneConnectionOptions, SceneSession};
@ -27,37 +28,39 @@ fn app<T>(this: &Object) -> &T {
}
/// 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();
YES
Bool::YES
}
extern "C" fn configuration_for_scene_session<T: AppDelegate>(this: &Object, _: Sel, _: id, session: id, opts: id) -> id {
Id::autorelease_return(
app::<T>(this)
.config_for_scene_session(SceneSession::with(session), SceneConnectionOptions::with(opts))
.into_inner()
.0
)
}
/// Registers an `NSObject` application delegate, and configures it for the various callbacks and
/// pointers we need to have.
pub(crate) fn register_app_delegate_class<T: AppDelegate>() -> *const Class {
pub(crate) fn register_app_delegate_class<T: AppDelegate>() -> &'static Class {
let should_generate_suffix = false;
load_or_register_class_with_optional_generated_suffix("NSObject", "RSTAppDelegate", should_generate_suffix, |decl| unsafe {
// Launching Applications
decl.add_method(
sel!(application:didFinishLaunchingWithOptions:),
did_finish_launching::<T> as extern "C" fn(&Object, _, _, id) -> BOOL
did_finish_launching::<T> as extern "C" fn(_, _, _, _) -> _
);
// Scenes
decl.add_method(
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(
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 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::notification_center::Dispatcher;

View file

@ -1,6 +1,6 @@
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
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.
#[derive(Debug)]
pub struct SceneConfig(Id<Object>);
pub struct SceneConfig(pub Id<Object, Owned>);
impl SceneConfig {
/// 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 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.
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::{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::uikit::app::SCENE_DELEGATE_VENDOR;
@ -9,9 +9,9 @@ use crate::utils::load;
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 {
*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 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
/// 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;
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);
// 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
decl.add_method(
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 objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, sel};
use crate::foundation::id;
use crate::geometry::Rect;
@ -31,11 +31,11 @@ mod session;
pub use session::*;
#[derive(Debug)]
pub struct Scene(pub Id<Object>);
pub struct Scene(pub Id<Object, Owned>);
impl Scene {
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
@ -48,8 +48,4 @@ impl Scene {
}
.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::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, sel};
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.
#[derive(Debug)]
pub struct SceneConnectionOptions(Id<Object>);
pub struct SceneConnectionOptions(Id<Object, Owned>);
impl SceneConnectionOptions {
pub fn with(opts: id) -> Self {
SceneConnectionOptions(unsafe { Id::from_ptr(opts) })
}
/// Consumes and returns the underlying `UISceneConfiguration`.
pub fn into_inner(mut self) -> id {
&mut *self.0
SceneConnectionOptions(unsafe { Id::retain(opts).unwrap() })
}
}

View file

@ -1,19 +1,19 @@
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{msg_send, msg_send_id, sel};
use crate::foundation::{id, NSString};
use crate::uikit::scene::enums::SessionRole;
#[derive(Debug)]
pub struct SceneSession(pub Id<Object>);
pub struct SceneSession(pub Id<Object, Owned>);
impl SceneSession {
pub fn with(session: id) -> Self {
SceneSession(unsafe { Id::from_ptr(session) })
SceneSession(unsafe { Id::retain(session).unwrap() })
}
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 objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
use crate::foundation::id;
use crate::geometry::Rect;
@ -10,20 +10,20 @@ use crate::uikit::Scene;
use crate::utils::Controller;
#[derive(Debug)]
pub struct Window(pub Id<Object>);
pub struct Window(pub Id<Object, Owned>);
impl Window {
pub fn new(frame: Rect) -> Self {
Window(unsafe {
let rect: CGRect = frame.into();
let alloc: id = msg_send![class!(UIWindow), alloc];
Id::from_ptr(msg_send![alloc, initWithFrame: rect])
let alloc = msg_send_id![class!(UIWindow), alloc];
msg_send_id![alloc, initWithFrame: rect]
})
}
pub fn set_window_scene(&mut self, scene: Scene) {
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.
use objc::rc::{Id, Shared};
use objc::runtime::Object;
use objc_id::ShareId;
use crate::foundation::id;
/// Represents an `NSUserActivity`, which acts as a lightweight method to capture
/// the state of your app.
#[derive(Debug)]
pub struct UserActivity(pub ShareId<Object>);
pub struct UserActivity(pub Id<Object, Shared>);
impl UserActivity {
/// An internal method for wrapping a system-provided activity.
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 objc::{class, msg_send, sel, sel_impl};
use objc::{class, msg_send, sel};
use uuid::Uuid;
use crate::foundation::{id, nil, NSString, NSUInteger};
@ -27,7 +27,7 @@ impl NotificationCenter {
unsafe {
// @TODO: Revisit.
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();
if e != "" {
println!("{:?}", e);
@ -41,7 +41,11 @@ impl NotificationCenter {
}
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 {
let identifier = NSString::new(&uuidentifier);
let request: id =
msg_send![class!(UNNotificationRequest), requestWithIdentifier:identifier content:&*notification.0 trigger:nil];
let request: id = msg_send![
class!(UNNotificationRequest),
requestWithIdentifier: &*identifier,
content: &*notification.0,
trigger: nil,
];
let center: id = msg_send![class!(UNUserNotificationCenter), currentNotificationCenter];
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
//! need to pass to the notification center for things to work.
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::{class, msg_send, msg_send_id, sel};
use crate::foundation::{id, NSString};
/// A wrapper for `UNMutableNotificationContent`. Retains the pointer from the Objective C side,
/// and is ultimately dropped upon sending.
#[derive(Debug)]
pub struct Notification(pub Id<Object>);
pub struct Notification(pub Id<Object, Owned>);
impl Notification {
/// 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);
Notification(unsafe {
let content: id = msg_send![class!(UNMutableNotificationContent), new];
let _: () = msg_send![content, setTitle: title];
let _: () = msg_send![content, setBody: body];
Id::from_ptr(content)
let mut content = msg_send_id![class!(UNMutableNotificationContent), new];
let _: () = msg_send![&mut content, setTitle: &*title];
let _: () = msg_send![&mut content, setBody: &*body];
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
//! they go away one day.
use core_foundation::base::CFIndex;
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::{Encode, Encoding};
use objc_id::ShareId;
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.
pub trait Controller {
/// 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
@ -92,12 +93,27 @@ impl CGSize {
}
unsafe impl Encode for CGSize {
/// Adds support for CGSize Objective-C encoding.
fn encode() -> Encoding {
let encoding = format!("{{CGSize={}{}}}", CGFloat::encode().as_str(), CGFloat::encode().as_str());
unsafe { Encoding::from_str(&encoding) }
const ENCODING: Encoding = Encoding::Struct("CGSize", &[CGFloat::ENCODING, CGFloat::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.

View file

@ -1,8 +1,8 @@
use std::cell::RefCell;
use std::rc::Rc;
use objc::rc::{Id, Owned};
use objc::runtime::Object;
use objc_id::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
/// is probably worth investigating at some point.
#[derive(Clone, Debug)]
pub struct ObjcProperty(Rc<RefCell<Id<Object>>>);
pub struct ObjcProperty(Rc<RefCell<Id<Object, Owned>>>);
impl ObjcProperty {
/// Given an Objective-C object, retains it and wraps it as a `Property`.
pub fn retain(obj: id) -> Self {
ObjcProperty(Rc::new(RefCell::new(unsafe { Id::from_ptr(obj) })))
}
/// 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) })))
ObjcProperty(Rc::new(RefCell::new(unsafe { Id::retain(obj).unwrap() })))
}
/// Runs a handler with mutable access for the underlying Objective-C object.

View file

@ -1,18 +1,18 @@
use core_graphics::base::CGFloat;
use objc::rc::{Id, Shared};
use objc::runtime::{Class, Object};
use objc::{msg_send, sel, sel_impl};
use objc_id::ShareId;
use objc::{msg_send, msg_send_id, sel};
use crate::foundation::id;
/// A wrapper for an animation proxy object in Cocoa that supports basic animations.
#[derive(Clone, Debug)]
pub struct ViewAnimatorProxy(pub ShareId<Object>);
pub struct ViewAnimatorProxy(pub Id<Object, Shared>);
impl ViewAnimatorProxy {
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.
@ -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.
use objc::declare::ClassDecl;
use objc::runtime::{Class, Object, Sel, BOOL};
use objc::{class, msg_send, sel, sel_impl};
use objc_id::Id;
use objc::rc::{Id, Owned};
use objc::runtime::{Bool, Class, Object, Sel};
use objc::{class, msg_send, sel};
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::view::{ViewDelegate, BACKGROUND_COLOR, VIEW_DELEGATE_PTR};
/// 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 {
return YES;
extern "C" fn enforce_normalcy(_: &Object, _: Sel) -> Bool {
return Bool::YES;
}
/// Called when a drag/drop operation has entered this view.
extern "C" fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
let view = load::<T>(this, VIEW_DELEGATE_PTR);
view.dragging_entered(DragInfo {
info: unsafe { Id::from_ptr(info) }
info: unsafe { Id::retain(info).unwrap() }
})
.into()
}
/// 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);
match view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
Bool::new(view.prepare_for_drag_operation(DragInfo {
info: unsafe { Id::retain(info).unwrap() }
}))
}
/// 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);
match view.perform_drag_operation(DragInfo {
info: unsafe { Id::from_ptr(info) }
}) {
true => YES,
false => NO
}
Bool::new(view.perform_drag_operation(DragInfo {
info: unsafe { Id::retain(info).unwrap() }
}))
}
/// 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);
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);
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
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// 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 {
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL);
decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(&Object, _));
decl.add_method(sel!(wantsUpdateLayer), 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(_, _));
decl.add_method(sel!(wantsUpdateLayer), enforce_normalcy as extern "C" fn(_, _) -> _);
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
/// 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 {
// A pointer to the ViewDelegate instance on the Rust side.
// It's expected that this doesn't move.
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
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)
decl.add_method(
sel!(draggingEntered:),
dragging_entered::<T> as extern "C" fn(&mut Object, _, _) -> NSUInteger
);
decl.add_method(sel!(draggingEntered:), dragging_entered::<T> as extern "C" fn(_, _, _) -> _);
decl.add_method(
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(
sel!(performDragOperation:),
perform_drag_operation::<T> as extern "C" fn(&mut Object, _, _) -> BOOL
perform_drag_operation::<T> as extern "C" fn(_, _, _) -> _
);
decl.add_method(
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(_, _, _));
})
}

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