Wrap Foundation ourselves, because there's some considerations down the road and it's easier to do this now.
This commit is contained in:
parent
66ffd83db0
commit
c16dad564e
|
@ -6,16 +6,12 @@ edition = "2018"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
appkit-derive = { path = "../derives" }
|
|
||||||
block = "0.1.6"
|
block = "0.1.6"
|
||||||
cocoa = "0.20.0"
|
|
||||||
core-foundation = "0.7"
|
|
||||||
core-graphics = "0.19.0"
|
|
||||||
dispatch = "0.2.0"
|
dispatch = "0.2.0"
|
||||||
lazy_static = "1"
|
libc = "0.2"
|
||||||
objc = "0.2.7"
|
objc = "0.2.7"
|
||||||
objc_id = "0.1.1"
|
objc_id = "0.1.1"
|
||||||
uuid = { version = "0.8", features = ["v4"] }
|
#uuid = { version = "0.8", features = ["v4"] }
|
||||||
url = "2.1.1"
|
url = "2.1.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if std::env::var("TARGET").unwrap().contains("-apple") {
|
if std::env::var("TARGET").unwrap().contains("-apple") {
|
||||||
|
println!("cargo:rustc-link-lib=framework=Foundation");
|
||||||
|
println!("cargo:rustc-link-lib=framework=CoreGraphics");
|
||||||
|
|
||||||
println!("cargo:rustc-link-lib=framework=Security");
|
println!("cargo:rustc-link-lib=framework=Security");
|
||||||
println!("cargo:rustc-link-lib=framework=WebKit");
|
println!("cargo:rustc-link-lib=framework=WebKit");
|
||||||
|
|
||||||
|
|
|
@ -1,46 +1,37 @@
|
||||||
//! A wrapper for `NSAlert`. Currently doesn't cover everything possible for this class, as it was
|
//! A wrapper for `NSAlert`. Currently doesn't cover everything possible for this class, as it was
|
||||||
//! built primarily for debugging uses. Feel free to extend via pull requests or something.
|
//! built primarily for debugging uses. Feel free to extend via pull requests or something.
|
||||||
|
|
||||||
use cocoa::base::{id, nil};
|
|
||||||
use cocoa::foundation::NSString;
|
|
||||||
|
|
||||||
use objc_id::Id;
|
use objc_id::Id;
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
|
use crate::foundation::{id, NSString};
|
||||||
|
|
||||||
/// Represents an `NSAlert`. Has no information other than the retained pointer to the Objective C
|
/// Represents an `NSAlert`. Has no information other than the retained pointer to the Objective C
|
||||||
/// side, so... don't bother inspecting this.
|
/// side, so... don't bother inspecting this.
|
||||||
pub struct Alert {
|
pub struct Alert(Id<Object>);
|
||||||
pub inner: Id<Object>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Alert {
|
impl Alert {
|
||||||
/// Creates a basic `NSAlert`, storing a pointer to it in the Objective C runtime.
|
/// Creates a basic `NSAlert`, storing a pointer to it in the Objective C runtime.
|
||||||
/// You can show this alert by calling `show()`.
|
/// You can show this alert by calling `show()`.
|
||||||
pub fn new(title: &str, message: &str) -> Self {
|
pub fn new(title: &str, message: &str) -> Self {
|
||||||
Alert {
|
let title = NSString::new(title);
|
||||||
inner: unsafe {
|
let message = NSString::new(message);
|
||||||
let cls = class!(NSAlert);
|
let x = NSString::new("OK");
|
||||||
let alert: id = msg_send![cls, new];
|
|
||||||
|
|
||||||
let title = NSString::alloc(nil).init_str(title);
|
Alert(unsafe {
|
||||||
|
let alert: id = msg_send![class!(NSAlert), new];
|
||||||
let _: () = msg_send![alert, setMessageText:title];
|
let _: () = msg_send![alert, setMessageText:title];
|
||||||
|
|
||||||
let message = NSString::alloc(nil).init_str(message);
|
|
||||||
let _: () = msg_send![alert, setInformativeText:message];
|
let _: () = msg_send![alert, setInformativeText:message];
|
||||||
|
|
||||||
let x = NSString::alloc(nil).init_str("OK");
|
|
||||||
let _: () = msg_send![alert, addButtonWithTitle:x];
|
let _: () = msg_send![alert, addButtonWithTitle:x];
|
||||||
|
|
||||||
Id::from_ptr(alert)
|
Id::from_ptr(alert)
|
||||||
}
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shows this alert as a modal.
|
/// Shows this alert as a modal.
|
||||||
pub fn show(&self) {
|
pub fn show(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _: () = msg_send![&*self.inner, runModal];
|
let _: () = msg_send![&*self.0, runModal];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,21 +8,18 @@ use std::unreachable;
|
||||||
|
|
||||||
use block::Block;
|
use block::Block;
|
||||||
|
|
||||||
use cocoa::base::{id, nil, BOOL, YES, NO};
|
|
||||||
use cocoa::foundation::{NSUInteger};
|
|
||||||
|
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
use objc::declare::ClassDecl;
|
use objc::declare::ClassDecl;
|
||||||
use objc::runtime::{Class, Object, Sel};
|
use objc::runtime::{Class, Object, Sel};
|
||||||
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::foundation::{id, nil, BOOL, YES, NO, NSUInteger, NSArray, NSString};
|
||||||
use crate::app::traits::AppController;
|
use crate::app::traits::AppController;
|
||||||
use crate::constants::APP_PTR;
|
use crate::constants::APP_PTR;
|
||||||
use crate::error::AppKitError;
|
use crate::error::AppKitError;
|
||||||
use crate::printing::PrintSettings;
|
use crate::printing::PrintSettings;
|
||||||
use crate::user_activity::UserActivity;
|
use crate::user_activity::UserActivity;
|
||||||
use crate::utils::{map_nsarray, str_from};
|
|
||||||
|
|
||||||
#[cfg(feature = "cloudkit")]
|
#[cfg(feature = "cloudkit")]
|
||||||
use crate::cloudkit::share::CKShareMetaData;
|
use crate::cloudkit::share::CKShareMetaData;
|
||||||
|
@ -122,7 +119,6 @@ extern fn should_handle_reopen<T: AppController>(this: &Object, _: Sel, _: id, h
|
||||||
|
|
||||||
/// Fires when the application delegate receives a `applicationDockMenu:` request.
|
/// Fires when the application delegate receives a `applicationDockMenu:` request.
|
||||||
extern fn dock_menu<T: AppController>(this: &Object, _: Sel, _: id) -> id {
|
extern fn dock_menu<T: AppController>(this: &Object, _: Sel, _: id) -> id {
|
||||||
// @TODO: Confirm this is safe to do and not leaky.
|
|
||||||
match app::<T>(this).dock_menu() {
|
match app::<T>(this).dock_menu() {
|
||||||
Some(mut menu) => &mut *menu.inner,
|
Some(mut menu) => &mut *menu.inner,
|
||||||
None => nil
|
None => nil
|
||||||
|
@ -143,9 +139,9 @@ extern fn did_change_screen_parameters<T: AppController>(this: &Object, _: Sel,
|
||||||
/// Fires when the application receives a `application:willContinueUserActivityWithType:`
|
/// Fires when the application receives a `application:willContinueUserActivityWithType:`
|
||||||
/// notification.
|
/// notification.
|
||||||
extern fn will_continue_user_activity_with_type<T: AppController>(this: &Object, _: Sel, _: id, activity_type: id) -> BOOL {
|
extern fn will_continue_user_activity_with_type<T: AppController>(this: &Object, _: Sel, _: id, activity_type: id) -> BOOL {
|
||||||
let activity = str_from(activity_type);
|
let activity = NSString::wrap(activity_type);
|
||||||
|
|
||||||
match app::<T>(this).will_continue_user_activity(activity) {
|
match app::<T>(this).will_continue_user_activity(activity.to_str()) {
|
||||||
true => YES,
|
true => YES,
|
||||||
false => NO
|
false => NO
|
||||||
}
|
}
|
||||||
|
@ -171,7 +167,7 @@ extern fn continue_user_activity<T: AppController>(this: &Object, _: Sel, _: id,
|
||||||
/// `application:didFailToContinueUserActivityWithType:error:` message.
|
/// `application:didFailToContinueUserActivityWithType:error:` message.
|
||||||
extern fn failed_to_continue_user_activity<T: AppController>(this: &Object, _: Sel, _: id, activity_type: id, error: id) {
|
extern fn failed_to_continue_user_activity<T: AppController>(this: &Object, _: Sel, _: id, activity_type: id, error: id) {
|
||||||
app::<T>(this).failed_to_continue_user_activity(
|
app::<T>(this).failed_to_continue_user_activity(
|
||||||
str_from(activity_type),
|
NSString::wrap(activity_type).to_str(),
|
||||||
AppKitError::new(error)
|
AppKitError::new(error)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -188,8 +184,8 @@ extern fn registered_for_remote_notifications<T: AppController>(_this: &Object,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fires when the application receives a `application:didFailToRegisterForRemoteNotificationsWithError:` message.
|
/// Fires when the application receives a `application:didFailToRegisterForRemoteNotificationsWithError:` message.
|
||||||
extern fn failed_to_register_for_remote_notifications<T: AppController>(_this: &Object, _: Sel, _: id, _: id) {
|
extern fn failed_to_register_for_remote_notifications<T: AppController>(this: &Object, _: Sel, _: id, error: id) {
|
||||||
|
app::<T>(this).failed_to_register_for_remote_notifications(AppKitError::new(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fires when the application receives a `application:didReceiveRemoteNotification:` message.
|
/// Fires when the application receives a `application:didReceiveRemoteNotification:` message.
|
||||||
|
@ -207,10 +203,12 @@ extern fn accepted_cloudkit_share<T: AppController>(_this: &Object, _: Sel, _: i
|
||||||
|
|
||||||
/// Fires when the application receives an `application:openURLs` message.
|
/// Fires when the application receives an `application:openURLs` message.
|
||||||
extern fn open_urls<T: AppController>(this: &Object, _: Sel, _: id, file_urls: id) {
|
extern fn open_urls<T: AppController>(this: &Object, _: Sel, _: id, file_urls: id) {
|
||||||
let urls = map_nsarray(file_urls, |url| unsafe {
|
let urls = NSArray::wrap(file_urls).map(|url| {
|
||||||
let absolute_string = msg_send![url, absoluteString];
|
let uri = NSString::wrap(unsafe {
|
||||||
let uri = str_from(absolute_string);
|
msg_send![url, absoluteString]
|
||||||
Url::parse(uri)
|
});
|
||||||
|
|
||||||
|
Url::parse(uri.to_str())
|
||||||
}).into_iter().filter_map(|url| url.ok()).collect();
|
}).into_iter().filter_map(|url| url.ok()).collect();
|
||||||
|
|
||||||
app::<T>(this).open_urls(urls);
|
app::<T>(this).open_urls(urls);
|
||||||
|
@ -218,9 +216,9 @@ extern fn open_urls<T: AppController>(this: &Object, _: Sel, _: id, file_urls: i
|
||||||
|
|
||||||
/// Fires when the application receives an `application:openFileWithoutUI:` message.
|
/// Fires when the application receives an `application:openFileWithoutUI:` message.
|
||||||
extern fn open_file_without_ui<T: AppController>(this: &Object, _: Sel, _: id, file: id) -> BOOL {
|
extern fn open_file_without_ui<T: AppController>(this: &Object, _: Sel, _: id, file: id) -> BOOL {
|
||||||
let filename = str_from(file);
|
let filename = NSString::wrap(file);
|
||||||
|
|
||||||
match app::<T>(this).open_file_without_ui(filename) {
|
match app::<T>(this).open_file_without_ui(filename.to_str()) {
|
||||||
true => YES,
|
true => YES,
|
||||||
false => NO
|
false => NO
|
||||||
}
|
}
|
||||||
|
@ -244,9 +242,9 @@ extern fn open_untitled_file<T: AppController>(this: &Object, _: Sel, _: id) ->
|
||||||
|
|
||||||
/// Fired when the application receives an `application:openTempFile:` message.
|
/// Fired when the application receives an `application:openTempFile:` message.
|
||||||
extern fn open_temp_file<T: AppController>(this: &Object, _: Sel, _: id, filename: id) -> BOOL {
|
extern fn open_temp_file<T: AppController>(this: &Object, _: Sel, _: id, filename: id) -> BOOL {
|
||||||
let filename = str_from(filename);
|
let filename = NSString::wrap(filename);
|
||||||
|
|
||||||
match app::<T>(this).open_temp_file(filename) {
|
match app::<T>(this).open_temp_file(filename.to_str()) {
|
||||||
true => YES,
|
true => YES,
|
||||||
false => NO
|
false => NO
|
||||||
}
|
}
|
||||||
|
@ -254,9 +252,9 @@ extern fn open_temp_file<T: AppController>(this: &Object, _: Sel, _: id, filenam
|
||||||
|
|
||||||
/// Fired when the application receives an `application:printFile:` message.
|
/// Fired when the application receives an `application:printFile:` message.
|
||||||
extern fn print_file<T: AppController>(this: &Object, _: Sel, _: id, file: id) -> BOOL {
|
extern fn print_file<T: AppController>(this: &Object, _: Sel, _: id, file: id) -> BOOL {
|
||||||
let filename = str_from(file);
|
let filename = NSString::wrap(file);
|
||||||
|
|
||||||
match app::<T>(this).print_file(filename) {
|
match app::<T>(this).print_file(filename.to_str()) {
|
||||||
true => YES,
|
true => YES,
|
||||||
false => NO
|
false => NO
|
||||||
}
|
}
|
||||||
|
@ -265,8 +263,8 @@ extern fn print_file<T: AppController>(this: &Object, _: Sel, _: id, file: id) -
|
||||||
/// Fired when the application receives an `application:printFiles:withSettings:showPrintPanels:`
|
/// Fired when the application receives an `application:printFiles:withSettings:showPrintPanels:`
|
||||||
/// message.
|
/// message.
|
||||||
extern fn print_files<T: AppController>(this: &Object, _: Sel, _: id, files: id, settings: id, show_print_panels: BOOL) -> NSUInteger {
|
extern fn print_files<T: AppController>(this: &Object, _: Sel, _: id, files: id, settings: id, show_print_panels: BOOL) -> NSUInteger {
|
||||||
let files = map_nsarray(files, |file| {
|
let files = NSArray::wrap(files).map(|file| {
|
||||||
str_from(file).to_string()
|
NSString::wrap(file).to_str().to_string()
|
||||||
});
|
});
|
||||||
|
|
||||||
let settings = PrintSettings::with_inner(settings);
|
let settings = PrintSettings::with_inner(settings);
|
||||||
|
@ -287,9 +285,9 @@ extern fn did_change_occlusion_state<T: AppController>(this: &Object, _: Sel, _:
|
||||||
/// Note: this may not fire in sandboxed applications. Apple's documentation is unclear on the
|
/// Note: this may not fire in sandboxed applications. Apple's documentation is unclear on the
|
||||||
/// matter.
|
/// matter.
|
||||||
extern fn delegate_handles_key<T: AppController>(this: &Object, _: Sel, _: id, key: id) -> BOOL {
|
extern fn delegate_handles_key<T: AppController>(this: &Object, _: Sel, _: id, key: id) -> BOOL {
|
||||||
let key = str_from(key);
|
let key = NSString::wrap(key);
|
||||||
|
|
||||||
match app::<T>(this).delegate_handles_key(key) {
|
match app::<T>(this).delegate_handles_key(key.to_str()) {
|
||||||
true => YES,
|
true => YES,
|
||||||
false => NO
|
false => NO
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Various types used at the AppController level.
|
//! Various types used at the AppController level.
|
||||||
|
|
||||||
use cocoa::foundation::NSUInteger;
|
use crate::foundation::NSUInteger;
|
||||||
|
|
||||||
/// Used for determining how an application should handle quitting/terminating.
|
/// Used for determining how an application should handle quitting/terminating.
|
||||||
/// You return this in your `AppController` `should_terminate` method.
|
/// You return this in your `AppController` `should_terminate` method.
|
||||||
|
@ -29,32 +29,3 @@ impl From<TerminateResponse> for NSUInteger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used for handling printing files. You return this in relevant `AppController` methods.
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub enum PrintResponse {
|
|
||||||
/// Printing was cancelled.
|
|
||||||
Cancelled,
|
|
||||||
|
|
||||||
/// Printing was a success.
|
|
||||||
Success,
|
|
||||||
|
|
||||||
/// Printing failed.
|
|
||||||
Failure,
|
|
||||||
|
|
||||||
/// For when the result of printing cannot be returned immediately (e.g, if printing causes a sheet to appear).
|
|
||||||
/// If your method returns PrintResponse::ReplyLater it must always invoke `App::reply_to_open_or_print()` when the
|
|
||||||
/// entire print operation has been completed, successfully or not.
|
|
||||||
ReplyLater
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<PrintResponse> for NSUInteger {
|
|
||||||
fn from(response: PrintResponse) -> NSUInteger {
|
|
||||||
match response {
|
|
||||||
PrintResponse::Cancelled => 0,
|
|
||||||
PrintResponse::Success => 1,
|
|
||||||
PrintResponse::Failure => 3,
|
|
||||||
PrintResponse::ReplyLater => 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
//! A wrapper for `NSApplicationDelegate` on macOS. Handles looping back events and providing a very janky
|
//! A wrapper for `NSApplicationDelegate` on macOS. Handles looping back events and providing a very janky
|
||||||
//! messaging architecture.
|
//! messaging architecture.
|
||||||
|
|
||||||
use cocoa::base::{id, nil};
|
|
||||||
use cocoa::appkit::{NSRunningApplication};
|
|
||||||
|
|
||||||
use objc_id::Id;
|
use objc_id::Id;
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
@ -12,6 +9,7 @@ mod class;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
pub mod enums;
|
pub mod enums;
|
||||||
|
|
||||||
|
use crate::foundation::{id, AutoReleasePool};
|
||||||
use crate::constants::APP_PTR;
|
use crate::constants::APP_PTR;
|
||||||
use crate::menu::Menu;
|
use crate::menu::Menu;
|
||||||
use class::{register_app_class, register_app_controller_class};
|
use class::{register_app_class, register_app_controller_class};
|
||||||
|
@ -24,6 +22,7 @@ pub struct App<T = (), M = ()> {
|
||||||
pub inner: Id<Object>,
|
pub inner: Id<Object>,
|
||||||
pub objc_delegate: Id<Object>,
|
pub objc_delegate: Id<Object>,
|
||||||
pub delegate: Box<T>,
|
pub delegate: Box<T>,
|
||||||
|
pub pool: AutoReleasePool,
|
||||||
_t: std::marker::PhantomData<M>
|
_t: std::marker::PhantomData<M>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,35 +50,17 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, M> App<T, M> where M: Send + Sync + 'static, T: AppController + Dispatcher<Message = M> {
|
impl<T, M> App<T, M> where M: Send + Sync + 'static, T: AppController + Dispatcher<Message = M> {
|
||||||
/// Dispatches a message by grabbing the `sharedApplication`, getting ahold of the delegate,
|
|
||||||
/// and passing back through there. All messages are currently dispatched on the main thread.
|
|
||||||
pub fn dispatch(message: M) {
|
|
||||||
let queue = dispatch::Queue::main();
|
|
||||||
|
|
||||||
queue.exec_async(move || unsafe {
|
|
||||||
let app: id = msg_send![register_app_class(), sharedApplication];
|
|
||||||
let app_delegate: id = msg_send![app, delegate];
|
|
||||||
let delegate_ptr: usize = *(*app_delegate).get_ivar(APP_PTR);
|
|
||||||
let delegate = delegate_ptr as *const T;
|
|
||||||
(&*delegate).on_message(message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an NSAutoReleasePool, configures various NSApplication properties (e.g, activation
|
/// Creates an NSAutoReleasePool, configures various NSApplication properties (e.g, activation
|
||||||
/// policies), injects an `NSObject` delegate wrapper, and retains everything on the
|
/// policies), injects an `NSObject` delegate wrapper, and retains everything on the
|
||||||
/// Objective-C side of things.
|
/// Objective-C side of things.
|
||||||
pub fn new(_bundle_id: &str, delegate: T) -> Self {
|
pub fn new(_bundle_id: &str, delegate: T) -> Self {
|
||||||
// set_bundle_id(bundle_id);
|
// set_bundle_id(bundle_id);
|
||||||
|
|
||||||
let _pool = unsafe {
|
let pool = AutoReleasePool::new();
|
||||||
//msg_send![class!(
|
|
||||||
cocoa::foundation::NSAutoreleasePool::new(nil)
|
|
||||||
};
|
|
||||||
|
|
||||||
let inner = unsafe {
|
let inner = unsafe {
|
||||||
let app: id = msg_send![register_app_class(), sharedApplication];
|
let app: id = msg_send![register_app_class(), sharedApplication];
|
||||||
let _: () = msg_send![app, setActivationPolicy:0];
|
let _: () = msg_send![app, setActivationPolicy:0];
|
||||||
//app.setActivationPolicy_(cocoa::appkit::NSApplicationActivationPolicyRegular);
|
|
||||||
Id::from_ptr(app)
|
Id::from_ptr(app)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -98,17 +79,32 @@ impl<T, M> App<T, M> where M: Send + Sync + 'static, T: AppController + Dispatch
|
||||||
objc_delegate: objc_delegate,
|
objc_delegate: objc_delegate,
|
||||||
inner: inner,
|
inner: inner,
|
||||||
delegate: app_delegate,
|
delegate: app_delegate,
|
||||||
|
pool: pool,
|
||||||
_t: std::marker::PhantomData
|
_t: std::marker::PhantomData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Dispatches a message by grabbing the `sharedApplication`, getting ahold of the delegate,
|
||||||
|
/// and passing back through there. All messages are currently dispatched on the main thread.
|
||||||
|
pub fn dispatch(message: M) {
|
||||||
|
let queue = dispatch::Queue::main();
|
||||||
|
|
||||||
|
queue.exec_async(move || unsafe {
|
||||||
|
let app: id = msg_send![register_app_class(), sharedApplication];
|
||||||
|
let app_delegate: id = msg_send![app, delegate];
|
||||||
|
let delegate_ptr: usize = *(*app_delegate).get_ivar(APP_PTR);
|
||||||
|
let delegate = delegate_ptr as *const T;
|
||||||
|
(&*delegate).on_message(message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Kicks off the NSRunLoop for the NSApplication instance. This blocks when called.
|
/// Kicks off the NSRunLoop for the NSApplication instance. This blocks when called.
|
||||||
/// If you're wondering where to go from here... you need an `AppController` that implements
|
/// If you're wondering where to go from here... you need an `AppController` that implements
|
||||||
/// `did_finish_launching`. :)
|
/// `did_finish_launching`. :)
|
||||||
pub fn run(&self) {
|
pub fn run(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let current_app = cocoa::appkit::NSRunningApplication::currentApplication(nil);
|
let current_app: id = msg_send![class!(NSRunningApplication), currentApplication];
|
||||||
current_app.activateWithOptions_(cocoa::appkit::NSApplicationActivateIgnoringOtherApps);
|
let _: () = msg_send![current_app, activateWithOptions:0];
|
||||||
let shared_app: id = msg_send![class!(RSTApplication), sharedApplication];
|
let shared_app: id = msg_send![class!(RSTApplication), sharedApplication];
|
||||||
let _: () = msg_send![shared_app, run];
|
let _: () = msg_send![shared_app, run];
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::app::enums::{TerminateResponse, PrintResponse};
|
use crate::app::enums::TerminateResponse;
|
||||||
use crate::error::AppKitError;
|
use crate::error::AppKitError;
|
||||||
use crate::menu::Menu;
|
use crate::menu::Menu;
|
||||||
|
use crate::printing::enums::PrintResponse;
|
||||||
use crate::printing::settings::PrintSettings;
|
use crate::printing::settings::PrintSettings;
|
||||||
use crate::user_activity::UserActivity;
|
use crate::user_activity::UserActivity;
|
||||||
|
|
||||||
#[cfg(feature = "user-notifications")]
|
#[cfg(feature = "cloudkit")]
|
||||||
use crate::cloudkit::share::CKShareMetaData;
|
use crate::cloudkit::share::CKShareMetaData;
|
||||||
|
|
||||||
/// Controllers interested in processing messages can implement this to respond to messages as
|
/// Controllers interested in processing messages can implement this to respond to messages as
|
||||||
|
@ -121,6 +122,18 @@ pub trait AppController {
|
||||||
/// Fired after the user activity object has been updated.
|
/// Fired after the user activity object has been updated.
|
||||||
fn updated_user_activity(&self, _activity: UserActivity) {}
|
fn updated_user_activity(&self, _activity: UserActivity) {}
|
||||||
|
|
||||||
|
/// Fired when you've successfully registered for remote notifications with APNS.
|
||||||
|
fn registered_for_remote_notifications(&self, _token: &str) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fired after you've received a push notification from APNS.
|
||||||
|
//fn did_receive_remote_notification(&self, notification: PushNotification) {}
|
||||||
|
|
||||||
|
/// Fired if there was a failure to register for remote notifications with APNS - e.g,
|
||||||
|
/// connection issues or something.
|
||||||
|
fn failed_to_register_for_remote_notifications(&self, _error: AppKitError) {}
|
||||||
|
|
||||||
/// Fires after the user accepted a CloudKit sharing invitation associated with your
|
/// Fires after the user accepted a CloudKit sharing invitation associated with your
|
||||||
/// application.
|
/// application.
|
||||||
#[cfg(feature = "cloudkit")]
|
#[cfg(feature = "cloudkit")]
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use cocoa::foundation::{NSString};
|
|
||||||
use cocoa::base::{id, nil, BOOL, YES};//, NO};
|
|
||||||
use objc::{class, msg_send, sel, sel_impl, Encode, Encoding, EncodeArguments, Message};
|
use objc::{class, msg_send, sel, sel_impl, Encode, Encoding, EncodeArguments, Message};
|
||||||
use objc::runtime::{Class, Sel, Method, Object, Imp};
|
use objc::runtime::{Class, Sel, Method, Object, Imp};
|
||||||
use objc::runtime::{
|
use objc::runtime::{
|
||||||
|
@ -19,6 +17,8 @@ use objc::runtime::{
|
||||||
method_exchangeImplementations
|
method_exchangeImplementations
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::foundation::{id, nil, BOOL, YES, NSString};
|
||||||
|
|
||||||
/// Types that can be used as the implementation of an Objective-C method.
|
/// Types that can be used as the implementation of an Objective-C method.
|
||||||
pub trait MethodImplementation {
|
pub trait MethodImplementation {
|
||||||
/// The callee type of the method.
|
/// The callee type of the method.
|
||||||
|
|
|
@ -3,13 +3,12 @@
|
||||||
|
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
|
||||||
use cocoa::base::{id, nil};
|
|
||||||
use cocoa::foundation::{NSString};
|
|
||||||
|
|
||||||
use objc_id::Id;
|
use objc_id::Id;
|
||||||
use objc::declare::ClassDecl;
|
use objc::declare::ClassDecl;
|
||||||
use objc::runtime::{Class, Object};
|
use objc::runtime::{Class, Object};
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
|
use crate::foundation::{nil, NSString};
|
||||||
|
|
||||||
/// A wrapper for `NSButton`. Holds (retains) pointers for the Objective-C runtime
|
/// A wrapper for `NSButton`. Holds (retains) pointers for the Objective-C runtime
|
||||||
/// where our `NSButton` lives.
|
/// where our `NSButton` lives.
|
||||||
|
@ -21,10 +20,9 @@ impl Button {
|
||||||
/// Creates a new `NSButton` instance, configures it appropriately,
|
/// Creates a new `NSButton` instance, configures it appropriately,
|
||||||
/// and retains the necessary Objective-C runtime pointer.
|
/// and retains the necessary Objective-C runtime pointer.
|
||||||
pub fn new(text: &str) -> Self {
|
pub fn new(text: &str) -> Self {
|
||||||
|
let title = NSString::new(text);
|
||||||
let inner = unsafe {
|
let inner = unsafe {
|
||||||
let title = NSString::alloc(nil).init_str(text);
|
Id::from_ptr(msg_send![register_class(), buttonWithTitle:title target:nil action:nil])
|
||||||
let button: id = msg_send![register_class(), buttonWithTitle:title target:nil action:nil];
|
|
||||||
Id::from_ptr(button)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
@ -47,7 +45,7 @@ fn register_class() -> *const Class {
|
||||||
static INIT: Once = Once::new();
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
INIT.call_once(|| unsafe {
|
INIT.call_once(|| unsafe {
|
||||||
let superclass = Class::get("NSButton").unwrap();
|
let superclass = class!(NSButton);
|
||||||
let decl = ClassDecl::new("RSTButton", superclass).unwrap();
|
let decl = ClassDecl::new("RSTButton", superclass).unwrap();
|
||||||
VIEW_CLASS = decl.register();
|
VIEW_CLASS = decl.register();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
//! Implements `Color`. Heavily based on the `Color` module in Servo's CSS parser, but tweaked
|
//! Implements `Color`. Heavily based on the `Color` module in Servo's CSS parser, but tweaked
|
||||||
//! for (what I believe) is a friendlier API.
|
//! for (what I believe) is a friendlier API.
|
||||||
|
|
||||||
use cocoa::base::id;
|
|
||||||
use core_graphics::base::CGFloat;
|
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
|
use crate::foundation::{id, CGFloat};
|
||||||
|
|
||||||
/// A color with red, green, blue, and alpha components, in a byte each.
|
/// A color with red, green, blue, and alpha components, in a byte each.
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
//! across the codebase, hence why they're here - they're not currently exhaustive, so feel free to
|
//! across the codebase, hence why they're here - they're not currently exhaustive, so feel free to
|
||||||
//! tinker and pull request.
|
//! tinker and pull request.
|
||||||
|
|
||||||
use cocoa::foundation::NSUInteger;
|
|
||||||
|
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{msg_send, sel, sel_impl};
|
||||||
use objc_id::Id;
|
use objc_id::Id;
|
||||||
|
|
||||||
|
use crate::foundation::NSUInteger;
|
||||||
use crate::pasteboard::Pasteboard;
|
use crate::pasteboard::Pasteboard;
|
||||||
|
|
||||||
/// Represents operations that can happen for a given drag/drop scenario.
|
/// Represents operations that can happen for a given drag/drop scenario.
|
||||||
|
|
|
@ -6,11 +6,9 @@
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use cocoa::base::{id, nil};
|
|
||||||
use cocoa::foundation::{NSInteger, NSString};
|
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
use crate::utils::str_from;
|
use crate::foundation::{id, nil, NSInteger, NSString};
|
||||||
|
|
||||||
/// A wrapper around pieces of data extracted from `NSError`. This could be improved: right now, it
|
/// A wrapper around pieces of data extracted from `NSError`. This could be improved: right now, it
|
||||||
/// allocates `String` instances when theoretically it could be avoided, and we might be erasing
|
/// allocates `String` instances when theoretically it could be avoided, and we might be erasing
|
||||||
|
@ -29,16 +27,16 @@ impl AppKitError {
|
||||||
pub fn new(error: id) -> Self {
|
pub fn new(error: id) -> Self {
|
||||||
let (code, domain, description) = unsafe {
|
let (code, domain, description) = unsafe {
|
||||||
let code: usize = msg_send![error, code];
|
let code: usize = msg_send![error, code];
|
||||||
let domain: id = msg_send![error, domain];
|
let domain = NSString::wrap(msg_send![error, domain]);
|
||||||
let description: id = msg_send![error, localizedDescription];
|
let description = NSString::wrap(msg_send![error, localizedDescription]);
|
||||||
|
|
||||||
(code, domain, description)
|
(code, domain, description)
|
||||||
};
|
};
|
||||||
|
|
||||||
AppKitError {
|
AppKitError {
|
||||||
code: code,
|
code: code,
|
||||||
domain: str_from(domain).to_string(),
|
domain: domain.to_str().to_string(),
|
||||||
description: str_from(description).to_string()
|
description: description.to_str().to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +49,7 @@ impl AppKitError {
|
||||||
/// thread safe.
|
/// thread safe.
|
||||||
pub fn into_nserror(self) -> id {
|
pub fn into_nserror(self) -> id {
|
||||||
unsafe {
|
unsafe {
|
||||||
let domain = NSString::alloc(nil).init_str(&self.domain);
|
let domain = NSString::new(&self.domain);
|
||||||
let code = self.code as NSInteger;
|
let code = self.code as NSInteger;
|
||||||
msg_send![class!(NSError), errorWithDomain:domain code:code userInfo:nil]
|
msg_send![class!(NSError), errorWithDomain:domain code:code userInfo:nil]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Hoists some type definitions in a way that I personally find cleaner than what's in the Servo
|
//! Hoists some type definitions in a way that I personally find cleaner than what's in the Servo
|
||||||
//! code.
|
//! code.
|
||||||
|
|
||||||
use cocoa::foundation::NSUInteger;
|
use crate::foundation::NSUInteger;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum EventModifierFlag {
|
pub enum EventModifierFlag {
|
||||||
|
|
82
appkit/src/foundation/array.rs
Normal file
82
appkit/src/foundation/array.rs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
//! A wrapper type for `NSArray`. This is abstracted out as we need to use `NSArray` in a ton of
|
||||||
|
//! instances in this framework, and down the road I'd like to investigate using `CFArray` instead
|
||||||
|
//! of `NSArray` (i.e, if the ObjC runtime is ever pulled or something - perhaps those types would
|
||||||
|
//! stick around).
|
||||||
|
//!
|
||||||
|
//! Essentially, consider this some sanity/cleanliness/future-proofing. End users should never need
|
||||||
|
//! to touch this.
|
||||||
|
|
||||||
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
use objc::runtime::Object;
|
||||||
|
use objc_id::Id;
|
||||||
|
|
||||||
|
use crate::foundation::id;
|
||||||
|
|
||||||
|
/// A wrapper for `NSArray` that makes common operations in our framework a bit easier to handle
|
||||||
|
/// and reason about.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NSArray(pub Id<Object>);
|
||||||
|
|
||||||
|
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()])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() count:objects.len()])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NSArray {
|
||||||
|
/// Given a set of `Object`s, creates an `NSArray` that holds them.
|
||||||
|
pub fn new(objects: &[id]) -> Self {
|
||||||
|
NSArray(unsafe {
|
||||||
|
Id::from_ptr(msg_send![class!(NSArray), arrayWithObjects:objects.as_ptr() count:objects.len()])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 wrap(array: id) -> Self {
|
||||||
|
NSArray(unsafe {
|
||||||
|
Id::from_retained_ptr(array)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consumes and returns the underlying Objective-C value.
|
||||||
|
pub fn into_inner(mut self) -> id {
|
||||||
|
&mut *self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the `count` (`len()` equivalent) for the backing `NSArray`.
|
||||||
|
pub fn count(&self) -> usize {
|
||||||
|
unsafe { msg_send![self.0, count] }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A helper method for mapping over the backing `NSArray` items.
|
||||||
|
/// Often times we need to map in this framework to convert between Rust types, so isolating
|
||||||
|
/// this out makes life much easier.
|
||||||
|
pub fn map<T, F: Fn(id) -> T>(&self, transform: F) -> Vec<T> {
|
||||||
|
let count = self.count();
|
||||||
|
let mut ret: Vec<T> = Vec::with_capacity(count);
|
||||||
|
let mut index = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let item: id = unsafe { msg_send![&*self.0, objectAtIndex:index] };
|
||||||
|
ret.push(transform(item));
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
if index == count { break }
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
19
appkit/src/foundation/autoreleasepool.rs
Normal file
19
appkit/src/foundation/autoreleasepool.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
//! A lightweight wrapper around `NSAutoreleasePool`.
|
||||||
|
|
||||||
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
use objc::runtime::Object;
|
||||||
|
use objc_id::Id;
|
||||||
|
|
||||||
|
pub struct AutoReleasePool(pub Id<Object>);
|
||||||
|
|
||||||
|
impl AutoReleasePool {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
AutoReleasePool(unsafe {
|
||||||
|
Id::from_retained_ptr(msg_send![class!(NSAutoreleasePool), new])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drain(self) {
|
||||||
|
let _: () = unsafe { msg_send![&*self.0, drain] };
|
||||||
|
}
|
||||||
|
}
|
10
appkit/src/foundation/dictionary.rs
Normal file
10
appkit/src/foundation/dictionary.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
//! A wrapper for `NSDictionary`, which aims to make dealing with the class throughout this
|
||||||
|
//! framework a tad bit simpler.
|
||||||
|
|
||||||
|
use objc::runtime::Object;
|
||||||
|
use objc_id::Id;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NSDictionary(Id<Object>);
|
||||||
|
|
||||||
|
impl NSDictionary {}
|
81
appkit/src/foundation/geometry.rs
Normal file
81
appkit/src/foundation/geometry.rs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
//! Implements Core Graphics Geometry types. Most of this is lifted from `servo/core-foundation-rs`
|
||||||
|
//! - as such, we include a copy of the license below.
|
||||||
|
//!
|
||||||
|
//! Copyright (c) 2012-2013 Mozilla Foundation
|
||||||
|
//!
|
||||||
|
//! Permission is hereby granted, free of charge, to any
|
||||||
|
//! person obtaining a copy of this software and associated
|
||||||
|
//! documentation files (the "Software"), to deal in the
|
||||||
|
//! Software without restriction, including without
|
||||||
|
//! limitation the rights to use, copy, modify, merge,
|
||||||
|
//! publish, distribute, sublicense, and/or sell copies of
|
||||||
|
//! the Software, and to permit persons to whom the Software
|
||||||
|
//! is furnished to do so, subject to the following
|
||||||
|
//! conditions:
|
||||||
|
//!
|
||||||
|
//! The above copyright notice and this permission notice
|
||||||
|
//! shall be included in all copies or substantial portions
|
||||||
|
//! of the Software.
|
||||||
|
//!
|
||||||
|
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||||
|
//! ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
//! TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
//! PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||||
|
//! SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
//! CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
//! OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
//! IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
//! DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
use crate::foundation::CGFloat;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
|
pub struct CGSize {
|
||||||
|
pub width: CGFloat,
|
||||||
|
pub height: CGFloat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CGSize {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(width: CGFloat, height: CGFloat) -> CGSize {
|
||||||
|
CGSize {
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
|
pub struct CGPoint {
|
||||||
|
pub x: CGFloat,
|
||||||
|
pub y: CGFloat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CGPoint {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(x: CGFloat, y: CGFloat) -> CGPoint {
|
||||||
|
CGPoint {
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
pub struct CGRect {
|
||||||
|
pub origin: CGPoint,
|
||||||
|
pub size: CGSize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CGRect {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(origin: &CGPoint, size: &CGSize) -> CGRect {
|
||||||
|
CGRect {
|
||||||
|
origin: *origin,
|
||||||
|
size: *size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
appkit/src/foundation/mod.rs
Normal file
51
appkit/src/foundation/mod.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
//! This module contains some lightweight wrappers over certain data types that we use throughout
|
||||||
|
//! the framework. Some of it is pulled/inspired from Servo's cocoa-rs (e.g, the "id" type). While
|
||||||
|
//! this isn't a clone of their module (we don't need everything from there, but remaining
|
||||||
|
//! compatible in case an end-user wants to drop that low is deal), it's worth linking their
|
||||||
|
//! license and repository - they've done really incredible work and it's 100% worth acknowledging.
|
||||||
|
//!
|
||||||
|
//! - [core-foundation-rs Repository](https://github.com/servo/core-foundation-rs)
|
||||||
|
//! - [core-foundation-rs MIT License](https://github.com/servo/core-foundation-rs/blob/master/LICENSE-MIT)
|
||||||
|
//! - [core-foundation-rs Apache License](https://github.com/servo/core-foundation-rs/blob/master/LICENSE-APACHE)
|
||||||
|
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
|
||||||
|
use objc::runtime;
|
||||||
|
pub use objc::runtime::{BOOL, NO, YES};
|
||||||
|
|
||||||
|
pub mod autoreleasepool;
|
||||||
|
pub use autoreleasepool::AutoReleasePool;
|
||||||
|
|
||||||
|
pub mod array;
|
||||||
|
pub use array::NSArray;
|
||||||
|
|
||||||
|
pub mod string;
|
||||||
|
pub use string::NSString;
|
||||||
|
|
||||||
|
pub mod dictionary;
|
||||||
|
pub use dictionary::NSDictionary;
|
||||||
|
|
||||||
|
pub mod geometry;
|
||||||
|
pub use geometry::{CGSize, CGPoint, CGRect};
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub type id = *mut runtime::Object;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub const nil: id = 0 as id;
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
pub type NSInteger = libc::c_int;
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
pub type NSUInteger = libc::c_uint;
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
pub type NSInteger = libc::c_long;
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
pub type NSUInteger = libc::c_ulong;
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
pub type CGFloat = libc::c_double;
|
||||||
|
#[cfg(not(target_pointer_width = "64"))]
|
||||||
|
pub type CGFloat = libc::c_float;
|
56
appkit/src/foundation/string.rs
Normal file
56
appkit/src/foundation/string.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
//! A wrapper library for `NSString`, which we use throughout the framework. This is abstracted out
|
||||||
|
//! for a few reasons, but namely:
|
||||||
|
//!
|
||||||
|
//! - It's used often, so we want a decent enough API.
|
||||||
|
//! - Playing around with performance for this type is ideal, as it's a lot of heap allocation.
|
||||||
|
//!
|
||||||
|
//! End users should never need to interact with this.
|
||||||
|
|
||||||
|
use std::{slice, str};
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
use objc::runtime::Object;
|
||||||
|
use objc_id::Id;
|
||||||
|
|
||||||
|
use crate::foundation::id;
|
||||||
|
|
||||||
|
const UTF8_ENCODING: usize = 4;
|
||||||
|
|
||||||
|
/// Wraps an underlying `NSString`.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct NSString(pub Id<Object>);
|
||||||
|
|
||||||
|
impl NSString {
|
||||||
|
pub fn new(s: &str) -> Self {
|
||||||
|
NSString(unsafe {
|
||||||
|
let nsstring: *mut Object = msg_send![class!(NSString), alloc];
|
||||||
|
//msg_send![nsstring, initWithBytesNoCopy:s.as_ptr() length:s.len() encoding:4 freeWhenDone:NO]
|
||||||
|
Id::from_ptr(msg_send![nsstring, initWithBytes:s.as_ptr() length:s.len() encoding:UTF8_ENCODING])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wrap(object: id) -> Self {
|
||||||
|
NSString(unsafe {
|
||||||
|
Id::from_retained_ptr(object)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_inner(mut self) -> id {
|
||||||
|
&mut *self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A utility method for taking an `NSString` and bridging it to a Rust `&str`.
|
||||||
|
pub fn to_str(self) -> &'static str {
|
||||||
|
unsafe {
|
||||||
|
let bytes = {
|
||||||
|
let bytes: *const c_char = msg_send![&*self.0, UTF8String];
|
||||||
|
bytes as *const u8
|
||||||
|
};
|
||||||
|
|
||||||
|
let len = msg_send![&*self.0, lengthOfBytesUsingEncoding:UTF8_ENCODING];
|
||||||
|
let bytes = slice::from_raw_parts(bytes, len);
|
||||||
|
str::from_utf8(bytes).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
//! Wrapper methods for various geometry types (rects, sizes, ec).
|
//! Wrapper methods for various geometry types (rects, sizes, ec).
|
||||||
|
|
||||||
use cocoa::foundation::{NSRect, NSPoint, NSSize};
|
use crate::foundation::{CGRect, CGPoint, CGSize};
|
||||||
|
|
||||||
/// A struct that represents a box - top, left, width and height.
|
/// A struct that represents a box - top, left, width and height.
|
||||||
pub struct Rect {
|
pub struct Rect {
|
||||||
|
@ -29,11 +29,11 @@ impl Rect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Rect> for NSRect {
|
impl From<Rect> for CGRect {
|
||||||
fn from(rect: Rect) -> NSRect {
|
fn from(rect: Rect) -> CGRect {
|
||||||
NSRect::new(
|
CGRect::new(
|
||||||
NSPoint::new(rect.top, rect.left),
|
&CGPoint::new(rect.top, rect.left),
|
||||||
NSSize::new(rect.width, rect.height)
|
&CGSize::new(rect.width, rect.height)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
//! escape hatch, if you need it (we use it for things like width and height, which aren't handled
|
//! escape hatch, if you need it (we use it for things like width and height, which aren't handled
|
||||||
//! by an axis).
|
//! by an axis).
|
||||||
|
|
||||||
use cocoa::base::id;
|
|
||||||
use core_graphics::base::CGFloat;
|
|
||||||
|
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
|
|
||||||
|
use crate::foundation::{id, CGFloat};
|
||||||
|
|
||||||
/// A wrapper for `NSLayoutConstraint`. This both acts as a central path through which to activate
|
/// A wrapper for `NSLayoutConstraint`. This both acts as a central path through which to activate
|
||||||
/// constraints, as well as a wrapper for layout constraints that are not axis bound (e.g, width or
|
/// constraints, as well as a wrapper for layout constraints that are not axis bound (e.g, width or
|
||||||
/// height).
|
/// height).
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
//! A wrapper for `NSLayoutAnchorDimension`, which is typically used to handle `width` and `height`
|
//! A wrapper for `NSLayoutAnchorDimension`, which is typically used to handle `width` and `height`
|
||||||
//! values for how a given view should layout.
|
//! values for how a given view should layout.
|
||||||
|
|
||||||
use cocoa::base::id;
|
|
||||||
use core_graphics::base::CGFloat;
|
|
||||||
|
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{msg_send, sel, sel_impl};
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
|
|
||||||
|
use crate::foundation::{id, CGFloat};
|
||||||
use crate::layout::constraint::LayoutConstraint;
|
use crate::layout::constraint::LayoutConstraint;
|
||||||
|
|
||||||
/// A wrapper for `NSLayoutAnchor`. You should never be creating this yourself - it's more of a
|
/// A wrapper for `NSLayoutAnchor`. You should never be creating this yourself - it's more of a
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
//! given view should layout along the x-axis. Of note: the only thing that can't be protected
|
//! given view should layout along the x-axis. Of note: the only thing that can't be protected
|
||||||
//! against is mixing/matching incorrect left/leading and right/trailing anchors. Be careful!
|
//! against is mixing/matching incorrect left/leading and right/trailing anchors. Be careful!
|
||||||
|
|
||||||
use cocoa::base::id;
|
|
||||||
|
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{msg_send, sel, sel_impl};
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
|
|
||||||
|
use crate::foundation::id;
|
||||||
use crate::layout::constraint::LayoutConstraint;
|
use crate::layout::constraint::LayoutConstraint;
|
||||||
|
|
||||||
/// A wrapper for `NSLayoutAnchor`. You should never be creating this yourself - it's more of a
|
/// A wrapper for `NSLayoutAnchor`. You should never be creating this yourself - it's more of a
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
//! given view should layout along the x-axis. Of note: the only thing that can't be protected
|
//! given view should layout along the x-axis. Of note: the only thing that can't be protected
|
||||||
//! against is mixing/matching incorrect left/leading and right/trailing anchors. Be careful!
|
//! against is mixing/matching incorrect left/leading and right/trailing anchors. Be careful!
|
||||||
|
|
||||||
use cocoa::base::id;
|
|
||||||
|
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{msg_send, sel, sel_impl};
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
|
|
||||||
|
use crate::foundation::id;
|
||||||
use crate::layout::constraint::LayoutConstraint;
|
use crate::layout::constraint::LayoutConstraint;
|
||||||
|
|
||||||
/// A wrapper for `NSLayoutAnchor`. You should never be creating this yourself - it's more of a
|
/// A wrapper for `NSLayoutAnchor`. You should never be creating this yourself - it's more of a
|
||||||
|
|
|
@ -16,15 +16,11 @@
|
||||||
//! your own risk. With that said, provided you follow the rules (regarding memory/ownership) it's
|
//! your own risk. With that said, provided you follow the rules (regarding memory/ownership) it's
|
||||||
//! already fine for some apps. Check the README for more info!
|
//! already fine for some apps. Check the README for more info!
|
||||||
|
|
||||||
pub use objc_id::ShareId;
|
|
||||||
pub use objc::runtime::Object;
|
|
||||||
pub use cocoa::base::id;
|
|
||||||
|
|
||||||
pub mod alert;
|
pub mod alert;
|
||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod button;
|
pub mod button;
|
||||||
|
|
||||||
#[cfg(feature = "user-notifications")]
|
#[cfg(feature = "cloudkit")]
|
||||||
pub mod cloudkit;
|
pub mod cloudkit;
|
||||||
|
|
||||||
pub mod color;
|
pub mod color;
|
||||||
|
@ -33,7 +29,8 @@ pub mod constants;
|
||||||
pub mod dragdrop;
|
pub mod dragdrop;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod filesystem;
|
//pub mod filesystem;
|
||||||
|
pub mod foundation;
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod menu;
|
pub mod menu;
|
||||||
|
@ -47,7 +44,7 @@ pub mod printing;
|
||||||
pub mod toolbar;
|
pub mod toolbar;
|
||||||
pub mod user_activity;
|
pub mod user_activity;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod view;
|
/*pub mod view;
|
||||||
pub mod webview;
|
pub mod webview;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
|
|
||||||
|
@ -81,4 +78,4 @@ pub mod prelude {
|
||||||
pub use appkit_derive::{
|
pub use appkit_derive::{
|
||||||
WindowWrapper, ViewWrapper
|
WindowWrapper, ViewWrapper
|
||||||
};
|
};
|
||||||
}
|
}*/
|
||||||
|
|
|
@ -2,13 +2,11 @@
|
||||||
//! one level deep; this could change in the future but is fine for
|
//! one level deep; this could change in the future but is fine for
|
||||||
//! now.
|
//! now.
|
||||||
|
|
||||||
use cocoa::base::{id, nil};
|
|
||||||
use cocoa::foundation::{NSString, NSUInteger};
|
|
||||||
|
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
use objc::runtime::{Object, Sel};
|
use objc::runtime::{Object, Sel};
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
|
|
||||||
|
use crate::foundation::{id, nil, NSString, NSUInteger};
|
||||||
use crate::events::EventModifierFlag;
|
use crate::events::EventModifierFlag;
|
||||||
|
|
||||||
/// Internal method (shorthand) for generating `NSMenuItem` holders.
|
/// Internal method (shorthand) for generating `NSMenuItem` holders.
|
||||||
|
@ -21,10 +19,10 @@ fn make_menu_item(
|
||||||
unsafe {
|
unsafe {
|
||||||
let cls = class!(NSMenuItem);
|
let cls = class!(NSMenuItem);
|
||||||
let alloc: id = msg_send![cls, alloc];
|
let alloc: id = msg_send![cls, alloc];
|
||||||
let title = NSString::alloc(nil).init_str(title);
|
let title = NSString::new(title);
|
||||||
|
|
||||||
// Note that AppKit requires a blank string if nil, not nil.
|
// Note that AppKit requires a blank string if nil, not nil.
|
||||||
let key = NSString::alloc(nil).init_str(match key {
|
let key = NSString::new(match key {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => ""
|
None => ""
|
||||||
});
|
});
|
||||||
|
@ -74,7 +72,7 @@ impl MenuItem {
|
||||||
|
|
||||||
MenuItem::Action(item) => {
|
MenuItem::Action(item) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
let key = NSString::alloc(nil).init_str(key);
|
let key = NSString::new(key);
|
||||||
let _: () = msg_send![&*item, setKeyEquivalent:key];
|
let _: () = msg_send![&*item, setKeyEquivalent:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
//! Wraps NSMenu and handles instrumenting necessary delegate pieces.
|
//! Wraps NSMenu and handles instrumenting necessary delegate pieces.
|
||||||
|
|
||||||
use cocoa::base::{id, nil};
|
|
||||||
use cocoa::foundation::NSString;
|
|
||||||
|
|
||||||
use objc_id::Id;
|
use objc_id::Id;
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
|
use crate::foundation::{id, NSString};
|
||||||
use crate::menu::item::MenuItem;
|
use crate::menu::item::MenuItem;
|
||||||
|
|
||||||
/// A struct that represents an `NSMenu`. It takes ownership of items, and handles instrumenting
|
/// A struct that represents an `NSMenu`. It takes ownership of items, and handles instrumenting
|
||||||
|
@ -23,7 +21,7 @@ impl Menu {
|
||||||
let inner = unsafe {
|
let inner = unsafe {
|
||||||
let cls = class!(NSMenu);
|
let cls = class!(NSMenu);
|
||||||
let alloc: id = msg_send![cls, alloc];
|
let alloc: id = msg_send![cls, alloc];
|
||||||
let title = NSString::alloc(nil).init_str(title);
|
let title = NSString::new(title);
|
||||||
let inner: id = msg_send![alloc, initWithTitle:title];
|
let inner: id = msg_send![alloc, initWithTitle:title];
|
||||||
Id::from_ptr(inner)
|
Id::from_ptr(inner)
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
//! A lightweight wrapper over some networking components, like `NSURLRequest` and co.
|
//! A lightweight wrapper over some networking components, like `NSURLRequest` and co.
|
||||||
//! This is currently not meant to be exhaustive.
|
//! This is currently not meant to be exhaustive.
|
||||||
|
|
||||||
use cocoa::base::id;
|
|
||||||
use objc_id::Id;
|
|
||||||
|
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{msg_send, sel, sel_impl};
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
|
use objc_id::Id;
|
||||||
|
|
||||||
use crate::utils::str_from;
|
use crate::foundation::{id, NSString};
|
||||||
|
|
||||||
pub struct URLRequest {
|
pub struct URLRequest {
|
||||||
pub inner: Id<Object>
|
pub inner: Id<Object>
|
||||||
|
@ -21,10 +19,9 @@ impl URLRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn url(&self) -> &'static str {
|
pub fn url(&self) -> &'static str {
|
||||||
unsafe {
|
NSString::wrap(unsafe {
|
||||||
let url: id = msg_send![&*self.inner, URL];
|
let url: id = msg_send![&*self.inner, URL];
|
||||||
let path: id = msg_send![url, absoluteString];
|
msg_send![url, absoluteString]
|
||||||
str_from(path)
|
}).to_str()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,96 @@
|
||||||
|
//! A wrapper for NSPasteBoard, which is the interface for copy/paste and general transferring
|
||||||
|
//! (think: drag and drop between applications). It exposes a Rust interface that tries to be
|
||||||
|
//! complete, but might not cover everything 100% right now - feel free to pull request.
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use objc::runtime::Object;
|
||||||
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
use objc_id::Id;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::foundation::{id, nil, NSString, NSArray};
|
||||||
|
use crate::error::AppKitError;
|
||||||
|
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub use types::*;
|
pub use types::{PasteboardName, PasteboardType};
|
||||||
|
|
||||||
pub mod pasteboard;
|
/// Represents an `NSPasteboard`, enabling you to handle copy/paste/drag and drop.
|
||||||
pub use pasteboard::*;
|
pub struct Pasteboard(pub Id<Object>);
|
||||||
|
|
||||||
|
impl Default for Pasteboard {
|
||||||
|
fn default() -> Self {
|
||||||
|
Pasteboard(unsafe {
|
||||||
|
Id::from_retained_ptr(msg_send![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 {
|
||||||
|
Id::from_retained_ptr(existing)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the system Pasteboard for the given name/type.
|
||||||
|
pub fn named(name: PasteboardName) -> Self {
|
||||||
|
Pasteboard(unsafe {
|
||||||
|
let name: NSString = name.into();
|
||||||
|
Id::from_retained_ptr(msg_send![class!(NSPasteboard), pasteboardWithName:&*name.0])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
Id::from_ptr(msg_send![class!(NSPasteboard), pasteboardWithUniqueName])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Releases the receiver’s resources in the pasteboard server. It's rare-ish to need to use
|
||||||
|
/// this, but considering this stuff happens on the Objective-C side you may need it.
|
||||||
|
pub fn release_globally(&self) {
|
||||||
|
unsafe {
|
||||||
|
let _: () = msg_send![&*self.0, releaseGlobally];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the existing contents of the pasteboard.
|
||||||
|
pub fn clear_contents(&self) {
|
||||||
|
unsafe {
|
||||||
|
let _: () = msg_send![&*self.0, clearContents];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Looks inside the pasteboard contents and extracts what FileURLs are there, if any.
|
||||||
|
pub fn get_file_urls(&self) -> Result<Vec<Url>, Box<dyn Error>> {
|
||||||
|
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];
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
if contents == nil {
|
||||||
|
// This error is not necessarily "correct", but in the event of an error in
|
||||||
|
// Pasteboard server retrieval I'm not sure where to check... and this stuff is
|
||||||
|
// kinda ancient and has conflicting docs in places. ;P
|
||||||
|
return Err(Box::new(AppKitError {
|
||||||
|
code: 666,
|
||||||
|
domain: "com.appkit-rs.pasteboard".to_string(),
|
||||||
|
description: "Pasteboard server returned no data.".to_string()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
let urls = NSArray::wrap(contents).map(|url| {
|
||||||
|
let path = NSString::wrap(msg_send![url, path]);
|
||||||
|
Url::parse(&format!("file://{}", path.to_str()))
|
||||||
|
}).into_iter().filter_map(|r| r.ok()).collect();
|
||||||
|
|
||||||
|
Ok(urls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
//! A wrapper for NSPasteBoard, which is the interface for copy/paste and general transferring
|
|
||||||
//! (think: drag and drop between applications). It exposes a Rust interface that tries to be
|
|
||||||
//! complete, but might not cover everything 100% right now - feel free to pull request.
|
|
||||||
|
|
||||||
use std::error::Error;
|
|
||||||
|
|
||||||
use cocoa::base::{id, nil};
|
|
||||||
use cocoa::foundation::{NSArray};
|
|
||||||
use objc::runtime::Object;
|
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
|
||||||
use objc_id::Id;
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
use crate::error::AppKitError;
|
|
||||||
use crate::pasteboard::types::{PasteboardName};
|
|
||||||
use crate::utils::str_from;
|
|
||||||
|
|
||||||
/// Represents an `NSPasteboard`, enabling you to handle copy/paste/drag and drop.
|
|
||||||
pub struct Pasteboard {
|
|
||||||
/// The internal pointer to the Objective-C side.
|
|
||||||
pub inner: Id<Object>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Pasteboard {
|
|
||||||
fn default() -> Self {
|
|
||||||
Pasteboard {
|
|
||||||
inner: unsafe { Id::from_ptr(msg_send![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 {
|
|
||||||
inner: unsafe { Id::from_ptr(existing) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the system Pasteboard for the given name/type.
|
|
||||||
pub fn named(name: PasteboardName) -> Self {
|
|
||||||
Pasteboard {
|
|
||||||
inner: unsafe {
|
|
||||||
let name = name.to_nsstring();
|
|
||||||
Id::from_ptr(msg_send![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 {
|
|
||||||
inner: unsafe { Id::from_ptr(msg_send![class!(NSPasteboard), pasteboardWithUniqueName]) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Releases the receiver’s resources in the pasteboard server. It's rare-ish to need to use
|
|
||||||
/// this, but considering this stuff happens on the Objective-C side you may need it.
|
|
||||||
pub fn release_globally(&self) {
|
|
||||||
unsafe {
|
|
||||||
let _: () = msg_send![&*self.inner, releaseGlobally];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clears the existing contents of the pasteboard.
|
|
||||||
pub fn clear_contents(&self) {
|
|
||||||
unsafe {
|
|
||||||
let _: () = msg_send![&*self.inner, clearContents];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Looks inside the pasteboard contents and extracts what FileURLs are there, if any.
|
|
||||||
pub fn get_file_urls(&self) -> Result<Vec<Url>, Box<dyn Error>> {
|
|
||||||
unsafe {
|
|
||||||
let mut i = 0;
|
|
||||||
|
|
||||||
let class: id = msg_send![class!(NSURL), class];
|
|
||||||
let classes: id = NSArray::arrayWithObjects(nil, &[class]);
|
|
||||||
let contents: id = msg_send![&*self.inner, 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.
|
|
||||||
if contents == nil {
|
|
||||||
// This error is not necessarily "correct", but in the event of an error in
|
|
||||||
// Pasteboard server retrieval I'm not sure where to check... and this stuff is
|
|
||||||
// kinda ancient and has conflicting docs in places. ;P
|
|
||||||
return Err(Box::new(AppKitError {
|
|
||||||
code: 666,
|
|
||||||
domain: "com.appkit-rs.pasteboard".to_string(),
|
|
||||||
description: "Pasteboard server returned no data.".to_string()
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
let count: usize = msg_send![contents, count];
|
|
||||||
let mut urls: Vec<Url> = Vec::with_capacity(count);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let nsurl: id = msg_send![contents, objectAtIndex:i];
|
|
||||||
let path: id = msg_send![nsurl, path];
|
|
||||||
let s = str_from(path);
|
|
||||||
urls.push(Url::parse(&format!("file://{}", s))?);
|
|
||||||
|
|
||||||
i += 1;
|
|
||||||
if i == count { break; }
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(urls)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
/// Retrieves the pasteboard contents as a string. This can be `None` (`nil` on the Objective-C
|
|
||||||
/// side) if the pasteboard data doesn't match the requested type, so check accordingly.
|
|
||||||
///
|
|
||||||
/// Note: In macOS 10.6 and later, if the receiver contains multiple items that can provide string,
|
|
||||||
/// RTF, or RTFD data, the text data from each item is returned as a combined result separated by newlines.
|
|
||||||
/// This Rust wrapper is a quick pass, and could be improved. ;P
|
|
||||||
pub fn contents_for(&self, pasteboard_type: PasteboardType) -> Option<String> {
|
|
||||||
unsafe {
|
|
||||||
let contents: id = msg_send![&*self.inner, stringForType:pasteboard_type.to_nsstring()];
|
|
||||||
if contents != nil {
|
|
||||||
return Some(str_from(contents).to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}*/
|
|
||||||
}
|
|
|
@ -1,8 +1,7 @@
|
||||||
//! This module provides some basic wrappers for Pasteboard functionality. It's currently not an
|
//! This module provides some basic wrappers for Pasteboard functionality. It's currently not an
|
||||||
//! exhaustive clone, but feel free to pull request accordingly!
|
//! exhaustive clone, but feel free to pull request accordingly!
|
||||||
|
|
||||||
use cocoa::base::{id, nil};
|
use crate::foundation::NSString;
|
||||||
use cocoa::foundation::NSString;
|
|
||||||
|
|
||||||
/// Constants for the standard system pasteboard names.
|
/// Constants for the standard system pasteboard names.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
@ -23,11 +22,9 @@ pub enum PasteboardName {
|
||||||
Ruler
|
Ruler
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PasteboardName {
|
impl From<PasteboardName> for NSString {
|
||||||
/// Creates an `NSString` out of the underlying type.
|
fn from(name: PasteboardName) -> Self {
|
||||||
pub fn to_nsstring(&self) -> id {
|
NSString::new(match name {
|
||||||
unsafe {
|
|
||||||
NSString::alloc(nil).init_str(match self {
|
|
||||||
PasteboardName::Drag => "Apple CFPasteboard drag",
|
PasteboardName::Drag => "Apple CFPasteboard drag",
|
||||||
PasteboardName::Find => "Apple CFPasteboard find",
|
PasteboardName::Find => "Apple CFPasteboard find",
|
||||||
PasteboardName::Font => "Apple CFPasteboard font",
|
PasteboardName::Font => "Apple CFPasteboard font",
|
||||||
|
@ -35,7 +32,6 @@ impl PasteboardName {
|
||||||
PasteboardName::Ruler => "Apple CFPasteboard ruler"
|
PasteboardName::Ruler => "Apple CFPasteboard ruler"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents different Pasteboard types that can be referred to.
|
/// Represents different Pasteboard types that can be referred to.
|
||||||
|
@ -87,11 +83,9 @@ pub enum PasteboardType {
|
||||||
TIFF
|
TIFF
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PasteboardType {
|
impl From<PasteboardType> for NSString {
|
||||||
/// Creates an `NSString` out of the underlying type.
|
fn from(pboard_type: PasteboardType) -> Self {
|
||||||
pub fn to_nsstring(&self) -> id {
|
NSString::new(match pboard_type {
|
||||||
unsafe {
|
|
||||||
NSString::alloc(nil).init_str(match self {
|
|
||||||
PasteboardType::URL => "public.url",
|
PasteboardType::URL => "public.url",
|
||||||
PasteboardType::Color => "com.apple.cocoa.pasteboard.color",
|
PasteboardType::Color => "com.apple.cocoa.pasteboard.color",
|
||||||
PasteboardType::FileURL => "public.file-url",
|
PasteboardType::FileURL => "public.file-url",
|
||||||
|
@ -109,5 +103,4 @@ impl PasteboardType {
|
||||||
PasteboardType::TIFF => "public.tiff",
|
PasteboardType::TIFF => "public.tiff",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
32
appkit/src/printing/enums.rs
Normal file
32
appkit/src/printing/enums.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
//! Enums used through the general printing flow.
|
||||||
|
|
||||||
|
use crate::foundation::NSUInteger;
|
||||||
|
|
||||||
|
/// Used for handling printing files. You return this in relevant `AppController` methods.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum PrintResponse {
|
||||||
|
/// Printing was cancelled.
|
||||||
|
Cancelled,
|
||||||
|
|
||||||
|
/// Printing was a success.
|
||||||
|
Success,
|
||||||
|
|
||||||
|
/// Printing failed.
|
||||||
|
Failure,
|
||||||
|
|
||||||
|
/// For when the result of printing cannot be returned immediately (e.g, if printing causes a sheet to appear).
|
||||||
|
/// If your method returns PrintResponse::ReplyLater it must always invoke `App::reply_to_open_or_print()` when the
|
||||||
|
/// entire print operation has been completed, successfully or not.
|
||||||
|
ReplyLater
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PrintResponse> for NSUInteger {
|
||||||
|
fn from(response: PrintResponse) -> NSUInteger {
|
||||||
|
match response {
|
||||||
|
PrintResponse::Cancelled => 0,
|
||||||
|
PrintResponse::Success => 1,
|
||||||
|
PrintResponse::Failure => 3,
|
||||||
|
PrintResponse::ReplyLater => 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,8 @@
|
||||||
//! Implements types used for printing (both configuring print jobs, as well as the act of printing
|
//! Implements types used for printing (both configuring print jobs, as well as the act of printing
|
||||||
//! itself).
|
//! itself).
|
||||||
|
|
||||||
|
pub mod enums;
|
||||||
|
pub use enums::PrintResponse;
|
||||||
|
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub use settings::PrintSettings;
|
pub use settings::PrintSettings;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
//! Represents settings for printing items. Backed by an `NSDictionary` in Objective-C, this struct
|
//! Represents settings for printing items. Backed by an `NSDictionary` in Objective-C, this struct
|
||||||
//! aims to make it easier to query/process printing operations.
|
//! aims to make it easier to query/process printing operations.
|
||||||
|
|
||||||
use cocoa::base::id;
|
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
|
|
||||||
|
use crate::foundation::id;
|
||||||
|
|
||||||
/// `PrintSettings` represents options used in printing, typically passed to you by the
|
/// `PrintSettings` represents options used in printing, typically passed to you by the
|
||||||
/// application/user.
|
/// application/user.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
|
@ -3,58 +3,51 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
|
|
||||||
use cocoa::base::{id, nil};
|
|
||||||
use cocoa::foundation::{NSArray, NSString};
|
|
||||||
|
|
||||||
use objc::declare::ClassDecl;
|
use objc::declare::ClassDecl;
|
||||||
use objc::runtime::{Class, Object, Sel};
|
use objc::runtime::{Class, Object, Sel};
|
||||||
use objc::{class, sel, sel_impl};
|
use objc::{class, sel, sel_impl};
|
||||||
|
|
||||||
|
use crate::foundation::{id, NSArray, NSString};
|
||||||
use crate::constants::TOOLBAR_PTR;
|
use crate::constants::TOOLBAR_PTR;
|
||||||
use crate::toolbar::traits::ToolbarController;
|
use crate::toolbar::traits::ToolbarController;
|
||||||
use crate::utils::{load, str_from};
|
use crate::utils::load;
|
||||||
|
|
||||||
/// Retrieves and passes the allowed item identifiers for this toolbar.
|
/// Retrieves and passes the allowed item identifiers for this toolbar.
|
||||||
extern fn allowed_item_identifiers<T: ToolbarController>(this: &Object, _: Sel, _: id) -> id {
|
extern fn allowed_item_identifiers<T: ToolbarController>(this: &Object, _: Sel, _: id) -> id {
|
||||||
let toolbar = load::<T>(this, TOOLBAR_PTR);
|
let toolbar = load::<T>(this, TOOLBAR_PTR);
|
||||||
|
|
||||||
unsafe {
|
let identifiers: NSArray = {
|
||||||
let identifiers = {
|
|
||||||
let t = toolbar.borrow();
|
let t = toolbar.borrow();
|
||||||
|
|
||||||
(*t).allowed_item_identifiers().iter().map(|identifier| {
|
(*t).allowed_item_identifiers().iter().map(|identifier| {
|
||||||
NSString::alloc(nil).init_str(identifier)
|
NSString::new(identifier).into_inner()
|
||||||
}).collect::<Vec<id>>()
|
}).collect::<Vec<id>>().into()
|
||||||
};
|
};
|
||||||
|
|
||||||
Rc::into_raw(toolbar);
|
Rc::into_raw(toolbar);
|
||||||
NSArray::arrayWithObjects(nil, &identifiers)
|
identifiers.into_inner()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves and passes the default item identifiers for this toolbar.
|
/// Retrieves and passes the default item identifiers for this toolbar.
|
||||||
extern fn default_item_identifiers<T: ToolbarController>(this: &Object, _: Sel, _: id) -> id {
|
extern fn default_item_identifiers<T: ToolbarController>(this: &Object, _: Sel, _: id) -> id {
|
||||||
let toolbar = load::<T>(this, TOOLBAR_PTR);
|
let toolbar = load::<T>(this, TOOLBAR_PTR);
|
||||||
|
|
||||||
unsafe {
|
let identifiers: NSArray = {
|
||||||
let identifiers = {
|
|
||||||
let t = toolbar.borrow();
|
let t = toolbar.borrow();
|
||||||
|
|
||||||
(*t).default_item_identifiers().iter().map(|identifier| {
|
(*t).default_item_identifiers().iter().map(|identifier| {
|
||||||
NSString::alloc(nil).init_str(identifier)
|
NSString::new(identifier).into_inner()
|
||||||
}).collect::<Vec<id>>()
|
}).collect::<Vec<id>>().into()
|
||||||
};
|
};
|
||||||
|
|
||||||
Rc::into_raw(toolbar);
|
Rc::into_raw(toolbar);
|
||||||
NSArray::arrayWithObjects(nil, &identifiers)
|
identifiers.into_inner()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads the controller, grabs whatever item is for this identifier, and returns what the
|
/// Loads the controller, grabs whatever item is for this identifier, and returns what the
|
||||||
/// Objective-C runtime needs.
|
/// Objective-C runtime needs.
|
||||||
extern fn item_for_identifier<T: ToolbarController>(this: &Object, _: Sel, _: id, identifier: id, _: id) -> id {
|
extern fn item_for_identifier<T: ToolbarController>(this: &Object, _: Sel, _: id, identifier: id, _: id) -> id {
|
||||||
let toolbar = load::<T>(this, TOOLBAR_PTR);
|
let toolbar = load::<T>(this, TOOLBAR_PTR);
|
||||||
let identifier = str_from(identifier);
|
let identifier = NSString::wrap(identifier).to_str();
|
||||||
|
|
||||||
let mut item = {
|
let mut item = {
|
||||||
let t = toolbar.borrow();
|
let t = toolbar.borrow();
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
//! A wrapper for the underlying `NSToolbar`, which is safe to clone and pass around. We do this to
|
//! A wrapper for the underlying `NSToolbar`, which is safe to clone and pass around. We do this to
|
||||||
//! provide a uniform and expectable API.
|
//! provide a uniform and expectable API.
|
||||||
|
|
||||||
use cocoa::base::{YES, NO};
|
|
||||||
use cocoa::foundation::{NSUInteger};
|
|
||||||
|
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{msg_send, sel, sel_impl};
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
|
|
||||||
|
use crate::foundation::{YES, NO, NSUInteger};
|
||||||
use crate::toolbar::types::{ToolbarDisplayMode, ToolbarSizeMode};
|
use crate::toolbar::types::{ToolbarDisplayMode, ToolbarSizeMode};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|
|
@ -3,13 +3,11 @@
|
||||||
//!
|
//!
|
||||||
//! UNFORTUNATELY, this is a very old and janky API. So... yeah.
|
//! UNFORTUNATELY, this is a very old and janky API. So... yeah.
|
||||||
|
|
||||||
use cocoa::base::{id, nil};
|
|
||||||
use cocoa::foundation::{NSSize, NSString};
|
|
||||||
|
|
||||||
use objc_id::Id;
|
use objc_id::Id;
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
|
use crate::foundation::{id, CGSize, NSString};
|
||||||
use crate::button::Button;
|
use crate::button::Button;
|
||||||
|
|
||||||
/// A wrapper for `NSWindow`. Holds (retains) pointers for the Objective-C runtime
|
/// A wrapper for `NSWindow`. Holds (retains) pointers for the Objective-C runtime
|
||||||
|
@ -28,7 +26,7 @@ impl ToolbarItem {
|
||||||
let identifier = identifier.into();
|
let identifier = identifier.into();
|
||||||
|
|
||||||
let inner = unsafe {
|
let inner = unsafe {
|
||||||
let identifr = NSString::alloc(nil).init_str(&identifier);
|
let identifr = NSString::new(&identifier);
|
||||||
let alloc: id = msg_send![class!(NSToolbarItem), alloc];
|
let alloc: id = msg_send![class!(NSToolbarItem), alloc];
|
||||||
let item: id = msg_send![alloc, initWithItemIdentifier:identifr];
|
let item: id = msg_send![alloc, initWithItemIdentifier:identifr];
|
||||||
Id::from_ptr(item)
|
Id::from_ptr(item)
|
||||||
|
@ -44,7 +42,7 @@ impl ToolbarItem {
|
||||||
/// Sets the title for this item.
|
/// Sets the title for this item.
|
||||||
pub fn set_title(&mut self, title: &str) {
|
pub fn set_title(&mut self, title: &str) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let title = NSString::alloc(nil).init_str(title);
|
let title = NSString::new(title);
|
||||||
let _: () = msg_send![&*self.inner, setTitle:title];
|
let _: () = msg_send![&*self.inner, setTitle:title];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +61,7 @@ impl ToolbarItem {
|
||||||
/// Sets the minimum size for this button.
|
/// Sets the minimum size for this button.
|
||||||
pub fn set_min_size(&mut self, width: f64, height: f64) {
|
pub fn set_min_size(&mut self, width: f64, height: f64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let size = NSSize::new(width.into(), height.into());
|
let size = CGSize::new(width.into(), height.into());
|
||||||
let _: () = msg_send![&*self.inner, setMinSize:size];
|
let _: () = msg_send![&*self.inner, setMinSize:size];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +69,7 @@ impl ToolbarItem {
|
||||||
/// Sets the maximum size for this button.
|
/// Sets the maximum size for this button.
|
||||||
pub fn set_max_size(&mut self, width: f64, height: f64) {
|
pub fn set_max_size(&mut self, width: f64, height: f64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let size = NSSize::new(width.into(), height.into());
|
let size = CGSize::new(width.into(), height.into());
|
||||||
let _: () = msg_send![&*self.inner, setMaxSize:size];
|
let _: () = msg_send![&*self.inner, setMaxSize:size];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,10 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use cocoa::base::{id, nil};
|
|
||||||
use cocoa::foundation::NSString;
|
|
||||||
|
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
use objc::{msg_send, sel, sel_impl};
|
use objc::{msg_send, sel, sel_impl};
|
||||||
|
|
||||||
|
use crate::foundation::{id, NSString};
|
||||||
use crate::constants::TOOLBAR_PTR;
|
use crate::constants::TOOLBAR_PTR;
|
||||||
use crate::toolbar::class::register_toolbar_class;
|
use crate::toolbar::class::register_toolbar_class;
|
||||||
use crate::toolbar::handle::ToolbarHandle;
|
use crate::toolbar::handle::ToolbarHandle;
|
||||||
|
@ -49,7 +47,7 @@ impl<T> Toolbar<T> where T: ToolbarController + 'static {
|
||||||
|
|
||||||
let objc_controller = unsafe {
|
let objc_controller = unsafe {
|
||||||
let delegate_class = register_toolbar_class::<T>();
|
let delegate_class = register_toolbar_class::<T>();
|
||||||
let identifier = NSString::alloc(nil).init_str(&identifier);
|
let identifier = NSString::new(&identifier);
|
||||||
let alloc: id = msg_send![delegate_class, alloc];
|
let alloc: id = msg_send![delegate_class, alloc];
|
||||||
let toolbar: id = msg_send![alloc, initWithIdentifier:identifier];
|
let toolbar: id = msg_send![alloc, initWithIdentifier:identifier];
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Various types used for Toolbar configuration.
|
//! Various types used for Toolbar configuration.
|
||||||
|
|
||||||
use cocoa::foundation::NSUInteger;
|
use crate::foundation::NSUInteger;
|
||||||
|
|
||||||
/// Represents the display mode(s) a Toolbar can render in.
|
/// Represents the display mode(s) a Toolbar can render in.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
//! A module wrapping `NSUserActivity`.
|
//! A module wrapping `NSUserActivity`.
|
||||||
|
|
||||||
use cocoa::base::id;
|
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
|
|
||||||
|
use crate::foundation::id;
|
||||||
|
|
||||||
/// Represents an `NSUserActivity`, which acts as a lightweight method to capture the state of your
|
/// Represents an `NSUserActivity`, which acts as a lightweight method to capture the state of your
|
||||||
/// app.
|
/// app.
|
||||||
pub struct UserActivity {
|
pub struct UserActivity {
|
||||||
|
|
|
@ -4,51 +4,9 @@
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::{slice, str};
|
|
||||||
use std::os::raw::c_char;
|
|
||||||
|
|
||||||
use cocoa::base::id;
|
|
||||||
use cocoa::foundation::NSString;
|
|
||||||
|
|
||||||
use objc::{msg_send, sel, sel_impl};
|
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
|
|
||||||
/// A utility method for taking an `NSString` and bridging it to a Rust `&str`.
|
|
||||||
pub fn str_from(nsstring: id) -> &'static str {
|
|
||||||
unsafe {
|
|
||||||
let bytes = {
|
|
||||||
let bytes: *const c_char = msg_send![nsstring, UTF8String];
|
|
||||||
bytes as *const u8
|
|
||||||
};
|
|
||||||
|
|
||||||
let len = nsstring.len();
|
|
||||||
let bytes = slice::from_raw_parts(bytes, len);
|
|
||||||
str::from_utf8(bytes).unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A utility method for mapping over NSArray instances. There's a number of places where we want
|
|
||||||
/// or need this functionality to provide Rust interfaces - this tries to do it in a way where the
|
|
||||||
/// `Vec` doesn't need to resize after being allocated.
|
|
||||||
pub fn map_nsarray<T, F>(array: id, transform: F) -> Vec<T>
|
|
||||||
where F: Fn(id) -> T {
|
|
||||||
let count: usize = unsafe { msg_send![array, count] };
|
|
||||||
|
|
||||||
let mut ret: Vec<T> = Vec::with_capacity(count);
|
|
||||||
let mut index = 0;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let file: id = unsafe { msg_send![array, objectAtIndex:index] };
|
|
||||||
ret.push(transform(file));
|
|
||||||
|
|
||||||
index += 1;
|
|
||||||
if index == count { break }
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Used for moving a pointer back into an Rc, so we can work with the object held behind it. Note
|
/// Used for moving a pointer back into an Rc, so we can work with the object held behind it. Note
|
||||||
/// that it's very important to make sure you reverse this when you're done (using
|
/// that it's very important to make sure you reverse this when you're done (using
|
||||||
/// `Rc::into_raw()`) otherwise you'll cause problems due to the `Drop` logic.
|
/// `Rc::into_raw()`) otherwise you'll cause problems due to the `Drop` logic.
|
||||||
|
|
|
@ -9,13 +9,13 @@ use std::ffi::c_void;
|
||||||
|
|
||||||
use block::Block;
|
use block::Block;
|
||||||
|
|
||||||
use cocoa::base::{id, nil, YES, NO};
|
|
||||||
use cocoa::foundation::{NSRect, NSPoint, NSSize, NSString, NSArray, NSInteger};
|
use cocoa::foundation::{NSRect, NSPoint, NSSize, NSString, NSArray, NSInteger};
|
||||||
|
|
||||||
use objc::declare::ClassDecl;
|
use objc::declare::ClassDecl;
|
||||||
use objc::runtime::{Class, Object, Sel, BOOL};
|
use objc::runtime::{Class, Object, Sel, BOOL};
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
|
use crate::foundation::{id, nil, YES, NO};
|
||||||
use crate::webview::traits::WebViewController;
|
use crate::webview::traits::WebViewController;
|
||||||
|
|
||||||
extern fn download_delegate(this: &Object, _: Sel) -> id {
|
extern fn download_delegate(this: &Object, _: Sel) -> id {
|
||||||
|
|
|
@ -11,13 +11,11 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use cocoa::base::{id, nil, YES, NO};
|
|
||||||
use cocoa::foundation::NSString;
|
|
||||||
|
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
use objc::{class, msg_send, sel, sel_impl};
|
||||||
|
|
||||||
|
use crate::foundation::{id, nil, YES, NO, NSString};
|
||||||
use crate::constants::{WEBVIEW_VAR, WEBVIEW_CONFIG_VAR, WEBVIEW_CONTROLLER_PTR};
|
use crate::constants::{WEBVIEW_VAR, WEBVIEW_CONFIG_VAR, WEBVIEW_CONTROLLER_PTR};
|
||||||
use crate::view::ViewController;
|
use crate::view::ViewController;
|
||||||
use crate::webview::config::{WebViewConfig, InjectAt};
|
use crate::webview::config::{WebViewConfig, InjectAt};
|
||||||
|
|
Loading…
Reference in a new issue