From d69f59d284c001df1233e65ba468bd3b11182e7c Mon Sep 17 00:00:00 2001 From: Ryan McGrath Date: Sun, 29 Mar 2020 22:33:51 -0700 Subject: [PATCH] Further work on splitting for macOS/iOS support --- Cargo.toml | 2 + examples/autolayout.rs | 12 ++- examples/window.rs | 4 +- examples/window_controller.rs | 4 +- examples/window_delegate.rs | 6 +- src/lib.rs | 16 ++-- src/{ => macos}/app/class.rs | 0 src/{ => macos}/app/delegate.rs | 97 ++++++---------------- src/{ => macos}/app/enums.rs | 0 src/{ => macos}/app/mod.rs | 10 +-- src/{ => macos}/app/traits.rs | 32 ++----- src/{ => macos}/menu/item.rs | 0 src/{ => macos}/menu/menu.rs | 2 +- src/{ => macos}/menu/mod.rs | 0 src/macos/mod.rs | 22 +++++ src/{ => macos}/printing/enums.rs | 0 src/{ => macos}/printing/mod.rs | 0 src/{ => macos}/printing/settings.rs | 0 src/{ => macos}/toolbar/class.rs | 2 +- src/{ => macos}/toolbar/enums.rs | 0 src/{ => macos}/toolbar/item.rs | 0 src/{ => macos}/toolbar/mod.rs | 0 src/{ => macos}/toolbar/traits.rs | 2 +- src/{ => macos}/window/class.rs | 2 +- src/{ => macos}/window/config.rs | 2 +- src/{ => macos}/window/controller/class.rs | 2 +- src/{ => macos}/window/controller/mod.rs | 6 +- src/{ => macos}/window/enums.rs | 0 src/{ => macos}/window/mod.rs | 2 +- src/{ => macos}/window/traits.rs | 4 +- src/pasteboard/mod.rs | 2 +- src/view/class.rs | 77 +++++------------ src/view/controller/class.rs | 33 +------- src/view/controller/mod.rs | 10 +-- src/view/mod.rs | 36 ++------ src/view/traits.rs | 2 +- 36 files changed, 132 insertions(+), 257 deletions(-) rename src/{ => macos}/app/class.rs (100%) rename src/{ => macos}/app/delegate.rs (75%) rename src/{ => macos}/app/enums.rs (100%) rename src/{ => macos}/app/mod.rs (96%) rename src/{ => macos}/app/traits.rs (93%) rename src/{ => macos}/menu/item.rs (100%) rename src/{ => macos}/menu/menu.rs (97%) rename src/{ => macos}/menu/mod.rs (100%) create mode 100644 src/macos/mod.rs rename src/{ => macos}/printing/enums.rs (100%) rename src/{ => macos}/printing/mod.rs (100%) rename src/{ => macos}/printing/settings.rs (100%) rename src/{ => macos}/toolbar/class.rs (97%) rename src/{ => macos}/toolbar/enums.rs (100%) rename src/{ => macos}/toolbar/item.rs (100%) rename src/{ => macos}/toolbar/mod.rs (100%) rename src/{ => macos}/toolbar/traits.rs (95%) rename src/{ => macos}/window/class.rs (99%) rename src/{ => macos}/window/config.rs (97%) rename src/{ => macos}/window/controller/class.rs (93%) rename src/{ => macos}/window/controller/mod.rs (94%) rename src/{ => macos}/window/enums.rs (100%) rename src/{ => macos}/window/mod.rs (99%) rename src/{ => macos}/window/traits.rs (98%) diff --git a/Cargo.toml b/Cargo.toml index ec2e645..1256312 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,8 @@ uuid = { version = "0.8", features = ["v4"], optional = true } url = "2.1.1" [features] +default = ["macos"] +macos = [] cloudkit = [] user-notifications = ["uuid"] webview = [] diff --git a/examples/autolayout.rs b/examples/autolayout.rs index f5297ec..dc0cb54 100644 --- a/examples/autolayout.rs +++ b/examples/autolayout.rs @@ -1,18 +1,17 @@ //! This example showcases setting up a basic application and window, and setting up some views to //! work with autolayout. -use cacao::app::{App, AppDelegate, MacAppDelegate}; use cacao::color::rgb; use cacao::layout::{Layout, LayoutConstraint}; use cacao::view::View; -use cacao::window::{Window, WindowConfig, WindowDelegate}; + +use cacao::macos::app::{App, AppDelegate}; +use cacao::macos::window::{Window, WindowConfig, WindowDelegate}; struct BasicApp { window: Window } -impl MacAppDelegate for BasicApp {} - impl AppDelegate for BasicApp { fn did_finish_launching(&self) { self.window.show(); @@ -29,10 +28,9 @@ struct AppWindow { } impl WindowDelegate for AppWindow { - fn did_load(&mut self, window: Window) { + fn did_load(&self, window: Window) { window.set_title("AutoLayout Example"); window.set_minimum_content_size(300., 300.); - self.window = window; self.blue.set_background_color(rgb(105, 162, 176)); self.content.add_subview(&self.blue); @@ -43,7 +41,7 @@ impl WindowDelegate for AppWindow { self.green.set_background_color(rgb(161, 192, 132)); self.content.add_subview(&self.green); - self.window.set_content_view(&self.content); + window.set_content_view(&self.content); LayoutConstraint::activate(&[ self.blue.top.constraint_equal_to(&self.content.top).offset(16.), diff --git a/examples/window.rs b/examples/window.rs index dceccb6..cfa78f2 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -1,7 +1,7 @@ //! This example showcases setting up a basic application and window. -use cacao::app::{App, AppDelegate}; -use cacao::window::Window; +use cacao::macos::app::{App, AppDelegate}; +use cacao::macos::window::Window; #[derive(Default)] struct BasicApp { diff --git a/examples/window_controller.rs b/examples/window_controller.rs index 107627d..c5d12da 100644 --- a/examples/window_controller.rs +++ b/examples/window_controller.rs @@ -4,8 +4,8 @@ //! //! If you're not using that, you can probably get by fine with a standard `NSWindow`. -use cacao::app::{App, AppDelegate}; -use cacao::window::{Window, WindowConfig, WindowController, WindowDelegate}; +use cacao::macos::app::{App, AppDelegate}; +use cacao::macos::window::{Window, WindowConfig, WindowController, WindowDelegate}; struct BasicApp { window: WindowController diff --git a/examples/window_delegate.rs b/examples/window_delegate.rs index 1450b7b..d392cf1 100644 --- a/examples/window_delegate.rs +++ b/examples/window_delegate.rs @@ -1,8 +1,8 @@ //! This example showcases setting up a basic application and window delegate. //! Window Delegate's give you lifecycle methods that you can respond to. -use cacao::app::{App, AppDelegate}; -use cacao::window::{Window, WindowConfig, WindowDelegate}; +use cacao::macos::app::{App, AppDelegate}; +use cacao::macos::window::{Window, WindowConfig, WindowDelegate}; struct BasicApp { window: Window @@ -18,7 +18,7 @@ impl AppDelegate for BasicApp { struct MyWindow; impl WindowDelegate for MyWindow { - fn did_load(&mut self, window: Window) { + fn did_load(&self, window: Window) { window.set_minimum_content_size(400., 400.); window.set_title("A Basic Window!?"); } diff --git a/src/lib.rs b/src/lib.rs index d806a48..f797200 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,8 +72,10 @@ pub use core_graphics; pub use objc; pub use url; +#[cfg(feature = "macos")] +pub mod macos; + pub mod alert; -pub mod app; pub mod button; #[cfg(feature = "cloudkit")] @@ -87,22 +89,18 @@ pub mod filesystem; pub mod foundation; pub mod geometry; pub mod layout; -pub mod menu; pub mod networking; pub mod notification_center; +pub mod pasteboard; #[cfg(feature = "user-notifications")] pub mod user_notifications; -pub mod pasteboard; -pub mod printing; -pub mod toolbar; pub mod user_activity; -pub mod utils; +pub(crate) mod utils; pub mod user_defaults; -//pub mod view; + +pub mod view; #[cfg(feature = "webview")] pub mod webview; - -pub mod window; diff --git a/src/app/class.rs b/src/macos/app/class.rs similarity index 100% rename from src/app/class.rs rename to src/macos/app/class.rs diff --git a/src/app/delegate.rs b/src/macos/app/delegate.rs similarity index 75% rename from src/app/delegate.rs rename to src/macos/app/delegate.rs index 8961b96..ee36d2b 100644 --- a/src/app/delegate.rs +++ b/src/macos/app/delegate.rs @@ -14,11 +14,10 @@ use objc::runtime::{Class, Object, Sel}; use url::Url; -use crate::app::APP_PTR; -use crate::app::traits::{AppDelegate, MacAppDelegate}; use crate::error::AppKitError; use crate::foundation::{id, nil, BOOL, YES, NO, NSUInteger, NSArray, NSString}; -use crate::printing::PrintSettings; +use crate::macos::app::{APP_PTR, AppDelegate}; +use crate::macos::printing::PrintSettings; use crate::user_activity::UserActivity; #[cfg(feature = "cloudkit")] @@ -45,7 +44,7 @@ extern fn did_finish_launching(this: &Object, _: Sel, _: id) { } /// Fires when the Application Delegate receives a `applicationWillBecomeActive` notification. -extern fn will_become_active(this: &Object, _: Sel, _: id) { +extern fn will_become_active(this: &Object, _: Sel, _: id) { app::(this).will_become_active(); } @@ -60,12 +59,12 @@ extern fn will_resign_active(this: &Object, _: Sel, _: id) { } /// Fires when the Application Delegate receives a `applicationDidResignActive` notification. -extern fn did_resign_active(this: &Object, _: Sel, _: id) { +extern fn did_resign_active(this: &Object, _: Sel, _: id) { app::(this).did_resign_active(); } /// Fires when the Application Delegate receives a 'applicationShouldTerminate:` notification. -extern fn should_terminate(this: &Object, _: Sel, _: id) -> NSUInteger { +extern fn should_terminate(this: &Object, _: Sel, _: id) -> NSUInteger { app::(this).should_terminate().into() } @@ -75,38 +74,38 @@ extern fn will_terminate(this: &Object, _: Sel, _: id) { } /// Fires when the Application Delegate receives a `applicationWillHide:` notification. -extern fn will_hide(this: &Object, _: Sel, _: id) { +extern fn will_hide(this: &Object, _: Sel, _: id) { app::(this).will_hide(); } /// Fires when the Application Delegate receives a `applicationDidHide:` notification. -extern fn did_hide(this: &Object, _: Sel, _: id) { +extern fn did_hide(this: &Object, _: Sel, _: id) { app::(this).did_hide(); } /// Fires when the Application Delegate receives a `applicationWillUnhide:` notification. -extern fn will_unhide(this: &Object, _: Sel, _: id) { +extern fn will_unhide(this: &Object, _: Sel, _: id) { app::(this).will_unhide(); } /// Fires when the Application Delegate receives a `applicationDidUnhide:` notification. -extern fn did_unhide(this: &Object, _: Sel, _: id) { +extern fn did_unhide(this: &Object, _: Sel, _: id) { app::(this).did_unhide(); } /// Fires when the Application Delegate receives a `applicationWillUpdate:` notification. -extern fn will_update(this: &Object, _: Sel, _: id) { +extern fn will_update(this: &Object, _: Sel, _: id) { app::(this).will_update(); } /// Fires when the Application Delegate receives a `applicationDidUpdate:` notification. -extern fn did_update(this: &Object, _: Sel, _: id) { +extern fn did_update(this: &Object, _: Sel, _: id) { app::(this).did_update(); } /// Fires when the Application Delegate receives a /// `applicationShouldHandleReopen:hasVisibleWindows:` notification. -extern fn should_handle_reopen(this: &Object, _: Sel, _: id, has_visible_windows: BOOL) -> BOOL { +extern fn should_handle_reopen(this: &Object, _: Sel, _: id, has_visible_windows: BOOL) -> BOOL { match app::(this).should_handle_reopen(match has_visible_windows { YES => true, NO => false, @@ -118,7 +117,7 @@ extern fn should_handle_reopen(this: &Object, _: Sel, _: id, } /// Fires when the application delegate receives a `applicationDockMenu:` request. -extern fn dock_menu(this: &Object, _: Sel, _: id) -> id { +extern fn dock_menu(this: &Object, _: Sel, _: id) -> id { match app::(this).dock_menu() { Some(mut menu) => &mut *menu.inner, None => nil @@ -126,13 +125,13 @@ extern fn dock_menu(this: &Object, _: Sel, _: id) -> id { } /// Fires when the application delegate receives a `application:willPresentError:` notification. -extern fn will_present_error(this: &Object, _: Sel, _: id, error: id) -> id { +extern fn will_present_error(this: &Object, _: Sel, _: id, error: id) -> id { let error = AppKitError::new(error); app::(this).will_present_error(error).into_nserror() } /// Fires when the application receives a `applicationDidChangeScreenParameters:` notification. -extern fn did_change_screen_parameters(this: &Object, _: Sel, _: id) { +extern fn did_change_screen_parameters(this: &Object, _: Sel, _: id) { app::(this).did_change_screen_parameters(); } @@ -202,7 +201,7 @@ extern fn accepted_cloudkit_share(_this: &Object, _: Sel, _: id, } /// Fires when the application receives an `application:openURLs` message. -extern fn open_urls(this: &Object, _: Sel, _: id, file_urls: id) { +extern fn open_urls(this: &Object, _: Sel, _: id, file_urls: id) { let urls = NSArray::wrap(file_urls).map(|url| { let uri = NSString::wrap(unsafe { msg_send![url, absoluteString] @@ -215,7 +214,7 @@ extern fn open_urls(this: &Object, _: Sel, _: id, file_urls: } /// Fires when the application receives an `application:openFileWithoutUI:` message. -extern fn open_file_without_ui(this: &Object, _: Sel, _: id, file: id) -> BOOL { +extern fn open_file_without_ui(this: &Object, _: Sel, _: id, file: id) -> BOOL { let filename = NSString::wrap(file); match app::(this).open_file_without_ui(filename.to_str()) { @@ -225,7 +224,7 @@ extern fn open_file_without_ui(this: &Object, _: Sel, _: id, } /// Fired when the application receives an `applicationShouldOpenUntitledFile:` message. -extern fn should_open_untitled_file(this: &Object, _: Sel, _: id) -> BOOL { +extern fn should_open_untitled_file(this: &Object, _: Sel, _: id) -> BOOL { match app::(this).should_open_untitled_file() { true => YES, false => NO @@ -233,7 +232,7 @@ extern fn should_open_untitled_file(this: &Object, _: Sel, _: } /// Fired when the application receives an `applicationOpenUntitledFile:` message. -extern fn open_untitled_file(this: &Object, _: Sel, _: id) -> BOOL { +extern fn open_untitled_file(this: &Object, _: Sel, _: id) -> BOOL { match app::(this).open_untitled_file() { true => YES, false => NO @@ -241,7 +240,7 @@ extern fn open_untitled_file(this: &Object, _: Sel, _: id) -> } /// Fired when the application receives an `application:openTempFile:` message. -extern fn open_temp_file(this: &Object, _: Sel, _: id, filename: id) -> BOOL { +extern fn open_temp_file(this: &Object, _: Sel, _: id, filename: id) -> BOOL { let filename = NSString::wrap(filename); match app::(this).open_temp_file(filename.to_str()) { @@ -251,7 +250,7 @@ extern fn open_temp_file(this: &Object, _: Sel, _: id, filena } /// Fired when the application receives an `application:printFile:` message. -extern fn print_file(this: &Object, _: Sel, _: id, file: id) -> BOOL { +extern fn print_file(this: &Object, _: Sel, _: id, file: id) -> BOOL { let filename = NSString::wrap(file); match app::(this).print_file(filename.to_str()) { @@ -262,7 +261,7 @@ extern fn print_file(this: &Object, _: Sel, _: id, file: id) /// Fired when the application receives an `application:printFiles:withSettings:showPrintPanels:` /// message. -extern fn print_files(this: &Object, _: Sel, _: id, files: id, settings: id, show_print_panels: BOOL) -> NSUInteger { +extern fn print_files(this: &Object, _: Sel, _: id, files: id, settings: id, show_print_panels: BOOL) -> NSUInteger { let files = NSArray::wrap(files).map(|file| { NSString::wrap(file).to_str().to_string() }); @@ -277,14 +276,14 @@ extern fn print_files(this: &Object, _: Sel, _: id, files: id } /// Called when the application's occlusion state has changed. -extern fn did_change_occlusion_state(this: &Object, _: Sel, _: id) { +extern fn did_change_occlusion_state(this: &Object, _: Sel, _: id) { app::(this).occlusion_state_changed(); } /// 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 fn delegate_handles_key(this: &Object, _: Sel, _: id, key: id) -> BOOL { +extern fn delegate_handles_key(this: &Object, _: Sel, _: id, key: id) -> BOOL { let key = NSString::wrap(key); match app::(this).delegate_handles_key(key.to_str()) { @@ -295,53 +294,7 @@ extern fn delegate_handles_key(this: &Object, _: Sel, _: id, /// Registers an `NSObject` application delegate, and configures it for the various callbacks and /// pointers we need to have. -pub(crate) fn register_app_delegate_class() -> *const Class { - static mut DELEGATE_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - - INIT.call_once(|| unsafe { - let superclass = class!(NSObject); - let mut decl = ClassDecl::new("RSTAppDelegate", superclass).unwrap(); - - decl.add_ivar::(APP_PTR); - - // Launching Applications - decl.add_method(sel!(applicationWillFinishLaunching:), will_finish_launching:: as extern fn(&Object, _, _)); - decl.add_method(sel!(applicationDidFinishLaunching:), did_finish_launching:: as extern fn(&Object, _, _)); - - // Managing Active Status - decl.add_method(sel!(applicationDidBecomeActive:), did_become_active:: as extern fn(&Object, _, _)); - decl.add_method(sel!(applicationWillResignActive:), will_resign_active:: as extern fn(&Object, _, _)); - - // Terminating Applications - decl.add_method(sel!(applicationWillTerminate:), will_terminate:: as extern fn(&Object, _, _)); - - // User Activities - decl.add_method(sel!(application:willContinueUserActivityWithType:), will_continue_user_activity_with_type:: as extern fn(&Object, _, _, id) -> BOOL); - decl.add_method(sel!(application:continueUserActivity:restorationHandler:), continue_user_activity:: as extern fn(&Object, _, _, id, id) -> BOOL); - decl.add_method(sel!(application:didFailToContinueUserActivityWithType:error:), failed_to_continue_user_activity:: as extern fn(&Object, _, _, id, id)); - decl.add_method(sel!(application:didUpdateUserActivity:), did_update_user_activity:: as extern fn(&Object, _, _, id)); - - // Handling push notifications - decl.add_method(sel!(application:didRegisterForRemoteNotificationsWithDeviceToken:), registered_for_remote_notifications:: as extern fn(&Object, _, _, id)); - decl.add_method(sel!(application:didFailToRegisterForRemoteNotificationsWithError:), failed_to_register_for_remote_notifications:: as extern fn(&Object, _, _, id)); - decl.add_method(sel!(application:didReceiveRemoteNotification:), did_receive_remote_notification:: as extern fn(&Object, _, _, id)); - - // CloudKit - #[cfg(feature = "cloudkit")] - decl.add_method(sel!(application:userDidAcceptCloudKitShareWithMetadata:), accepted_cloudkit_share:: as extern fn(&Object, _, _, id)); - - DELEGATE_CLASS = decl.register(); - }); - - unsafe { - DELEGATE_CLASS - } -} - -/// Registers an `NSObject` application delegate, and configures it for the various callbacks and -/// pointers we need to have. -pub(crate) fn register_mac_app_delegate_class() -> *const Class { +pub(crate) fn register_app_delegate_class() -> *const Class { static mut DELEGATE_CLASS: *const Class = 0 as *const Class; static INIT: Once = Once::new(); diff --git a/src/app/enums.rs b/src/macos/app/enums.rs similarity index 100% rename from src/app/enums.rs rename to src/macos/app/enums.rs diff --git a/src/app/mod.rs b/src/macos/app/mod.rs similarity index 96% rename from src/app/mod.rs rename to src/macos/app/mod.rs index 2634035..3c53d8a 100644 --- a/src/app/mod.rs +++ b/src/macos/app/mod.rs @@ -39,20 +39,20 @@ use objc::runtime::Object; use objc::{class, msg_send, sel, sel_impl}; use crate::foundation::{id, YES, NO, NSUInteger, AutoReleasePool}; -use crate::menu::Menu; +use crate::macos::menu::Menu; use crate::notification_center::Dispatcher; mod class; use class::register_app_class; mod delegate; -use delegate::{register_app_delegate_class, register_mac_app_delegate_class}; +use delegate::{register_app_delegate_class}; mod enums; pub use enums::*; mod traits; -pub use traits::{AppDelegate, MacAppDelegate}; +pub use traits::AppDelegate; pub(crate) static APP_PTR: &str = "rstAppPtr"; @@ -118,7 +118,7 @@ impl App { } } -impl App where T: AppDelegate + MacAppDelegate + 'static { +impl App where T: AppDelegate + 'static { /// Creates an NSAutoReleasePool, configures various NSApplication properties (e.g, activation /// policies), injects an `NSObject` delegate wrapper, and retains everything on the /// Objective-C side of things. @@ -138,7 +138,7 @@ impl App where T: AppDelegate + MacAppDelegate + 'static { let app_delegate = Box::new(delegate); let objc_delegate = unsafe { - let delegate_class = register_mac_app_delegate_class::(); + let delegate_class = register_app_delegate_class::(); let delegate: id = msg_send![delegate_class, new]; let delegate_ptr: *const T = &*app_delegate; (&mut *delegate).set_ivar(APP_PTR, delegate_ptr as usize); diff --git a/src/app/traits.rs b/src/macos/app/traits.rs similarity index 93% rename from src/app/traits.rs rename to src/macos/app/traits.rs index 24f6a39..bee1006 100644 --- a/src/app/traits.rs +++ b/src/macos/app/traits.rs @@ -3,17 +3,18 @@ use url::Url; -use crate::app::enums::TerminateResponse; use crate::error::AppKitError; -use crate::menu::Menu; -use crate::printing::enums::PrintResponse; -use crate::printing::settings::PrintSettings; use crate::user_activity::UserActivity; +use crate::macos::app::enums::TerminateResponse; +use crate::macos::menu::Menu; +use crate::macos::printing::enums::PrintResponse; +use crate::macos::printing::settings::PrintSettings; + #[cfg(feature = "cloudkit")] use crate::cloudkit::share::CKShareMetaData; -/// `AppDelegate` is more or less `NSAppDelegate` from the Objective-C/Swift side, just named +/// `AppDelegate` is more or less `NSApplicationDelegate` from the Objective-C/Swift side, just named /// differently to fit in with the general naming scheme found within this framework. You can /// implement methods from this trait in order to respond to lifecycle events that the system will /// fire off. @@ -64,28 +65,7 @@ pub trait AppDelegate { /// Fired before the application terminates. You can use this to do any required cleanup. fn will_terminate(&self) {} -} -/// `SceneDelegate` maps over to the newer iOS13+ API. This is necessary in order to support -/// multiple windows (scenes) on iPadOS, which is a desirable feature. -pub trait SceneDelegate { - /*fn configuration_for( - &mut self, - session: SceneSession, - options: &[SceneConnectionOptions] - ) -> SceneConfiguration { - - } - - fn did_discard(&mut self, sessions: &[SceneSession]) {} - */ -} - -pub trait IOSAppDelegate { - -} - -pub trait MacAppDelegate { /// Fired immediately before the application is about to become active. fn will_become_active(&self) {} diff --git a/src/menu/item.rs b/src/macos/menu/item.rs similarity index 100% rename from src/menu/item.rs rename to src/macos/menu/item.rs diff --git a/src/menu/menu.rs b/src/macos/menu/menu.rs similarity index 97% rename from src/menu/menu.rs rename to src/macos/menu/menu.rs index 17a623d..6cd3993 100644 --- a/src/menu/menu.rs +++ b/src/macos/menu/menu.rs @@ -5,7 +5,7 @@ use objc::runtime::Object; use objc::{class, msg_send, sel, sel_impl}; use crate::foundation::{id, NSString}; -use crate::menu::item::MenuItem; +use crate::macos::menu::item::MenuItem; /// A struct that represents an `NSMenu`. It takes ownership of items, and handles instrumenting /// them throughout the application lifecycle. diff --git a/src/menu/mod.rs b/src/macos/menu/mod.rs similarity index 100% rename from src/menu/mod.rs rename to src/macos/menu/mod.rs diff --git a/src/macos/mod.rs b/src/macos/mod.rs new file mode 100644 index 0000000..2f0415d --- /dev/null +++ b/src/macos/mod.rs @@ -0,0 +1,22 @@ +//! Mac-specific implementations. +//! +//! macOS is a much older system than iOS, and as a result has some... quirks, in addition to just +//! plain different APIs. It's tempting to want to find a common one and just implement that, but +//! unfortunately doing so erases a lot of control and finer points of the macOS platform. +//! +//! With that said, this framework makes attempts to make things mostly work as you'd expect them +//! to from the iOS-side of things, which means we wrap things like `NSView` and `NSTableView` and +//! so on to act like their iOS counterparts (we also layer-back everything by default, as it's +//! typically what you want). +//! +//! _However_, there are some specific things that just can't be wrapped well - for example, +//! `NSToolbar`. Yes, `UIToolbar` exists, but it's really not close to `NSToolbar` in functionality +//! at all. For controls like these, we surface them here - the goal is to enable you to write 90% +//! of your app as a cross platform codebase, with the initial 10% being scaffolding code for the +//! platform (e.g, NSApplication vs UIApplication lifecycle). + +pub mod app; +pub mod menu; +pub mod printing; +pub mod toolbar; +pub mod window; diff --git a/src/printing/enums.rs b/src/macos/printing/enums.rs similarity index 100% rename from src/printing/enums.rs rename to src/macos/printing/enums.rs diff --git a/src/printing/mod.rs b/src/macos/printing/mod.rs similarity index 100% rename from src/printing/mod.rs rename to src/macos/printing/mod.rs diff --git a/src/printing/settings.rs b/src/macos/printing/settings.rs similarity index 100% rename from src/printing/settings.rs rename to src/macos/printing/settings.rs diff --git a/src/toolbar/class.rs b/src/macos/toolbar/class.rs similarity index 97% rename from src/toolbar/class.rs rename to src/macos/toolbar/class.rs index 422d8dc..4b535af 100644 --- a/src/toolbar/class.rs +++ b/src/macos/toolbar/class.rs @@ -7,7 +7,7 @@ use objc::runtime::{Class, Object, Sel}; use objc::{class, sel, sel_impl}; use crate::foundation::{id, NSArray, NSString}; -use crate::toolbar::{TOOLBAR_PTR, ToolbarDelegate}; +use crate::macos::toolbar::{TOOLBAR_PTR, ToolbarDelegate}; use crate::utils::load; /// Retrieves and passes the allowed item identifiers for this toolbar. diff --git a/src/toolbar/enums.rs b/src/macos/toolbar/enums.rs similarity index 100% rename from src/toolbar/enums.rs rename to src/macos/toolbar/enums.rs diff --git a/src/toolbar/item.rs b/src/macos/toolbar/item.rs similarity index 100% rename from src/toolbar/item.rs rename to src/macos/toolbar/item.rs diff --git a/src/toolbar/mod.rs b/src/macos/toolbar/mod.rs similarity index 100% rename from src/toolbar/mod.rs rename to src/macos/toolbar/mod.rs diff --git a/src/toolbar/traits.rs b/src/macos/toolbar/traits.rs similarity index 95% rename from src/toolbar/traits.rs rename to src/macos/toolbar/traits.rs index 2e54839..658c0ed 100644 --- a/src/toolbar/traits.rs +++ b/src/macos/toolbar/traits.rs @@ -2,7 +2,7 @@ //! go. Currently a bit incomplete in that we don't support the customizing workflow, but feel free //! to pull request it. -use crate::toolbar::{Toolbar, ToolbarItem}; +use crate::macos::toolbar::{Toolbar, ToolbarItem}; /// A trait that you can implement to have your struct/etc act as an `NSToolbarDelegate`. pub trait ToolbarDelegate { diff --git a/src/window/class.rs b/src/macos/window/class.rs similarity index 99% rename from src/window/class.rs rename to src/macos/window/class.rs index 4883934..054f992 100644 --- a/src/window/class.rs +++ b/src/macos/window/class.rs @@ -11,7 +11,7 @@ use objc::{class, sel, sel_impl}; use crate::foundation::{id, BOOL, YES, NO, NSUInteger}; use crate::utils::{load, CGSize}; -use crate::window::{WindowDelegate, WINDOW_DELEGATE_PTR}; +use crate::macos::window::{WindowDelegate, WINDOW_DELEGATE_PTR}; /// Called when an `NSWindowDelegate` receives a `windowWillClose:` event. /// Good place to clean up memory and what not. diff --git a/src/window/config.rs b/src/macos/window/config.rs similarity index 97% rename from src/window/config.rs rename to src/macos/window/config.rs index 1ea6c61..9fd469c 100644 --- a/src/window/config.rs +++ b/src/macos/window/config.rs @@ -4,7 +4,7 @@ use crate::foundation::NSUInteger; use crate::geometry::Rect; -use crate::window::enums::WindowStyle; +use crate::macos::window::enums::WindowStyle; #[derive(Debug)] pub struct WindowConfig { diff --git a/src/window/controller/class.rs b/src/macos/window/controller/class.rs similarity index 93% rename from src/window/controller/class.rs rename to src/macos/window/controller/class.rs index 81e0479..c597316 100644 --- a/src/window/controller/class.rs +++ b/src/macos/window/controller/class.rs @@ -7,7 +7,7 @@ use objc::declare::ClassDecl; use objc::runtime::Class; use objc::class; -use crate::window::{WindowDelegate, WINDOW_DELEGATE_PTR}; +use crate::macos::window::{WindowDelegate, WINDOW_DELEGATE_PTR}; /// Injects an `NSWindowController` subclass, with some callback and pointer ivars for what we /// need to do. diff --git a/src/window/controller/mod.rs b/src/macos/window/controller/mod.rs similarity index 94% rename from src/window/controller/mod.rs rename to src/macos/window/controller/mod.rs index c0e808a..2ac3e7c 100644 --- a/src/window/controller/mod.rs +++ b/src/macos/window/controller/mod.rs @@ -12,8 +12,8 @@ //! # How to use //! //! ```rust,no_run -//! use cacao::app::AppDelegate; -//! use cacao::window::{WindowController, WindowDelegate}; +//! use cacao::macos::app::AppDelegate; +//! use cacao::macos::window::{WindowController, WindowDelegate}; //! //! #[derive(Default)] //! struct MyWindow; @@ -33,7 +33,7 @@ use objc_id::ShareId; use crate::foundation::{id, nil}; use crate::utils::Controller; -use crate::window::{Window, WindowConfig, WindowDelegate, WINDOW_DELEGATE_PTR}; +use crate::macos::window::{Window, WindowConfig, WindowDelegate, WINDOW_DELEGATE_PTR}; mod class; use class::register_window_controller_class; diff --git a/src/window/enums.rs b/src/macos/window/enums.rs similarity index 100% rename from src/window/enums.rs rename to src/macos/window/enums.rs diff --git a/src/window/mod.rs b/src/macos/window/mod.rs similarity index 99% rename from src/window/mod.rs rename to src/macos/window/mod.rs index 11e9aee..86c2ede 100644 --- a/src/window/mod.rs +++ b/src/macos/window/mod.rs @@ -20,7 +20,7 @@ use objc_id::ShareId; use crate::color::Color; use crate::foundation::{id, nil, YES, NO, NSString, NSInteger, NSUInteger}; use crate::layout::traits::Layout; -use crate::toolbar::{Toolbar, ToolbarDelegate}; +use crate::macos::toolbar::{Toolbar, ToolbarDelegate}; use crate::utils::Controller; mod class; diff --git a/src/window/traits.rs b/src/macos/window/traits.rs similarity index 98% rename from src/window/traits.rs rename to src/macos/window/traits.rs index 1f29cd3..fc787c3 100644 --- a/src/window/traits.rs +++ b/src/macos/window/traits.rs @@ -2,8 +2,8 @@ //! module. There's a few different ones, and it's just... cleaner, if //! it's organized here. -use crate::app::PresentationOption; -use crate::window::Window; +use crate::macos::app::PresentationOption; +use crate::macos::window::Window; /// Lifecycle events for anything that `impl Window`'s. These map to the standard Cocoa /// lifecycle methods, but mix in a few extra things to handle offering configuration tools diff --git a/src/pasteboard/mod.rs b/src/pasteboard/mod.rs index 4443739..f856b1e 100644 --- a/src/pasteboard/mod.rs +++ b/src/pasteboard/mod.rs @@ -12,7 +12,7 @@ use url::Url; use crate::foundation::{id, nil, NSString, NSArray}; use crate::error::AppKitError; -pub mod types; +mod types; pub use types::{PasteboardName, PasteboardType}; /// Represents an `NSPasteboard`, enabling you to handle copy/paste/drag and drop. diff --git a/src/view/class.rs b/src/view/class.rs index ca7caee..af49ce9 100644 --- a/src/view/class.rs +++ b/src/view/class.rs @@ -7,7 +7,6 @@ //! 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 std::rc::Rc; use std::sync::Once; use objc::declare::ClassDecl; @@ -28,83 +27,51 @@ extern fn enforce_normalcy(_: &Object, _: Sel) -> BOOL { /// Called when a drag/drop operation has entered this view. extern fn dragging_entered(this: &mut Object, _: Sel, info: id) -> NSUInteger { let view = load::(this, VIEW_DELEGATE_PTR); - - let response = { - let v = view.borrow(); - - (*v).dragging_entered(DragInfo { - info: unsafe { Id::from_ptr(info) } - }).into() - }; - - Rc::into_raw(view); - response + view.dragging_entered(DragInfo { + info: unsafe { Id::from_ptr(info) } + }).into() } /// Called when a drag/drop operation has entered this view. extern fn prepare_for_drag_operation(this: &mut Object, _: Sel, info: id) -> BOOL { let view = load::(this, VIEW_DELEGATE_PTR); - let response = { - let v = view.borrow(); - - match (*v).prepare_for_drag_operation(DragInfo { - info: unsafe { Id::from_ptr(info) } - }) { - true => YES, - false => NO - } - }; - - Rc::into_raw(view); - response + match 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 fn perform_drag_operation(this: &mut Object, _: Sel, info: id) -> BOOL { let view = load::(this, VIEW_DELEGATE_PTR); - let response = { - let v = view.borrow(); - - match (*v).perform_drag_operation(DragInfo { - info: unsafe { Id::from_ptr(info) } - }) { - true => YES, - false => NO - } - }; - - Rc::into_raw(view); - response + match 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. extern fn conclude_drag_operation(this: &mut Object, _: Sel, info: id) { let view = load::(this, VIEW_DELEGATE_PTR); - - { - let v = view.borrow(); - (*v).conclude_drag_operation(DragInfo { - info: unsafe { Id::from_ptr(info) } - }); - } - - Rc::into_raw(view); + + view.conclude_drag_operation(DragInfo { + info: unsafe { Id::from_ptr(info) } + }); } /// Called when a drag/drop operation has entered this view. extern fn dragging_exited(this: &mut Object, _: Sel, info: id) { let view = load::(this, VIEW_DELEGATE_PTR); - { - let v = view.borrow(); - (*v).dragging_exited(DragInfo { - info: unsafe { Id::from_ptr(info) } - }); - } - - Rc::into_raw(view); + view.dragging_exited(DragInfo { + info: unsafe { Id::from_ptr(info) } + }); } /// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we diff --git a/src/view/controller/class.rs b/src/view/controller/class.rs index a8a7b7f..c18a0d7 100644 --- a/src/view/controller/class.rs +++ b/src/view/controller/class.rs @@ -1,6 +1,5 @@ //! Hoists a basic `NSViewController`. -use std::rc::Rc; use std::sync::Once; use objc::declare::ClassDecl; @@ -13,49 +12,25 @@ use crate::utils::load; /// Called when the view controller receives a `viewWillAppear` message. extern fn will_appear(this: &mut Object, _: Sel) { let controller = load::(this, VIEW_DELEGATE_PTR); - - { - let vc = controller.borrow(); - (*vc).will_appear(); - } - - Rc::into_raw(controller); + controller.will_appear(); } /// Called when the view controller receives a `viewDidAppear` message. extern fn did_appear(this: &mut Object, _: Sel) { let controller = load::(this, VIEW_DELEGATE_PTR); - - { - let vc = controller.borrow(); - (*vc).did_appear(); - } - - Rc::into_raw(controller); + controller.did_appear(); } /// Called when the view controller receives a `viewWillDisappear` message. extern fn will_disappear(this: &mut Object, _: Sel) { let controller = load::(this, VIEW_DELEGATE_PTR); - - { - let vc = controller.borrow(); - (*vc).will_disappear(); - } - - Rc::into_raw(controller); + controller.will_disappear(); } /// Called when the view controller receives a `viewDidDisappear` message. extern fn did_disappear(this: &mut Object, _: Sel) { let controller = load::(this, VIEW_DELEGATE_PTR); - - { - let vc = controller.borrow(); - (*vc).did_disappear(); - } - - Rc::into_raw(controller); + controller.did_disappear(); } /// Registers an `NSViewDelegate`. diff --git a/src/view/controller/mod.rs b/src/view/controller/mod.rs index c2cf1c5..9946193 100644 --- a/src/view/controller/mod.rs +++ b/src/view/controller/mod.rs @@ -17,12 +17,13 @@ pub struct ViewController { impl ViewController where T: ViewDelegate + 'static { pub fn new(delegate: T) -> Self { - let mut view = View::with(delegate); + let view = View::with(delegate); let objc = unsafe { let vc: id = msg_send![register_view_controller_class::(), new]; - if let Some(ptr)= view.internal_callback_ptr { + if let Some(delegate)= &view.delegate { + let ptr: *const T = &**delegate; (&mut *vc).set_ivar(VIEW_DELEGATE_PTR, ptr as usize); } @@ -32,9 +33,8 @@ impl ViewController where T: ViewDelegate + 'static { }; let handle = view.clone_as_handle(); - if let Some(view_delegate) = &mut view.delegate { - let mut view_delegate = view_delegate.borrow_mut(); - (*view_delegate).did_load(handle); + if let Some(view_delegate) = &view.delegate { + view_delegate.did_load(handle); } ViewController { diff --git a/src/view/mod.rs b/src/view/mod.rs index af29cb1..c7423ae 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -41,9 +41,6 @@ //! //! For more information on Autolayout, view the module or check out the examples folder. -use std::rc::Rc; -use std::cell::RefCell; - use objc_id::ShareId; use objc::runtime::{Class, Object}; use objc::{msg_send, sel, sel_impl}; @@ -81,12 +78,8 @@ pub struct View { /// A pointer to the Objective-C runtime view controller. pub objc: ShareId, - /// An internal callback pointer that we use in delegate loopbacks. Default implementations - /// don't require this. - pub(crate) internal_callback_ptr: Option<*const RefCell>, - /// A pointer to the delegate for this view. - pub delegate: Option>>, + pub delegate: Option>, /// A pointer to the Objective-C runtime top layout constraint. pub top: LayoutAnchorY, @@ -125,7 +118,6 @@ impl View { let view = allocate_view(register_view_class); View { - internal_callback_ptr: None, delegate: None, top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), @@ -144,22 +136,17 @@ impl View where T: ViewDelegate + 'static { /// Initializes a new View with a given `ViewDelegate`. This enables you to respond to events /// and customize the view as a module, similar to class-based systems. pub fn with(delegate: T) -> View { - let delegate = Rc::new(RefCell::new(delegate)); + let delegate = Box::new(delegate); - let internal_callback_ptr = { - let cloned = Rc::clone(&delegate); - Rc::into_raw(cloned) - }; - let view = allocate_view(register_view_class_with_delegate::); unsafe { //let view: id = msg_send![register_view_class_with_delegate::(), new]; //let _: () = msg_send![view, setTranslatesAutoresizingMaskIntoConstraints:NO]; - (&mut *view).set_ivar(VIEW_DELEGATE_PTR, internal_callback_ptr as usize); + let ptr: *const T = &*delegate; + (&mut *view).set_ivar(VIEW_DELEGATE_PTR, ptr as usize); }; let mut view = View { - internal_callback_ptr: Some(internal_callback_ptr), delegate: None, top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }), leading: LayoutAnchorX::new(unsafe { msg_send![view, leadingAnchor] }), @@ -172,11 +159,7 @@ impl View where T: ViewDelegate + 'static { objc: unsafe { ShareId::from_ptr(view) }, }; - { - let mut delegate = delegate.borrow_mut(); - (*delegate).did_load(view.clone_as_handle()); - } - + &delegate.did_load(view.clone_as_handle()); view.delegate = Some(delegate); view } @@ -189,7 +172,6 @@ impl View { /// delegate - the `View` is the only true holder of those. pub(crate) fn clone_as_handle(&self) -> View { View { - internal_callback_ptr: None, delegate: None, top: self.top.clone(), leading: self.leading.clone(), @@ -245,20 +227,18 @@ impl Layout for View { impl Drop for View { /// A bit of extra cleanup for delegate callback pointers. If the originating `View` is being - /// dropped, we do some logic to release the loopback ptr. We also go ahead and check to see if + /// dropped, we do some logic to clean it all up (e.g, we go ahead and check to see if /// this has a superview (i.e, it's in the heirarchy) on the AppKit side. If it does, we go - /// ahead and remove it - this is intended to match the semantics of how Rust handles things. + /// ahead and remove it - this is intended to match the semantics of how Rust handles things). /// /// There are, thankfully, no delegates we need to break here. fn drop(&mut self) { - if let Some(ptr) = &self.internal_callback_ptr { + if self.delegate.is_some() { unsafe { let superview: id = msg_send![&*self.objc, superview]; if superview != nil { let _: () = msg_send![&*self.objc, removeFromSuperview]; } - - let _ = Rc::from_raw(ptr); } } } diff --git a/src/view/traits.rs b/src/view/traits.rs index f215acf..706c376 100644 --- a/src/view/traits.rs +++ b/src/view/traits.rs @@ -7,7 +7,7 @@ pub trait ViewDelegate { /// Called when the View is ready to work with. You're passed a `ViewHandle` - this is safe to /// store and use repeatedly, but it's not thread safe - any UI calls must be made from the /// main thread! - fn did_load(&mut self, _view: View) {} + fn did_load(&self, _view: View) {} /// Called when this is about to be added to the view heirarchy. fn will_appear(&self) {}