Further work on splitting for macOS/iOS support
This commit is contained in:
parent
27e534a612
commit
d69f59d284
|
@ -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 = []
|
||||
|
|
|
@ -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<AppWindow>
|
||||
}
|
||||
|
||||
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.),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<MyWindow>
|
||||
|
|
|
@ -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<MyWindow>
|
||||
|
@ -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!?");
|
||||
}
|
||||
|
|
16
src/lib.rs
16
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;
|
||||
|
|
|
@ -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<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
|||
}
|
||||
|
||||
/// Fires when the Application Delegate receives a `applicationWillBecomeActive` notification.
|
||||
extern fn will_become_active<T: MacAppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
extern fn will_become_active<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
app::<T>(this).will_become_active();
|
||||
}
|
||||
|
||||
|
@ -60,12 +59,12 @@ extern fn will_resign_active<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
|||
}
|
||||
|
||||
/// Fires when the Application Delegate receives a `applicationDidResignActive` notification.
|
||||
extern fn did_resign_active<T: MacAppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
extern fn did_resign_active<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
app::<T>(this).did_resign_active();
|
||||
}
|
||||
|
||||
/// Fires when the Application Delegate receives a 'applicationShouldTerminate:` notification.
|
||||
extern fn should_terminate<T: MacAppDelegate>(this: &Object, _: Sel, _: id) -> NSUInteger {
|
||||
extern fn should_terminate<T: AppDelegate>(this: &Object, _: Sel, _: id) -> NSUInteger {
|
||||
app::<T>(this).should_terminate().into()
|
||||
}
|
||||
|
||||
|
@ -75,38 +74,38 @@ extern fn will_terminate<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
|||
}
|
||||
|
||||
/// Fires when the Application Delegate receives a `applicationWillHide:` notification.
|
||||
extern fn will_hide<T: MacAppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
extern fn will_hide<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
app::<T>(this).will_hide();
|
||||
}
|
||||
|
||||
/// Fires when the Application Delegate receives a `applicationDidHide:` notification.
|
||||
extern fn did_hide<T: MacAppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
extern fn did_hide<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
app::<T>(this).did_hide();
|
||||
}
|
||||
|
||||
/// Fires when the Application Delegate receives a `applicationWillUnhide:` notification.
|
||||
extern fn will_unhide<T: MacAppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
extern fn will_unhide<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
app::<T>(this).will_unhide();
|
||||
}
|
||||
|
||||
/// Fires when the Application Delegate receives a `applicationDidUnhide:` notification.
|
||||
extern fn did_unhide<T: MacAppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
extern fn did_unhide<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
app::<T>(this).did_unhide();
|
||||
}
|
||||
|
||||
/// Fires when the Application Delegate receives a `applicationWillUpdate:` notification.
|
||||
extern fn will_update<T: MacAppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
extern fn will_update<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
app::<T>(this).will_update();
|
||||
}
|
||||
|
||||
/// Fires when the Application Delegate receives a `applicationDidUpdate:` notification.
|
||||
extern fn did_update<T: MacAppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
extern fn did_update<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
app::<T>(this).did_update();
|
||||
}
|
||||
|
||||
/// Fires when the Application Delegate receives a
|
||||
/// `applicationShouldHandleReopen:hasVisibleWindows:` notification.
|
||||
extern fn should_handle_reopen<T: MacAppDelegate>(this: &Object, _: Sel, _: id, has_visible_windows: BOOL) -> BOOL {
|
||||
extern fn should_handle_reopen<T: AppDelegate>(this: &Object, _: Sel, _: id, has_visible_windows: BOOL) -> BOOL {
|
||||
match app::<T>(this).should_handle_reopen(match has_visible_windows {
|
||||
YES => true,
|
||||
NO => false,
|
||||
|
@ -118,7 +117,7 @@ extern fn should_handle_reopen<T: MacAppDelegate>(this: &Object, _: Sel, _: id,
|
|||
}
|
||||
|
||||
/// Fires when the application delegate receives a `applicationDockMenu:` request.
|
||||
extern fn dock_menu<T: MacAppDelegate>(this: &Object, _: Sel, _: id) -> id {
|
||||
extern fn dock_menu<T: AppDelegate>(this: &Object, _: Sel, _: id) -> id {
|
||||
match app::<T>(this).dock_menu() {
|
||||
Some(mut menu) => &mut *menu.inner,
|
||||
None => nil
|
||||
|
@ -126,13 +125,13 @@ extern fn dock_menu<T: MacAppDelegate>(this: &Object, _: Sel, _: id) -> id {
|
|||
}
|
||||
|
||||
/// Fires when the application delegate receives a `application:willPresentError:` notification.
|
||||
extern fn will_present_error<T: MacAppDelegate>(this: &Object, _: Sel, _: id, error: id) -> id {
|
||||
extern fn will_present_error<T: AppDelegate>(this: &Object, _: Sel, _: id, error: id) -> id {
|
||||
let error = AppKitError::new(error);
|
||||
app::<T>(this).will_present_error(error).into_nserror()
|
||||
}
|
||||
|
||||
/// Fires when the application receives a `applicationDidChangeScreenParameters:` notification.
|
||||
extern fn did_change_screen_parameters<T: MacAppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
extern fn did_change_screen_parameters<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
app::<T>(this).did_change_screen_parameters();
|
||||
}
|
||||
|
||||
|
@ -202,7 +201,7 @@ extern fn accepted_cloudkit_share<T: AppDelegate>(_this: &Object, _: Sel, _: id,
|
|||
}
|
||||
|
||||
/// Fires when the application receives an `application:openURLs` message.
|
||||
extern fn open_urls<T: MacAppDelegate>(this: &Object, _: Sel, _: id, file_urls: id) {
|
||||
extern fn open_urls<T: AppDelegate>(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<T: MacAppDelegate>(this: &Object, _: Sel, _: id, file_urls:
|
|||
}
|
||||
|
||||
/// Fires when the application receives an `application:openFileWithoutUI:` message.
|
||||
extern fn open_file_without_ui<T: MacAppDelegate>(this: &Object, _: Sel, _: id, file: id) -> BOOL {
|
||||
extern fn open_file_without_ui<T: AppDelegate>(this: &Object, _: Sel, _: id, file: id) -> BOOL {
|
||||
let filename = NSString::wrap(file);
|
||||
|
||||
match app::<T>(this).open_file_without_ui(filename.to_str()) {
|
||||
|
@ -225,7 +224,7 @@ extern fn open_file_without_ui<T: MacAppDelegate>(this: &Object, _: Sel, _: id,
|
|||
}
|
||||
|
||||
/// Fired when the application receives an `applicationShouldOpenUntitledFile:` message.
|
||||
extern fn should_open_untitled_file<T: MacAppDelegate>(this: &Object, _: Sel, _: id) -> BOOL {
|
||||
extern fn should_open_untitled_file<T: AppDelegate>(this: &Object, _: Sel, _: id) -> BOOL {
|
||||
match app::<T>(this).should_open_untitled_file() {
|
||||
true => YES,
|
||||
false => NO
|
||||
|
@ -233,7 +232,7 @@ extern fn should_open_untitled_file<T: MacAppDelegate>(this: &Object, _: Sel, _:
|
|||
}
|
||||
|
||||
/// Fired when the application receives an `applicationOpenUntitledFile:` message.
|
||||
extern fn open_untitled_file<T: MacAppDelegate>(this: &Object, _: Sel, _: id) -> BOOL {
|
||||
extern fn open_untitled_file<T: AppDelegate>(this: &Object, _: Sel, _: id) -> BOOL {
|
||||
match app::<T>(this).open_untitled_file() {
|
||||
true => YES,
|
||||
false => NO
|
||||
|
@ -241,7 +240,7 @@ extern fn open_untitled_file<T: MacAppDelegate>(this: &Object, _: Sel, _: id) ->
|
|||
}
|
||||
|
||||
/// Fired when the application receives an `application:openTempFile:` message.
|
||||
extern fn open_temp_file<T: MacAppDelegate>(this: &Object, _: Sel, _: id, filename: id) -> BOOL {
|
||||
extern fn open_temp_file<T: AppDelegate>(this: &Object, _: Sel, _: id, filename: id) -> BOOL {
|
||||
let filename = NSString::wrap(filename);
|
||||
|
||||
match app::<T>(this).open_temp_file(filename.to_str()) {
|
||||
|
@ -251,7 +250,7 @@ extern fn open_temp_file<T: MacAppDelegate>(this: &Object, _: Sel, _: id, filena
|
|||
}
|
||||
|
||||
/// Fired when the application receives an `application:printFile:` message.
|
||||
extern fn print_file<T: MacAppDelegate>(this: &Object, _: Sel, _: id, file: id) -> BOOL {
|
||||
extern fn print_file<T: AppDelegate>(this: &Object, _: Sel, _: id, file: id) -> BOOL {
|
||||
let filename = NSString::wrap(file);
|
||||
|
||||
match app::<T>(this).print_file(filename.to_str()) {
|
||||
|
@ -262,7 +261,7 @@ extern fn print_file<T: MacAppDelegate>(this: &Object, _: Sel, _: id, file: id)
|
|||
|
||||
/// Fired when the application receives an `application:printFiles:withSettings:showPrintPanels:`
|
||||
/// message.
|
||||
extern fn print_files<T: MacAppDelegate>(this: &Object, _: Sel, _: id, files: id, settings: id, show_print_panels: BOOL) -> NSUInteger {
|
||||
extern fn print_files<T: AppDelegate>(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<T: MacAppDelegate>(this: &Object, _: Sel, _: id, files: id
|
|||
}
|
||||
|
||||
/// Called when the application's occlusion state has changed.
|
||||
extern fn did_change_occlusion_state<T: MacAppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
extern fn did_change_occlusion_state<T: AppDelegate>(this: &Object, _: Sel, _: id) {
|
||||
app::<T>(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<T: MacAppDelegate>(this: &Object, _: Sel, _: id, key: id) -> BOOL {
|
||||
extern fn delegate_handles_key<T: AppDelegate>(this: &Object, _: Sel, _: id, key: id) -> BOOL {
|
||||
let key = NSString::wrap(key);
|
||||
|
||||
match app::<T>(this).delegate_handles_key(key.to_str()) {
|
||||
|
@ -295,53 +294,7 @@ extern fn delegate_handles_key<T: MacAppDelegate>(this: &Object, _: Sel, _: id,
|
|||
|
||||
/// Registers an `NSObject` application delegate, and configures it for the various callbacks and
|
||||
/// pointers we need to have.
|
||||
pub(crate) fn register_app_delegate_class<T: AppDelegate>() -> *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::<usize>(APP_PTR);
|
||||
|
||||
// Launching Applications
|
||||
decl.add_method(sel!(applicationWillFinishLaunching:), will_finish_launching::<T> as extern fn(&Object, _, _));
|
||||
decl.add_method(sel!(applicationDidFinishLaunching:), did_finish_launching::<T> as extern fn(&Object, _, _));
|
||||
|
||||
// Managing Active Status
|
||||
decl.add_method(sel!(applicationDidBecomeActive:), did_become_active::<T> as extern fn(&Object, _, _));
|
||||
decl.add_method(sel!(applicationWillResignActive:), will_resign_active::<T> as extern fn(&Object, _, _));
|
||||
|
||||
// Terminating Applications
|
||||
decl.add_method(sel!(applicationWillTerminate:), will_terminate::<T> as extern fn(&Object, _, _));
|
||||
|
||||
// User Activities
|
||||
decl.add_method(sel!(application:willContinueUserActivityWithType:), will_continue_user_activity_with_type::<T> as extern fn(&Object, _, _, id) -> BOOL);
|
||||
decl.add_method(sel!(application:continueUserActivity:restorationHandler:), continue_user_activity::<T> as extern fn(&Object, _, _, id, id) -> BOOL);
|
||||
decl.add_method(sel!(application:didFailToContinueUserActivityWithType:error:), failed_to_continue_user_activity::<T> as extern fn(&Object, _, _, id, id));
|
||||
decl.add_method(sel!(application:didUpdateUserActivity:), did_update_user_activity::<T> as extern fn(&Object, _, _, id));
|
||||
|
||||
// Handling push notifications
|
||||
decl.add_method(sel!(application:didRegisterForRemoteNotificationsWithDeviceToken:), registered_for_remote_notifications::<T> as extern fn(&Object, _, _, id));
|
||||
decl.add_method(sel!(application:didFailToRegisterForRemoteNotificationsWithError:), failed_to_register_for_remote_notifications::<T> as extern fn(&Object, _, _, id));
|
||||
decl.add_method(sel!(application:didReceiveRemoteNotification:), did_receive_remote_notification::<T> as extern fn(&Object, _, _, id));
|
||||
|
||||
// CloudKit
|
||||
#[cfg(feature = "cloudkit")]
|
||||
decl.add_method(sel!(application:userDidAcceptCloudKitShareWithMetadata:), accepted_cloudkit_share::<T> 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<T: AppDelegate + MacAppDelegate>() -> *const Class {
|
||||
pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> *const Class {
|
||||
static mut DELEGATE_CLASS: *const Class = 0 as *const Class;
|
||||
static INIT: Once = Once::new();
|
||||
|
|
@ -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<T> App<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> App<T> where T: AppDelegate + MacAppDelegate + 'static {
|
||||
impl<T> App<T> 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<T> App<T> where T: AppDelegate + MacAppDelegate + 'static {
|
|||
let app_delegate = Box::new(delegate);
|
||||
|
||||
let objc_delegate = unsafe {
|
||||
let delegate_class = register_mac_app_delegate_class::<T>();
|
||||
let delegate_class = register_app_delegate_class::<T>();
|
||||
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);
|
|
@ -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) {}
|
||||
|
|
@ -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.
|
22
src/macos/mod.rs
Normal file
22
src/macos/mod.rs
Normal file
|
@ -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;
|
|
@ -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.
|
|
@ -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 {
|
|
@ -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.
|
|
@ -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 {
|
|
@ -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.
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
|
|
@ -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.
|
||||
|
|
|
@ -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,85 +27,53 @@ extern fn enforce_normalcy(_: &Object, _: Sel) -> BOOL {
|
|||
/// Called when a drag/drop operation has entered this view.
|
||||
extern fn dragging_entered<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> NSUInteger {
|
||||
let view = load::<T>(this, VIEW_DELEGATE_PTR);
|
||||
|
||||
let response = {
|
||||
let v = view.borrow();
|
||||
|
||||
(*v).dragging_entered(DragInfo {
|
||||
view.dragging_entered(DragInfo {
|
||||
info: unsafe { Id::from_ptr(info) }
|
||||
}).into()
|
||||
};
|
||||
|
||||
Rc::into_raw(view);
|
||||
response
|
||||
}
|
||||
|
||||
/// Called when a drag/drop operation has entered this view.
|
||||
extern fn prepare_for_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL {
|
||||
let view = load::<T>(this, VIEW_DELEGATE_PTR);
|
||||
|
||||
let response = {
|
||||
let v = view.borrow();
|
||||
|
||||
match (*v).prepare_for_drag_operation(DragInfo {
|
||||
match view.prepare_for_drag_operation(DragInfo {
|
||||
info: unsafe { Id::from_ptr(info) }
|
||||
}) {
|
||||
true => YES,
|
||||
false => NO
|
||||
}
|
||||
};
|
||||
|
||||
Rc::into_raw(view);
|
||||
response
|
||||
}
|
||||
|
||||
/// Called when a drag/drop operation has entered this view.
|
||||
extern fn perform_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) -> BOOL {
|
||||
let view = load::<T>(this, VIEW_DELEGATE_PTR);
|
||||
|
||||
let response = {
|
||||
let v = view.borrow();
|
||||
|
||||
match (*v).perform_drag_operation(DragInfo {
|
||||
match view.perform_drag_operation(DragInfo {
|
||||
info: unsafe { Id::from_ptr(info) }
|
||||
}) {
|
||||
true => YES,
|
||||
false => NO
|
||||
}
|
||||
};
|
||||
|
||||
Rc::into_raw(view);
|
||||
response
|
||||
}
|
||||
|
||||
/// Called when a drag/drop operation has entered this view.
|
||||
extern fn conclude_drag_operation<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) {
|
||||
let view = load::<T>(this, VIEW_DELEGATE_PTR);
|
||||
|
||||
{
|
||||
let v = view.borrow();
|
||||
(*v).conclude_drag_operation(DragInfo {
|
||||
view.conclude_drag_operation(DragInfo {
|
||||
info: unsafe { Id::from_ptr(info) }
|
||||
});
|
||||
}
|
||||
|
||||
Rc::into_raw(view);
|
||||
}
|
||||
|
||||
/// Called when a drag/drop operation has entered this view.
|
||||
extern fn dragging_exited<T: ViewDelegate>(this: &mut Object, _: Sel, info: id) {
|
||||
let view = load::<T>(this, VIEW_DELEGATE_PTR);
|
||||
|
||||
{
|
||||
let v = view.borrow();
|
||||
(*v).dragging_exited(DragInfo {
|
||||
view.dragging_exited(DragInfo {
|
||||
info: unsafe { Id::from_ptr(info) }
|
||||
});
|
||||
}
|
||||
|
||||
Rc::into_raw(view);
|
||||
}
|
||||
|
||||
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
|
||||
/// have separate classes here since we don't want to waste cycles on methods that will never be
|
||||
/// used if there's no delegates.
|
||||
|
|
|
@ -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<T: ViewDelegate>(this: &mut Object, _: Sel) {
|
||||
let controller = load::<T>(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<T: ViewDelegate>(this: &mut Object, _: Sel) {
|
||||
let controller = load::<T>(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<T: ViewDelegate>(this: &mut Object, _: Sel) {
|
||||
let controller = load::<T>(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<T: ViewDelegate>(this: &mut Object, _: Sel) {
|
||||
let controller = load::<T>(this, VIEW_DELEGATE_PTR);
|
||||
|
||||
{
|
||||
let vc = controller.borrow();
|
||||
(*vc).did_disappear();
|
||||
}
|
||||
|
||||
Rc::into_raw(controller);
|
||||
controller.did_disappear();
|
||||
}
|
||||
|
||||
/// Registers an `NSViewDelegate`.
|
||||
|
|
|
@ -17,12 +17,13 @@ pub struct ViewController<T> {
|
|||
|
||||
impl<T> ViewController<T> 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::<T>(), 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<T> ViewController<T> 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 {
|
||||
|
|
|
@ -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<T = ()> {
|
|||
/// A pointer to the Objective-C runtime view controller.
|
||||
pub objc: ShareId<Object>,
|
||||
|
||||
/// An internal callback pointer that we use in delegate loopbacks. Default implementations
|
||||
/// don't require this.
|
||||
pub(crate) internal_callback_ptr: Option<*const RefCell<T>>,
|
||||
|
||||
/// A pointer to the delegate for this view.
|
||||
pub delegate: Option<Rc<RefCell<T>>>,
|
||||
pub delegate: Option<Box<T>>,
|
||||
|
||||
/// 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<T> View<T> 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<T> {
|
||||
let delegate = Rc::new(RefCell::new(delegate));
|
||||
|
||||
let internal_callback_ptr = {
|
||||
let cloned = Rc::clone(&delegate);
|
||||
Rc::into_raw(cloned)
|
||||
};
|
||||
let delegate = Box::new(delegate);
|
||||
|
||||
let view = allocate_view(register_view_class_with_delegate::<T>);
|
||||
unsafe {
|
||||
//let view: id = msg_send![register_view_class_with_delegate::<T>(), 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<T> View<T> 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<T> View<T> {
|
|||
/// 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<T> Layout for View<T> {
|
|||
|
||||
impl<T> Drop for View<T> {
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {}
|
||||
|
|
Loading…
Reference in a new issue