diff --git a/src/appkit/app/class.rs b/src/appkit/app/class.rs index 2b46ae7..59690d9 100644 --- a/src/appkit/app/class.rs +++ b/src/appkit/app/class.rs @@ -2,27 +2,11 @@ //! creates a custom `NSApplication` subclass that currently does nothing; this is meant as a hook //! for potential future use. -use std::sync::Once; - -use objc::class; -use objc::declare::ClassDecl; use objc::runtime::Class; +use crate::foundation::load_or_register_class; + /// Used for injecting a custom NSApplication. Currently does nothing. pub(crate) fn register_app_class() -> *const Class { - static mut APP_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTApplication"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { APP_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSApplication); - let decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - APP_CLASS = decl.register(); - }); - } - - unsafe { APP_CLASS } + load_or_register_class("NSApplication", "RSTApplication", |decl| unsafe {}) } diff --git a/src/appkit/app/delegate.rs b/src/appkit/app/delegate.rs index d5e2069..b833c46 100644 --- a/src/appkit/app/delegate.rs +++ b/src/appkit/app/delegate.rs @@ -3,24 +3,19 @@ //! for potential future use. use std::ffi::c_void; -use std::sync::Once; use block::Block; - -use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel}; -use objc::{class, msg_send, sel, sel_impl}; - +use objc::{msg_send, sel, sel_impl}; use url::Url; use crate::appkit::app::{AppDelegate, APP_PTR}; use crate::appkit::printing::PrintSettings; -use crate::error::Error; -use crate::foundation::{id, nil, to_bool, NSArray, NSString, NSUInteger, BOOL, NO, YES}; -use crate::user_activity::UserActivity; - #[cfg(feature = "cloudkit")] use crate::cloudkit::share::CKShareMetaData; +use crate::error::Error; +use crate::foundation::{id, load_or_register_class, nil, to_bool, NSArray, NSString, NSUInteger, BOOL, NO, YES}; +use crate::user_activity::UserActivity; /// A handy method for grabbing our `AppDelegate` from the pointer. This is different from our /// standard `utils` version as this doesn't require `RefCell` backing. @@ -295,180 +290,165 @@ extern "C" 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(); - const CLASS_NAME: &str = "RSTAppDelegate"; + load_or_register_class("NSObject", "RSTAppDelegate", |decl| unsafe { + decl.add_ivar::(APP_PTR); - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { DELEGATE_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSObject); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); + // Launching Applications + decl.add_method( + sel!(applicationWillFinishLaunching:), + will_finish_launching:: as extern "C" fn(&Object, _, _) + ); + decl.add_method( + sel!(applicationDidFinishLaunching:), + did_finish_launching:: as extern "C" fn(&Object, _, _) + ); - decl.add_ivar::(APP_PTR); + // Managing Active Status + decl.add_method( + sel!(applicationWillBecomeActive:), + will_become_active:: as extern "C" fn(&Object, _, _) + ); + decl.add_method( + sel!(applicationDidBecomeActive:), + did_become_active:: as extern "C" fn(&Object, _, _) + ); + decl.add_method( + sel!(applicationWillResignActive:), + will_resign_active:: as extern "C" fn(&Object, _, _) + ); + decl.add_method( + sel!(applicationDidResignActive:), + did_resign_active:: as extern "C" fn(&Object, _, _) + ); - // Launching Applications - decl.add_method( - sel!(applicationWillFinishLaunching:), - will_finish_launching:: as extern "C" fn(&Object, _, _) - ); - decl.add_method( - sel!(applicationDidFinishLaunching:), - did_finish_launching:: as extern "C" fn(&Object, _, _) - ); + // Terminating Applications + decl.add_method( + sel!(applicationShouldTerminate:), + should_terminate:: as extern "C" fn(&Object, _, _) -> NSUInteger + ); + decl.add_method( + sel!(applicationWillTerminate:), + will_terminate:: as extern "C" fn(&Object, _, _) + ); + decl.add_method( + sel!(applicationShouldTerminateAfterLastWindowClosed:), + should_terminate_after_last_window_closed:: as extern "C" fn(&Object, _, _) -> BOOL + ); - // Managing Active Status - decl.add_method( - sel!(applicationWillBecomeActive:), - will_become_active:: as extern "C" fn(&Object, _, _) - ); - decl.add_method( - sel!(applicationDidBecomeActive:), - did_become_active:: as extern "C" fn(&Object, _, _) - ); - decl.add_method( - sel!(applicationWillResignActive:), - will_resign_active:: as extern "C" fn(&Object, _, _) - ); - decl.add_method( - sel!(applicationDidResignActive:), - did_resign_active:: as extern "C" fn(&Object, _, _) - ); + // Hiding Applications + decl.add_method(sel!(applicationWillHide:), will_hide:: as extern "C" fn(&Object, _, _)); + decl.add_method(sel!(applicationDidHide:), did_hide:: as extern "C" fn(&Object, _, _)); + decl.add_method(sel!(applicationWillUnhide:), will_unhide:: as extern "C" fn(&Object, _, _)); + decl.add_method(sel!(applicationDidUnhide:), did_unhide:: as extern "C" fn(&Object, _, _)); - // Terminating Applications - decl.add_method( - sel!(applicationShouldTerminate:), - should_terminate:: as extern "C" fn(&Object, _, _) -> NSUInteger - ); - decl.add_method( - sel!(applicationWillTerminate:), - will_terminate:: as extern "C" fn(&Object, _, _) - ); - decl.add_method( - sel!(applicationShouldTerminateAfterLastWindowClosed:), - should_terminate_after_last_window_closed:: as extern "C" fn(&Object, _, _) -> BOOL - ); + // Managing Windows + decl.add_method(sel!(applicationWillUpdate:), will_update:: as extern "C" fn(&Object, _, _)); + decl.add_method(sel!(applicationDidUpdate:), did_update:: as extern "C" fn(&Object, _, _)); + decl.add_method( + sel!(applicationShouldHandleReopen:hasVisibleWindows:), + should_handle_reopen:: as extern "C" fn(&Object, _, _, BOOL) -> BOOL + ); - // Hiding Applications - decl.add_method(sel!(applicationWillHide:), will_hide:: as extern "C" fn(&Object, _, _)); - decl.add_method(sel!(applicationDidHide:), did_hide:: as extern "C" fn(&Object, _, _)); - decl.add_method(sel!(applicationWillUnhide:), will_unhide:: as extern "C" fn(&Object, _, _)); - decl.add_method(sel!(applicationDidUnhide:), did_unhide:: as extern "C" fn(&Object, _, _)); + // Dock Menu + decl.add_method( + sel!(applicationDockMenu:), + dock_menu:: as extern "C" fn(&Object, _, _) -> id + ); - // Managing Windows - decl.add_method(sel!(applicationWillUpdate:), will_update:: as extern "C" fn(&Object, _, _)); - decl.add_method(sel!(applicationDidUpdate:), did_update:: as extern "C" fn(&Object, _, _)); - decl.add_method( - sel!(applicationShouldHandleReopen:hasVisibleWindows:), - should_handle_reopen:: as extern "C" fn(&Object, _, _, BOOL) -> BOOL - ); + // Displaying Errors + decl.add_method( + sel!(application:willPresentError:), + will_present_error:: as extern "C" fn(&Object, _, _, id) -> id + ); - // Dock Menu - decl.add_method( - sel!(applicationDockMenu:), - dock_menu:: as extern "C" fn(&Object, _, _) -> id - ); + // Managing the Screen + decl.add_method( + sel!(applicationDidChangeScreenParameters:), + did_change_screen_parameters:: as extern "C" fn(&Object, _, _) + ); + decl.add_method( + sel!(applicationDidChangeOcclusionState:), + did_change_occlusion_state:: as extern "C" fn(&Object, _, _) + ); - // Displaying Errors - decl.add_method( - sel!(application:willPresentError:), - will_present_error:: as extern "C" fn(&Object, _, _, id) -> id - ); + // User Activities + decl.add_method( + sel!(application:willContinueUserActivityWithType:), + will_continue_user_activity_with_type:: as extern "C" fn(&Object, _, _, id) -> BOOL + ); + decl.add_method( + sel!(application:continueUserActivity:restorationHandler:), + continue_user_activity:: as extern "C" fn(&Object, _, _, id, id) -> BOOL + ); + decl.add_method( + sel!(application:didFailToContinueUserActivityWithType:error:), + failed_to_continue_user_activity:: as extern "C" fn(&Object, _, _, id, id) + ); + decl.add_method( + sel!(application:didUpdateUserActivity:), + did_update_user_activity:: as extern "C" fn(&Object, _, _, id) + ); - // Managing the Screen - decl.add_method( - sel!(applicationDidChangeScreenParameters:), - did_change_screen_parameters:: as extern "C" fn(&Object, _, _) - ); - decl.add_method( - sel!(applicationDidChangeOcclusionState:), - did_change_occlusion_state:: as extern "C" fn(&Object, _, _) - ); + // Handling push notifications + decl.add_method( + sel!(application:didRegisterForRemoteNotificationsWithDeviceToken:), + registered_for_remote_notifications:: as extern "C" fn(&Object, _, _, id) + ); + decl.add_method( + sel!(application:didFailToRegisterForRemoteNotificationsWithError:), + failed_to_register_for_remote_notifications:: as extern "C" fn(&Object, _, _, id) + ); + decl.add_method( + sel!(application:didReceiveRemoteNotification:), + did_receive_remote_notification:: as extern "C" fn(&Object, _, _, id) + ); - // User Activities - decl.add_method( - sel!(application:willContinueUserActivityWithType:), - will_continue_user_activity_with_type:: as extern "C" fn(&Object, _, _, id) -> BOOL - ); - decl.add_method( - sel!(application:continueUserActivity:restorationHandler:), - continue_user_activity:: as extern "C" fn(&Object, _, _, id, id) -> BOOL - ); - decl.add_method( - sel!(application:didFailToContinueUserActivityWithType:error:), - failed_to_continue_user_activity:: as extern "C" fn(&Object, _, _, id, id) - ); - decl.add_method( - sel!(application:didUpdateUserActivity:), - did_update_user_activity:: as extern "C" fn(&Object, _, _, id) - ); + // CloudKit + #[cfg(feature = "cloudkit")] + decl.add_method( + sel!(application:userDidAcceptCloudKitShareWithMetadata:), + accepted_cloudkit_share:: as extern "C" fn(&Object, _, _, id) + ); - // Handling push notifications - decl.add_method( - sel!(application:didRegisterForRemoteNotificationsWithDeviceToken:), - registered_for_remote_notifications:: as extern "C" fn(&Object, _, _, id) - ); - decl.add_method( - sel!(application:didFailToRegisterForRemoteNotificationsWithError:), - failed_to_register_for_remote_notifications:: as extern "C" fn(&Object, _, _, id) - ); - decl.add_method( - sel!(application:didReceiveRemoteNotification:), - did_receive_remote_notification:: as extern "C" fn(&Object, _, _, id) - ); + // Opening Files + decl.add_method( + sel!(application:openURLs:), + open_urls:: as extern "C" fn(&Object, _, _, id) + ); + decl.add_method( + sel!(application:openFileWithoutUI:), + open_file_without_ui:: as extern "C" fn(&Object, _, _, id) -> BOOL + ); + decl.add_method( + sel!(applicationShouldOpenUntitledFile:), + should_open_untitled_file:: as extern "C" fn(&Object, _, _) -> BOOL + ); + decl.add_method( + sel!(applicationOpenUntitledFile:), + open_untitled_file:: as extern "C" fn(&Object, _, _) -> BOOL + ); + decl.add_method( + sel!(application:openTempFile:), + open_temp_file:: as extern "C" fn(&Object, _, _, id) -> BOOL + ); - // CloudKit - #[cfg(feature = "cloudkit")] - decl.add_method( - sel!(application:userDidAcceptCloudKitShareWithMetadata:), - accepted_cloudkit_share:: as extern "C" fn(&Object, _, _, id) - ); + // Printing + decl.add_method( + sel!(application:printFile:), + print_file:: as extern "C" fn(&Object, _, _, id) -> BOOL + ); + decl.add_method( + sel!(application:printFiles:withSettings:showPrintPanels:), + print_files:: as extern "C" fn(&Object, _, id, id, id, BOOL) -> NSUInteger + ); - // Opening Files - decl.add_method( - sel!(application:openURLs:), - open_urls:: as extern "C" fn(&Object, _, _, id) - ); - decl.add_method( - sel!(application:openFileWithoutUI:), - open_file_without_ui:: as extern "C" fn(&Object, _, _, id) -> BOOL - ); - decl.add_method( - sel!(applicationShouldOpenUntitledFile:), - should_open_untitled_file:: as extern "C" fn(&Object, _, _) -> BOOL - ); - decl.add_method( - sel!(applicationOpenUntitledFile:), - open_untitled_file:: as extern "C" fn(&Object, _, _) -> BOOL - ); - decl.add_method( - sel!(application:openTempFile:), - open_temp_file:: as extern "C" fn(&Object, _, _, id) -> BOOL - ); + // @TODO: Restoring Application State + // Depends on NSCoder support, which is... welp. - // Printing - decl.add_method( - sel!(application:printFile:), - print_file:: as extern "C" fn(&Object, _, _, id) -> BOOL - ); - decl.add_method( - sel!(application:printFiles:withSettings:showPrintPanels:), - print_files:: as extern "C" fn(&Object, _, id, id, id, BOOL) -> NSUInteger - ); - - // @TODO: Restoring Application State - // Depends on NSCoder support, which is... welp. - - // Scripting - decl.add_method( - sel!(application:delegateHandlesKey:), - delegate_handles_key:: as extern "C" fn(&Object, _, _, id) -> BOOL - ); - - DELEGATE_CLASS = decl.register(); - }); - } - - unsafe { DELEGATE_CLASS } + // Scripting + decl.add_method( + sel!(application:delegateHandlesKey:), + delegate_handles_key:: as extern "C" fn(&Object, _, _, id) -> BOOL + ); + }) } diff --git a/src/appkit/menu/item.rs b/src/appkit/menu/item.rs index 334ffa4..6c7298d 100644 --- a/src/appkit/menu/item.rs +++ b/src/appkit/menu/item.rs @@ -3,16 +3,13 @@ //! now. use std::fmt; -use std::sync::Once; -use block::ConcreteBlock; -use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel}; use objc::{class, msg_send, sel, sel_impl}; use objc_id::Id; use crate::events::EventModifierFlag; -use crate::foundation::{id, nil, NSString, NSUInteger}; +use crate::foundation::{id, load_or_register_class, NSString, NSUInteger}; static BLOCK_PTR: &'static str = "cacaoMenuItemBlockPtr"; @@ -314,24 +311,10 @@ extern "C" fn fire_block_action(this: &Object, _: Sel, _item: id) { /// In general, we do not want to do more than we need to here - menus are one of the last areas /// where Carbon still lurks, and subclassing things can get weird. pub(crate) fn register_menu_item_class() -> *const Class { - static mut APP_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "CacaoMenuItem"; + load_or_register_class("NSMenuItem", "CacaoMenuItem", |decl| unsafe { + decl.add_ivar::(BLOCK_PTR); - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { APP_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSMenuItem); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - decl.add_ivar::(BLOCK_PTR); - - decl.add_method(sel!(dealloc), dealloc_cacao_menuitem as extern "C" fn(&Object, _)); - decl.add_method(sel!(fireBlockAction:), fire_block_action as extern "C" fn(&Object, _, id)); - - APP_CLASS = decl.register(); - }); - } - - unsafe { APP_CLASS } + decl.add_method(sel!(dealloc), dealloc_cacao_menuitem as extern "C" fn(&Object, _)); + decl.add_method(sel!(fireBlockAction:), fire_block_action as extern "C" fn(&Object, _, id)); + }) } diff --git a/src/appkit/window/controller/class.rs b/src/appkit/window/controller/class.rs index f82c5d0..21cce00 100644 --- a/src/appkit/window/controller/class.rs +++ b/src/appkit/window/controller/class.rs @@ -1,31 +1,15 @@ //! Everything useful for the `WindowController`. Handles injecting an `NSWindowController` subclass //! into the Objective C runtime, which loops back to give us lifecycle methods. -use std::sync::Once; - -use objc::class; -use objc::declare::ClassDecl; use objc::runtime::Class; use crate::appkit::window::{WindowDelegate, WINDOW_DELEGATE_PTR}; +use crate::foundation::load_or_register_class; /// Injects an `NSWindowController` subclass, with some callback and pointer ivars for what we /// need to do. pub(crate) fn register_window_controller_class() -> *const Class { - static mut DELEGATE_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTWindowController"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { DELEGATE_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSWindowController); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - decl.add_ivar::(WINDOW_DELEGATE_PTR); - DELEGATE_CLASS = decl.register(); - }); - } - - unsafe { DELEGATE_CLASS } + load_or_register_class("NSWindowController", "RSTWindowController", |decl| unsafe { + decl.add_ivar::(WINDOW_DELEGATE_PTR); + }) } diff --git a/src/button/mod.rs b/src/button/mod.rs index 979385d..d22b60b 100644 --- a/src/button/mod.rs +++ b/src/button/mod.rs @@ -21,36 +21,28 @@ //! my_view.add_subview(&button); //! ``` -use std::fmt; -use std::sync::Once; - -use std::cell::RefCell; -use std::rc::Rc; - -use objc::declare::ClassDecl; -use objc::runtime::{Class, Object, Sel}; -use objc::{class, msg_send, sel, sel_impl}; +use objc::runtime::{Class, Object}; +use objc::{msg_send, sel, sel_impl}; use objc_id::ShareId; +pub use enums::*; + +#[cfg(feature = "appkit")] +use crate::appkit::FocusRingType; use crate::color::Color; use crate::control::Control; -use crate::foundation::{id, nil, NSString, NSUInteger, BOOL, NO, YES}; +use crate::foundation::{id, load_or_register_class, nil, NSString, NSUInteger, NO, YES}; use crate::image::Image; use crate::invoker::TargetActionHandler; use crate::keys::Key; use crate::layout::Layout; -use crate::objc_access::ObjcAccess; -use crate::text::{AttributedString, Font}; -use crate::utils::{load, properties::ObjcProperty}; - #[cfg(feature = "autolayout")] use crate::layout::{LayoutAnchorDimension, LayoutAnchorX, LayoutAnchorY}; - -#[cfg(feature = "appkit")] -use crate::appkit::FocusRingType; +use crate::objc_access::ObjcAccess; +use crate::text::{AttributedString, Font}; +use crate::utils::properties::ObjcProperty; mod enums; -pub use enums::*; /// Wraps `NSButton` on appkit, and `UIButton` on iOS and tvOS. /// @@ -343,20 +335,5 @@ impl Drop for Button { /// Registers an `NSButton` subclass, and configures it to hold some ivars /// for various things we need to store. fn register_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTButton"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { - VIEW_CLASS = c; - } - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSButton); - let decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - VIEW_CLASS = decl.register(); - }); - } - unsafe { VIEW_CLASS } + load_or_register_class("NSButton", "RSTButton", |decl| unsafe {}) } diff --git a/src/color/appkit_dynamic_color.rs b/src/color/appkit_dynamic_color.rs index 6502614..aa03502 100644 --- a/src/color/appkit_dynamic_color.rs +++ b/src/color/appkit_dynamic_color.rs @@ -10,16 +10,11 @@ //! that enables this functionality, we want to be able to provide this with some level of //! backwards compatibility for Mojave, as that's still a supported OS. -use std::os::raw::c_void; -use std::sync::Once; - use core_graphics::base::CGFloat; - -use objc::declare::ClassDecl; -use objc::runtime::{Class, Object, Sel, BOOL}; +use objc::runtime::{Class, Object, Sel}; use objc::{class, msg_send, sel, sel_impl}; -use crate::foundation::{id, nil, NSArray, NSInteger, NSString, NSUInteger, NO, YES}; +use crate::foundation::{id, load_or_register_class, nil, NSArray, NSInteger}; use crate::utils::os; pub(crate) const AQUA_LIGHT_COLOR_NORMAL_CONTRAST: &'static str = "AQUA_LIGHT_COLOR_NORMAL_CONTRAST"; @@ -259,114 +254,99 @@ extern "C" fn color_with_system_effect(this: &Object, _: Sel, effect: NSInteger) } pub(crate) fn register_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "CacaoDynamicColor"; + load_or_register_class("NSColor", "CacaoDynamicColor", |decl| unsafe { + // These methods all need to be forwarded, so let's hook them up. + decl.add_method(sel!(colorSpace), color_space as extern "C" fn(&Object, _) -> id); + decl.add_method( + sel!(colorUsingColorSpace:), + color_using_color_space as extern "C" fn(&Object, _, id) -> id + ); + decl.add_method(sel!(colorSpaceName), color_space_name as extern "C" fn(&Object, _) -> id); + decl.add_method( + sel!(colorUsingColorSpaceName:), + color_using_color_space_name as extern "C" fn(&Object, _, id) -> id + ); + decl.add_method( + sel!(numberOfComponents), + number_of_components as extern "C" fn(&Object, _) -> NSInteger + ); - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSColor); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); + decl.add_method(sel!(getComponents:), get_components as extern "C" fn(&Object, _, CGFloat)); + decl.add_method( + sel!(getRed:green:blue:alpha:), + get_rgba as extern "C" fn(&Object, _, CGFloat, CGFloat, CGFloat, CGFloat) + ); + decl.add_method(sel!(redComponent), red_component as extern "C" fn(&Object, _) -> CGFloat); + decl.add_method(sel!(greenComponent), green_component as extern "C" fn(&Object, _) -> CGFloat); + decl.add_method(sel!(blueComponent), blue_component as extern "C" fn(&Object, _) -> CGFloat); - // These methods all need to be forwarded, so let's hook them up. - decl.add_method(sel!(colorSpace), color_space as extern "C" fn(&Object, _) -> id); - decl.add_method( - sel!(colorUsingColorSpace:), - color_using_color_space as extern "C" fn(&Object, _, id) -> id - ); - decl.add_method(sel!(colorSpaceName), color_space_name as extern "C" fn(&Object, _) -> id); - decl.add_method( - sel!(colorUsingColorSpaceName:), - color_using_color_space_name as extern "C" fn(&Object, _, id) -> id - ); - decl.add_method( - sel!(numberOfComponents), - number_of_components as extern "C" fn(&Object, _) -> NSInteger - ); + decl.add_method(sel!(hueComponent), hue_component as extern "C" fn(&Object, _) -> CGFloat); + decl.add_method( + sel!(saturationComponent), + saturation_component as extern "C" fn(&Object, _) -> CGFloat + ); + decl.add_method( + sel!(brightnessComponent), + brightness_component as extern "C" fn(&Object, _) -> CGFloat + ); + decl.add_method( + sel!(getHue:saturation:brightness:alpha:), + get_hsba as extern "C" fn(&Object, _, CGFloat, CGFloat, CGFloat, CGFloat) + ); - decl.add_method(sel!(getComponents:), get_components as extern "C" fn(&Object, _, CGFloat)); - decl.add_method( - sel!(getRed:green:blue:alpha:), - get_rgba as extern "C" fn(&Object, _, CGFloat, CGFloat, CGFloat, CGFloat) - ); - decl.add_method(sel!(redComponent), red_component as extern "C" fn(&Object, _) -> CGFloat); - decl.add_method(sel!(greenComponent), green_component as extern "C" fn(&Object, _) -> CGFloat); - decl.add_method(sel!(blueComponent), blue_component as extern "C" fn(&Object, _) -> CGFloat); + decl.add_method(sel!(whiteComponent), white_component as extern "C" fn(&Object, _) -> CGFloat); + decl.add_method( + sel!(getWhite:alpha:), + get_white as extern "C" fn(&Object, _, CGFloat, CGFloat) + ); - decl.add_method(sel!(hueComponent), hue_component as extern "C" fn(&Object, _) -> CGFloat); - decl.add_method( - sel!(saturationComponent), - saturation_component as extern "C" fn(&Object, _) -> CGFloat - ); - decl.add_method( - sel!(brightnessComponent), - brightness_component as extern "C" fn(&Object, _) -> CGFloat - ); - decl.add_method( - sel!(getHue:saturation:brightness:alpha:), - get_hsba as extern "C" fn(&Object, _, CGFloat, CGFloat, CGFloat, CGFloat) - ); + decl.add_method(sel!(cyanComponent), cyan_component as extern "C" fn(&Object, _) -> CGFloat); + decl.add_method( + sel!(magentaComponent), + magenta_component as extern "C" fn(&Object, _) -> CGFloat + ); + decl.add_method( + sel!(yellowComponent), + yellow_component as extern "C" fn(&Object, _) -> CGFloat + ); + decl.add_method(sel!(blackComponent), black_component as extern "C" fn(&Object, _) -> CGFloat); + decl.add_method( + sel!(getCyan:magenta:yellow:black:alpha:), + get_cmyk as extern "C" fn(&Object, _, CGFloat, CGFloat, CGFloat, CGFloat, CGFloat) + ); - decl.add_method(sel!(whiteComponent), white_component as extern "C" fn(&Object, _) -> CGFloat); - decl.add_method( - sel!(getWhite:alpha:), - get_white as extern "C" fn(&Object, _, CGFloat, CGFloat) - ); + decl.add_method(sel!(alphaComponent), alpha_component as extern "C" fn(&Object, _) -> CGFloat); - decl.add_method(sel!(cyanComponent), cyan_component as extern "C" fn(&Object, _) -> CGFloat); - decl.add_method( - sel!(magentaComponent), - magenta_component as extern "C" fn(&Object, _) -> CGFloat - ); - decl.add_method( - sel!(yellowComponent), - yellow_component as extern "C" fn(&Object, _) -> CGFloat - ); - decl.add_method(sel!(blackComponent), black_component as extern "C" fn(&Object, _) -> CGFloat); - decl.add_method( - sel!(getCyan:magenta:yellow:black:alpha:), - get_cmyk as extern "C" fn(&Object, _, CGFloat, CGFloat, CGFloat, CGFloat, CGFloat) - ); + decl.add_method(sel!(CGColor), cg_color as extern "C" fn(&Object, _) -> id); + decl.add_method(sel!(setStroke), set_stroke as extern "C" fn(&Object, _)); + decl.add_method(sel!(setFill), set_fill as extern "C" fn(&Object, _)); + decl.add_method(sel!(set), call_set as extern "C" fn(&Object, _)); - decl.add_method(sel!(alphaComponent), alpha_component as extern "C" fn(&Object, _) -> CGFloat); + decl.add_method( + sel!(highlightWithLevel:), + highlight_with_level as extern "C" fn(&Object, _, CGFloat) -> id + ); + decl.add_method( + sel!(shadowWithLevel:), + shadow_with_level as extern "C" fn(&Object, _, CGFloat) -> id + ); - decl.add_method(sel!(CGColor), cg_color as extern "C" fn(&Object, _) -> id); - decl.add_method(sel!(setStroke), set_stroke as extern "C" fn(&Object, _)); - decl.add_method(sel!(setFill), set_fill as extern "C" fn(&Object, _)); - decl.add_method(sel!(set), call_set as extern "C" fn(&Object, _)); + decl.add_method( + sel!(colorWithAlphaComponent:), + color_with_alpha_component as extern "C" fn(&Object, _, CGFloat) -> id + ); + decl.add_method( + sel!(blendedColorWithFraction:ofColor:), + blended_color as extern "C" fn(&Object, _, CGFloat, id) -> id + ); + decl.add_method( + sel!(colorWithSystemEffect:), + color_with_system_effect as extern "C" fn(&Object, _, NSInteger) -> id + ); - decl.add_method( - sel!(highlightWithLevel:), - highlight_with_level as extern "C" fn(&Object, _, CGFloat) -> id - ); - decl.add_method( - sel!(shadowWithLevel:), - shadow_with_level as extern "C" fn(&Object, _, CGFloat) -> id - ); - - decl.add_method( - sel!(colorWithAlphaComponent:), - color_with_alpha_component as extern "C" fn(&Object, _, CGFloat) -> id - ); - decl.add_method( - sel!(blendedColorWithFraction:ofColor:), - blended_color as extern "C" fn(&Object, _, CGFloat, id) -> id - ); - decl.add_method( - sel!(colorWithSystemEffect:), - color_with_system_effect as extern "C" fn(&Object, _, NSInteger) -> id - ); - - decl.add_ivar::(AQUA_LIGHT_COLOR_NORMAL_CONTRAST); - decl.add_ivar::(AQUA_LIGHT_COLOR_HIGH_CONTRAST); - decl.add_ivar::(AQUA_DARK_COLOR_NORMAL_CONTRAST); - decl.add_ivar::(AQUA_DARK_COLOR_HIGH_CONTRAST); - - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + decl.add_ivar::(AQUA_LIGHT_COLOR_NORMAL_CONTRAST); + decl.add_ivar::(AQUA_LIGHT_COLOR_HIGH_CONTRAST); + decl.add_ivar::(AQUA_DARK_COLOR_NORMAL_CONTRAST); + decl.add_ivar::(AQUA_DARK_COLOR_HIGH_CONTRAST); + }) } diff --git a/src/image/appkit.rs b/src/image/appkit.rs index b388dd2..2af6d95 100644 --- a/src/image/appkit.rs +++ b/src/image/appkit.rs @@ -7,38 +7,15 @@ //! 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::sync::Once; +use objc::runtime::Class; -use objc::declare::ClassDecl; -use objc::runtime::{Class, Object, Sel, BOOL}; -use objc::{class, sel, sel_impl}; -use objc_id::Id; - -use crate::dragdrop::DragInfo; -use crate::foundation::{id, NSUInteger, NO, YES}; -use crate::utils::load; -use crate::view::{ViewDelegate, VIEW_DELEGATE_PTR}; +use crate::foundation::load_or_register_class; /// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we /// have separate classes here since we don't want to waste cycles on methods that will never be /// used if there's no delegates. pub(crate) fn register_image_view_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTImageView"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSImageView); - let decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - - //decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); - - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("NSImageView", "RSTImageView", |decl| unsafe { + //decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); + }) } diff --git a/src/image/uikit.rs b/src/image/uikit.rs index 43acf5d..8cb89a3 100644 --- a/src/image/uikit.rs +++ b/src/image/uikit.rs @@ -1,31 +1,10 @@ -use std::sync::Once; +use objc::runtime::Class; -use objc::declare::ClassDecl; -use objc::runtime::{Class, Object, Sel, BOOL}; -use objc::{class, sel, sel_impl}; -use objc_id::Id; - -use crate::foundation::{id, NSUInteger, NO, YES}; -use crate::utils::load; -use crate::view::{ViewDelegate, VIEW_DELEGATE_PTR}; +use crate::foundation::load_or_register_class; /// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we /// have separate classes here since we don't want to waste cycles on methods that will never be /// used if there's no delegates. pub(crate) fn register_image_view_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTImageView"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(UIImageView); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).expect("Failed to get RSTVIEW"); - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("UIImageView", "RSTImageView", |decl| unsafe {}) } diff --git a/src/input/appkit.rs b/src/input/appkit.rs index 560c14e..66df7b6 100644 --- a/src/input/appkit.rs +++ b/src/input/appkit.rs @@ -1,12 +1,7 @@ -use std::sync::Once; - -use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel, BOOL}; -use objc::{class, msg_send, sel, sel_impl}; -use objc_id::Id; +use objc::{msg_send, sel, sel_impl}; -use crate::dragdrop::DragInfo; -use crate::foundation::{id, load_or_register_class, NSString, NSUInteger, NO, YES}; +use crate::foundation::{id, load_or_register_class, NSString, NO, YES}; use crate::input::{TextFieldDelegate, TEXTFIELD_DELEGATE_PTR}; use crate::utils::load; @@ -52,21 +47,7 @@ extern "C" fn text_should_end_editing(this: &mut Object, _ /// have separate classes here since we don't want to waste cycles on methods that will never be /// used if there's no delegates. pub(crate) fn register_view_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTTextInputField"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSTextField); - let decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("NSTextField", "RSTTextInputField", |decl| unsafe {}) } /// Injects an `NSTextField` subclass, with some callback and pointer ivars for what we diff --git a/src/invoker.rs b/src/invoker.rs index 51ab45f..c923858 100644 --- a/src/invoker.rs +++ b/src/invoker.rs @@ -9,15 +9,12 @@ //! is going away. use std::fmt; -use std::sync::{Arc, Mutex, Once}; -use block::{Block, ConcreteBlock, RcBlock}; -use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel}; -use objc::{class, msg_send, sel, sel_impl}; +use objc::{msg_send, sel, sel_impl}; use objc_id::ShareId; -use crate::foundation::{id, nil, NSString}; +use crate::foundation::{id, load_or_register_class}; use crate::utils::load; pub static ACTION_CALLBACK_PTR: &str = "rstTargetActionPtr"; @@ -95,25 +92,8 @@ extern "C" fn perform(this: &mut Object, _: Sel, _sender: id) /// on drop. We handle the heap copy on the Rust side, so setting the block /// is just an ivar. pub(crate) fn register_invoker_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTTargetActionHandler"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { - VIEW_CLASS = c; - } - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSObject); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - - decl.add_ivar::(ACTION_CALLBACK_PTR); - decl.add_method(sel!(perform:), perform:: as extern "C" fn(&mut Object, _, id)); - - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("NSObject", "RSTTargetActionHandler", |decl| unsafe { + decl.add_ivar::(ACTION_CALLBACK_PTR); + decl.add_method(sel!(perform:), perform:: as extern "C" fn(&mut Object, _, id)); + }) } diff --git a/src/listview/appkit.rs b/src/listview/appkit.rs index 95c5fd3..81b2dd3 100644 --- a/src/listview/appkit.rs +++ b/src/listview/appkit.rs @@ -7,16 +7,13 @@ //! for in the modern era. It also implements a few helpers for things like setting a background //! color, and enforcing layer backing by default. -use std::sync::Once; - -use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel, BOOL}; -use objc::{class, msg_send, sel, sel_impl}; +use objc::{msg_send, sel, sel_impl}; use objc_id::Id; -use crate::appkit::menu::{Menu, MenuItem}; +use crate::appkit::menu::Menu; use crate::dragdrop::DragInfo; -use crate::foundation::{id, load_or_register_class, nil, NSArray, NSInteger, NSUInteger, NO, YES}; +use crate::foundation::{id, load_or_register_class, NSArray, NSInteger, NSUInteger, NO, YES}; use crate::listview::{ListViewDelegate, RowEdge, LISTVIEW_DELEGATE_PTR}; use crate::utils::load; @@ -185,21 +182,7 @@ extern "C" fn dragging_exited(this: &mut Object, _: Sel, in /// `UITableView` semantics; if `NSTableView`'s multi column behavior is needed, then it can /// be added in. pub(crate) fn register_listview_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &'static str = "RSTListView"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSTableView); - let decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("NSTableView", "RSTListView", |decl| unsafe {}) } /// Injects an `NSTableView` subclass, with some callback and pointer ivars for what we diff --git a/src/listview/row/appkit.rs b/src/listview/row/appkit.rs index 25a96e1..054820b 100644 --- a/src/listview/row/appkit.rs +++ b/src/listview/row/appkit.rs @@ -7,15 +7,12 @@ //! 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::sync::Once; - -use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel, BOOL}; use objc::{class, msg_send, sel, sel_impl}; use objc_id::Id; use crate::dragdrop::DragInfo; -use crate::foundation::{id, nil, NSUInteger, NO, YES}; +use crate::foundation::{id, load_or_register_class, nil, NSUInteger, NO, YES}; use crate::listview::row::{ViewDelegate, BACKGROUND_COLOR, LISTVIEW_ROW_DELEGATE_PTR}; use crate::utils::load; @@ -107,76 +104,46 @@ extern "C" fn dealloc(this: &Object, _: Sel) { /// have separate classes here since we don't want to waste cycles on methods that will never be /// used if there's no delegates. pub(crate) fn register_listview_row_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTTableViewRow"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSView); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - - decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); - - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("NSView", "RSTTableViewRow", |decl| unsafe { + decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); + }) } /// Injects an `NSView` subclass, with some callback and pointer ivars for what we /// need to do. pub(crate) fn register_listview_row_class_with_delegate() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTableViewRowWithDelegate"; + load_or_register_class("NSView", "RSTableViewRowWithDelegate", |decl| unsafe { + // A pointer to the "view controller" on the Rust side. It's expected that this doesn't + // move. + decl.add_ivar::(LISTVIEW_ROW_DELEGATE_PTR); + decl.add_ivar::(BACKGROUND_COLOR); - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSView); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); + decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); + decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(&Object, _)); - // A pointer to the "view controller" on the Rust side. It's expected that this doesn't - // move. - decl.add_ivar::(LISTVIEW_ROW_DELEGATE_PTR); - decl.add_ivar::(BACKGROUND_COLOR); + // Drag and drop operations (e.g, accepting files) + decl.add_method( + sel!(draggingEntered:), + dragging_entered:: as extern "C" fn(&mut Object, _, _) -> NSUInteger + ); + decl.add_method( + sel!(prepareForDragOperation:), + prepare_for_drag_operation:: as extern "C" fn(&mut Object, _, _) -> BOOL + ); + decl.add_method( + sel!(performDragOperation:), + perform_drag_operation:: as extern "C" fn(&mut Object, _, _) -> BOOL + ); + decl.add_method( + sel!(concludeDragOperation:), + conclude_drag_operation:: as extern "C" fn(&mut Object, _, _) + ); + decl.add_method( + sel!(draggingExited:), + dragging_exited:: as extern "C" fn(&mut Object, _, _) + ); - decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); - decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(&Object, _)); - - // Drag and drop operations (e.g, accepting files) - decl.add_method( - sel!(draggingEntered:), - dragging_entered:: as extern "C" fn(&mut Object, _, _) -> NSUInteger - ); - decl.add_method( - sel!(prepareForDragOperation:), - prepare_for_drag_operation:: as extern "C" fn(&mut Object, _, _) -> BOOL - ); - decl.add_method( - sel!(performDragOperation:), - perform_drag_operation:: as extern "C" fn(&mut Object, _, _) -> BOOL - ); - decl.add_method( - sel!(concludeDragOperation:), - conclude_drag_operation:: as extern "C" fn(&mut Object, _, _) - ); - decl.add_method( - sel!(draggingExited:), - dragging_exited:: as extern "C" fn(&mut Object, _, _) - ); - - // Cleanup - decl.add_method(sel!(dealloc), dealloc:: as extern "C" fn(&Object, _)); - - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + // Cleanup + decl.add_method(sel!(dealloc), dealloc:: as extern "C" fn(&Object, _)); + }) } diff --git a/src/listview/row/uikit.rs b/src/listview/row/uikit.rs index 1ea8ce4..76ea8b9 100644 --- a/src/listview/row/uikit.rs +++ b/src/listview/row/uikit.rs @@ -1,53 +1,24 @@ -use std::sync::Once; - use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel, BOOL}; use objc::{class, sel, sel_impl}; use objc_id::Id; -use crate::foundation::{id, YES, NO, NSUInteger}; use crate::dragdrop::DragInfo; -use crate::view::{VIEW_DELEGATE_PTR, ViewDelegate}; +use crate::foundation::{id, NSUInteger, NO, YES}; use crate::utils::load; +use crate::view::{ViewDelegate, VIEW_DELEGATE_PTR}; /// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we /// have separate classes here since we don't want to waste cycles on methods that will never be /// used if there's no delegates. pub(crate) fn register_view_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTView"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(UIView); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("UIView", "RSTView", |decl| unsafe {}) } /// Injects an `NSView` subclass, with some callback and pointer ivars for what we /// need to do. pub(crate) fn register_view_class_with_delegate() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTViewWithDelegate"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(UIView); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - decl.add_ivar::(VIEW_DELEGATE_PTR); - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("UIView", "RSTViewWithDelegate", |decl| unsafe { + decl.add_ivar::(VIEW_DELEGATE_PTR); + }) } diff --git a/src/scrollview/appkit.rs b/src/scrollview/appkit.rs index d325465..6d08308 100644 --- a/src/scrollview/appkit.rs +++ b/src/scrollview/appkit.rs @@ -7,15 +7,12 @@ //! 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::sync::Once; - -use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel, BOOL}; -use objc::{class, sel, sel_impl}; +use objc::{sel, sel_impl}; use objc_id::Id; use crate::dragdrop::DragInfo; -use crate::foundation::{id, NSUInteger, NO, YES}; +use crate::foundation::{id, load_or_register_class, NSUInteger, NO, YES}; use crate::scrollview::{ScrollViewDelegate, SCROLLVIEW_DELEGATE_PTR}; use crate::utils::load; @@ -77,68 +74,39 @@ extern "C" fn dragging_exited(this: &mut Object, _: Sel, /// Injects an `NSScrollView` subclass. pub(crate) fn register_scrollview_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &'static str = "RSTScrollView"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSScrollView); - let decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("NSScrollView", "RSTScrollView", |decl| unsafe {}) } /// Injects an `NSView` subclass, with some callback and pointer ivars for what we /// need to do. pub(crate) fn register_scrollview_class_with_delegate() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &'static str = "RSTScrollViewWithDelegate"; + load_or_register_class("NSScrollView", "RSTScrollViewWithDelegate", |decl| unsafe { + // A pointer to the "view controller" on the Rust side. It's expected that this doesn't + // move. + decl.add_ivar::(SCROLLVIEW_DELEGATE_PTR); - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSScrollView); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); + decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); - // A pointer to the "view controller" on the Rust side. It's expected that this doesn't - // move. - decl.add_ivar::(SCROLLVIEW_DELEGATE_PTR); - - decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); - - // Drag and drop operations (e.g, accepting files) - decl.add_method( - sel!(draggingEntered:), - dragging_entered:: as extern "C" fn(&mut Object, _, _) -> NSUInteger - ); - decl.add_method( - sel!(prepareForDragOperation:), - prepare_for_drag_operation:: as extern "C" fn(&mut Object, _, _) -> BOOL - ); - decl.add_method( - sel!(performDragOperation:), - perform_drag_operation:: as extern "C" fn(&mut Object, _, _) -> BOOL - ); - decl.add_method( - sel!(concludeDragOperation:), - conclude_drag_operation:: as extern "C" fn(&mut Object, _, _) - ); - decl.add_method( - sel!(draggingExited:), - dragging_exited:: as extern "C" fn(&mut Object, _, _) - ); - - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + // Drag and drop operations (e.g, accepting files) + decl.add_method( + sel!(draggingEntered:), + dragging_entered:: as extern "C" fn(&mut Object, _, _) -> NSUInteger + ); + decl.add_method( + sel!(prepareForDragOperation:), + prepare_for_drag_operation:: as extern "C" fn(&mut Object, _, _) -> BOOL + ); + decl.add_method( + sel!(performDragOperation:), + perform_drag_operation:: as extern "C" fn(&mut Object, _, _) -> BOOL + ); + decl.add_method( + sel!(concludeDragOperation:), + conclude_drag_operation:: as extern "C" fn(&mut Object, _, _) + ); + decl.add_method( + sel!(draggingExited:), + dragging_exited:: as extern "C" fn(&mut Object, _, _) + ); + }) } diff --git a/src/select/mod.rs b/src/select/mod.rs index 2cbdd2e..3c8303e 100644 --- a/src/select/mod.rs +++ b/src/select/mod.rs @@ -1,24 +1,19 @@ //! Implements a Select-style dropdown. By default this uses NSPopupSelect on macOS. -use std::sync::Once; - use core_graphics::geometry::CGRect; - -use objc::declare::ClassDecl; -use objc::runtime::{Class, Object, Sel}; -use objc::{class, msg_send, sel, sel_impl}; +use objc::runtime::{Class, Object}; +use objc::{msg_send, sel, sel_impl}; use objc_id::ShareId; use crate::control::Control; -use crate::foundation::{id, nil, NSInteger, NSString, NO, YES}; +use crate::foundation::{id, load_or_register_class, nil, NSInteger, NSString, NO, YES}; use crate::geometry::Rect; use crate::invoker::TargetActionHandler; use crate::layout::Layout; -use crate::objc_access::ObjcAccess; -use crate::utils::properties::ObjcProperty; - #[cfg(feature = "autolayout")] use crate::layout::{LayoutAnchorDimension, LayoutAnchorX, LayoutAnchorY}; +use crate::objc_access::ObjcAccess; +use crate::utils::properties::ObjcProperty; /// Wraps `NSPopUpSelect` on AppKit. Not currently implemented for iOS. /// @@ -268,19 +263,5 @@ impl Drop for Select { /// Registers an `NSSelect` subclass, and configures it to hold some ivars /// for various things we need to store. fn register_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "CacaoSelect"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSPopUpButton); - let decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("NSPopUpButton", "CacaoSelect", |decl| unsafe {}) } diff --git a/src/switch.rs b/src/switch.rs index 5d04c87..4631beb 100644 --- a/src/switch.rs +++ b/src/switch.rs @@ -1,22 +1,17 @@ //! A wrapper for NSSwitch. Currently the epitome of jank - if you're poking around here, expect //! that this will change at some point. -use std::fmt; -use std::sync::Once; - -use objc::declare::ClassDecl; -use objc::runtime::{Class, Object, Sel}; -use objc::{class, msg_send, sel, sel_impl}; +use objc::runtime::{Class, Object}; +use objc::{msg_send, sel, sel_impl}; use objc_id::ShareId; -use crate::foundation::{id, nil, NSString, BOOL, NO, YES}; +use crate::foundation::{id, load_or_register_class, nil, NSString, NO}; use crate::invoker::TargetActionHandler; use crate::layout::Layout; -use crate::objc_access::ObjcAccess; -use crate::utils::{load, properties::ObjcProperty}; - #[cfg(feature = "autolayout")] use crate::layout::{LayoutAnchorDimension, LayoutAnchorX, LayoutAnchorY}; +use crate::objc_access::ObjcAccess; +use crate::utils::properties::ObjcProperty; /// A wrapper for `NSSwitch`. Holds (retains) pointers for the Objective-C runtime /// where our `NSSwitch` lives. @@ -178,21 +173,5 @@ impl Drop for Switch { /// Registers an `NSButton` subclass, and configures it to hold some ivars /// for various things we need to store. fn register_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTSwitch"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { - VIEW_CLASS = c; - } - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSButton); - let decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("NSButton", "RSTSwitch", |decl| unsafe {}) } diff --git a/src/text/label/appkit.rs b/src/text/label/appkit.rs index e27fe1b..4dfc927 100644 --- a/src/text/label/appkit.rs +++ b/src/text/label/appkit.rs @@ -7,60 +7,24 @@ //! 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::sync::Once; +use objc::runtime::Class; -use objc::declare::ClassDecl; -use objc::runtime::{Class, Object, Sel, BOOL}; -use objc::{class, sel, sel_impl}; -use objc_id::Id; - -use crate::dragdrop::DragInfo; -use crate::foundation::{id, NSUInteger, NO, YES}; +use crate::foundation::load_or_register_class; use crate::text::label::{LabelDelegate, LABEL_DELEGATE_PTR}; -use crate::utils::load; /// Injects an `NSTextField` subclass. This is used for the default views that don't use delegates - we /// have separate classes here since we don't want to waste cycles on methods that will never be /// used if there's no delegates. pub(crate) fn register_view_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTTextField"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSTextField); - let decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("NSTextField", "RSTTextField", |decl| unsafe {}) } /// Injects an `NSTextField` subclass, with some callback and pointer ivars for what we /// need to do. pub(crate) fn register_view_class_with_delegate() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTTextFieldWithDelegate"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSView); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - - // A pointer to the "view controller" on the Rust side. It's expected that this doesn't - // move. - decl.add_ivar::(LABEL_DELEGATE_PTR); - - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("NSView", "RSTTextFieldWithDelegate", |decl| unsafe { + // A pointer to the "view controller" on the Rust side. It's expected that this doesn't + // move. + decl.add_ivar::(LABEL_DELEGATE_PTR); + }) } diff --git a/src/uikit/app/class.rs b/src/uikit/app/class.rs index 37909f0..9ac3706 100644 --- a/src/uikit/app/class.rs +++ b/src/uikit/app/class.rs @@ -2,27 +2,11 @@ //! creates a custom `UIApplication` subclass that currently does nothing; this is meant as a hook //! for potential future use. -use std::sync::Once; - -use objc::class; -use objc::declare::ClassDecl; use objc::runtime::Class; +use crate::foundation::load_or_register_class; + /// Used for injecting a custom UIApplication. Currently does nothing. pub(crate) fn register_app_class() -> *const Class { - static mut APP_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTApplication"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { APP_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(UIApplication); - let decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - APP_CLASS = decl.register(); - }); - } - - unsafe { APP_CLASS } + load_or_register_class("UIApplication", "RSTApplication", |decl| unsafe {}) } diff --git a/src/uikit/app/delegate.rs b/src/uikit/app/delegate.rs index 5462b69..ddf36f5 100644 --- a/src/uikit/app/delegate.rs +++ b/src/uikit/app/delegate.rs @@ -2,28 +2,20 @@ //! creates a custom `UIApplication` subclass that currently does nothing; this is meant as a hook //! for potential future use. -//use std::ffi::c_void; -use std::sync::Once; +use objc::runtime::{Class, Object, Sel}; +use objc::{sel, sel_impl}; + +//use crate::error::Error; +use crate::foundation::{id, load_or_register_class, BOOL, YES}; +use crate::uikit::app::{AppDelegate, APP_DELEGATE}; +use crate::uikit::scene::{SceneConnectionOptions, SceneSession}; + //use std::unreachable; //use block::Block; -use objc::declare::ClassDecl; -use objc::runtime::{Class, Object, Sel}; -use objc::{class, msg_send, sel, sel_impl}; - -use url::Url; - -//use crate::error::Error; -use crate::foundation::{id, nil, NSArray, NSString, NSUInteger, BOOL, NO, YES}; //use crate::user_activity::UserActivity; -use crate::uikit::app::{AppDelegate, APP_DELEGATE}; -use crate::uikit::scene::{SceneConfig, SceneConnectionOptions, SceneSession}; - -#[cfg(feature = "cloudkit")] -use crate::cloudkit::share::CKShareMetaData; - /// A handy method for grabbing our `AppDelegate` from the pointer. This is different from our /// standard `utils` version as this doesn't require `RefCell` backing. fn app(this: &Object) -> &T { @@ -49,36 +41,21 @@ extern "C" fn configuration_for_scene_session(this: &Object, _: /// 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(); - const CLASS_NAME: &str = "RSTAppDelegate"; + load_or_register_class("NSObject", "RSTAppDelegate", |decl| unsafe { + // Launching Applications + decl.add_method( + sel!(application:didFinishLaunchingWithOptions:), + did_finish_launching:: as extern "C" fn(&Object, _, _, id) -> BOOL + ); - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { DELEGATE_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSObject); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - - // Launching Applications - decl.add_method( - sel!(application:didFinishLaunchingWithOptions:), - did_finish_launching:: as extern "C" fn(&Object, _, _, id) -> BOOL - ); - - // Scenes - decl.add_method( - sel!(application:configurationForConnectingSceneSession:options:), - configuration_for_scene_session:: as extern "C" fn(&Object, _, _, id, id) -> id - ); - /*decl.add_method( - sel!(application:didDiscardSceneSessions:), - did_discard_scene_sessions:: as extern "C" fn(&Object, _, _, id) - );*/ - - DELEGATE_CLASS = decl.register(); - }); - } - - unsafe { DELEGATE_CLASS } + // Scenes + decl.add_method( + sel!(application:configurationForConnectingSceneSession:options:), + configuration_for_scene_session:: as extern "C" fn(&Object, _, _, id, id) -> id + ); + /*decl.add_method( + sel!(application:didDiscardSceneSessions:), + did_discard_scene_sessions:: as extern "C" fn(&Object, _, _, id) + );*/ + }) } diff --git a/src/uikit/scene/delegate.rs b/src/uikit/scene/delegate.rs index 2406f84..ac6092a 100644 --- a/src/uikit/scene/delegate.rs +++ b/src/uikit/scene/delegate.rs @@ -1,25 +1,10 @@ -use std::ffi::c_void; -use std::sync::Once; -use std::unreachable; - -use block::Block; - -use objc::declare::ClassDecl; -use objc::runtime::{Class, Object, Sel}; +use objc::runtime::{Class, Object, Protocol, Sel}; use objc::{class, msg_send, sel, sel_impl}; -use url::Url; - -use crate::error::Error; -use crate::foundation::{id, nil, NSArray, NSString, NSUInteger, BOOL, NO, YES}; -use crate::user_activity::UserActivity; -use crate::utils::load; - +use crate::foundation::{id, load_or_register_class}; use crate::uikit::app::SCENE_DELEGATE_VENDOR; -use crate::uikit::scene::{Scene, SceneConfig, SceneConnectionOptions, SceneSession, WindowSceneDelegate}; - -#[cfg(feature = "cloudkit")] -use crate::cloudkit::share::CKShareMetaData; +use crate::uikit::scene::{Scene, SceneConnectionOptions, SceneSession, WindowSceneDelegate}; +use crate::utils::load; pub(crate) static WINDOW_SCENE_PTR: &str = "rstWindowSceneDelegatePtr"; @@ -60,37 +45,20 @@ extern "C" fn scene_will_connect_to_session_with_options /// Registers an `NSObject` application delegate, and configures it for the various callbacks and /// pointers we need to have. pub(crate) fn register_window_scene_delegate_class Box>() -> *const Class { - static mut DELEGATE_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTWindowSceneDelegate"; + load_or_register_class("UIResponder", "RSTWindowSceneDelegate", |decl| unsafe { + let p = Protocol::get("UIWindowSceneDelegate").unwrap(); - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { DELEGATE_CLASS = c }; - } else { - use objc::runtime::Protocol; - INIT.call_once(|| unsafe { - let superclass = class!(UIResponder); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); + // A spot to hold a pointer to + decl.add_ivar::(WINDOW_SCENE_PTR); + decl.add_protocol(p); - let p = Protocol::get("UIWindowSceneDelegate").unwrap(); + // Override the `init` call to handle creating and attaching a WindowSceneDelegate. + decl.add_method(sel!(init), init:: as extern "C" fn(&mut Object, _) -> id); - // A spot to hold a pointer to - decl.add_ivar::(WINDOW_SCENE_PTR); - decl.add_protocol(p); - - // Override the `init` call to handle creating and attaching a WindowSceneDelegate. - decl.add_method(sel!(init), init:: as extern "C" fn(&mut Object, _) -> id); - - // UIWindowSceneDelegate API - decl.add_method( - sel!(scene:willConnectToSession:options:), - scene_will_connect_to_session_with_options:: as extern "C" fn(&Object, _, _, _, _) - ); - - // Launching Applications - DELEGATE_CLASS = decl.register(); - }); - } - - unsafe { DELEGATE_CLASS } + // UIWindowSceneDelegate API + decl.add_method( + sel!(scene:willConnectToSession:options:), + scene_will_connect_to_session_with_options:: as extern "C" fn(&Object, _, _, _, _) + ); + }) } diff --git a/src/view/appkit.rs b/src/view/appkit.rs index 85bc096..4ada6c0 100644 --- a/src/view/appkit.rs +++ b/src/view/appkit.rs @@ -7,8 +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::sync::Once; - use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel, BOOL}; use objc::{class, msg_send, sel, sel_impl}; @@ -92,28 +90,13 @@ extern "C" fn update_layer(this: &Object, _: Sel) { /// have separate classes here since we don't want to waste cycles on methods that will never be /// used if there's no delegates. pub(crate) fn register_view_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTView"; + load_or_register_class("NSView", "RSTView", |decl| unsafe { + decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); + decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(&Object, _)); + decl.add_method(sel!(wantsUpdateLayer), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(NSView); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - - decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); - decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(&Object, _)); - decl.add_method(sel!(wantsUpdateLayer), enforce_normalcy as extern "C" fn(&Object, _) -> BOOL); - - decl.add_ivar::(BACKGROUND_COLOR); - - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + decl.add_ivar::(BACKGROUND_COLOR); + }) } /// Injects an `NSView` subclass, with some callback and pointer ivars for what we diff --git a/src/view/splitviewcontroller/ios.rs b/src/view/splitviewcontroller/ios.rs index bb4cf59..0cc0a45 100644 --- a/src/view/splitviewcontroller/ios.rs +++ b/src/view/splitviewcontroller/ios.rs @@ -1,13 +1,10 @@ -use std::sync::Once; -use std::unreachable; - use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel}; use objc::{class, msg_send, sel, sel_impl}; -use crate::foundation::{BOOL}; -use crate::view::{VIEW_DELEGATE_PTR, ViewDelegate}; -use crate::utils::{load, as_bool}; +use crate::foundation::BOOL; +use crate::utils::{as_bool, load}; +use crate::view::{ViewDelegate, VIEW_DELEGATE_PTR}; /// Called when the view controller receives a `viewWillAppear:` message. extern "C" fn will_appear(this: &mut Object, _: Sel, animated: BOOL) { @@ -51,32 +48,18 @@ extern "C" fn did_disappear(this: &mut Object, _: Sel, animated /// Registers an `NSViewDelegate`. pub(crate) fn register_view_controller_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTViewController"; + load_or_register_class("UIViewController", "RSTViewController", |decl| unsafe { + decl.add_ivar::(VIEW_DELEGATE_PTR); - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(UIViewController); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - - decl.add_ivar::(VIEW_DELEGATE_PTR); - - decl.add_method(sel!(viewWillAppear:), will_appear:: as extern "C" fn(&mut Object, _, BOOL)); - decl.add_method(sel!(viewDidAppear:), did_appear:: as extern "C" fn(&mut Object, _, BOOL)); - decl.add_method( - sel!(viewWillDisappear:), - will_disappear:: as extern "C" fn(&mut Object, _, BOOL) - ); - decl.add_method( - sel!(viewDidDisappear:), - did_disappear:: as extern "C" fn(&mut Object, _, BOOL) - ); - - VIEW_CLASS = decl.register(); - }); - } - unsafe { VIEW_CLASS } + decl.add_method(sel!(viewWillAppear:), will_appear:: as extern "C" fn(&mut Object, _, BOOL)); + decl.add_method(sel!(viewDidAppear:), did_appear:: as extern "C" fn(&mut Object, _, BOOL)); + decl.add_method( + sel!(viewWillDisappear:), + will_disappear:: as extern "C" fn(&mut Object, _, BOOL) + ); + decl.add_method( + sel!(viewDidDisappear:), + did_disappear:: as extern "C" fn(&mut Object, _, BOOL) + ); + }) } diff --git a/src/view/uikit.rs b/src/view/uikit.rs index 54015ce..ba02945 100644 --- a/src/view/uikit.rs +++ b/src/view/uikit.rs @@ -1,5 +1,3 @@ -use std::sync::Once; - use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel, BOOL}; use objc::{class, sel, sel_impl}; @@ -14,21 +12,7 @@ use crate::view::{ViewDelegate, VIEW_DELEGATE_PTR}; /// have separate classes here since we don't want to waste cycles on methods that will never be /// used if there's no delegates. pub(crate) fn register_view_class() -> *const Class { - static mut VIEW_CLASS: *const Class = 0 as *const Class; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTView"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { VIEW_CLASS = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = class!(UIView); - let mut decl = ClassDecl::new(CLASS_NAME, superclass).unwrap(); - VIEW_CLASS = decl.register(); - }); - } - - unsafe { VIEW_CLASS } + load_or_register_class("UIView", "RSTView", |decl| unsafe {}) } /// Injects a `UIView` subclass, with some callback and pointer ivars for what we diff --git a/src/webview/process_pool.rs b/src/webview/process_pool.rs index 718b292..62f5c7d 100644 --- a/src/webview/process_pool.rs +++ b/src/webview/process_pool.rs @@ -4,46 +4,23 @@ //! //! If you use that feature, there are no guarantees you'll be accepted into the App Store. -use std::sync::Once; -use std::ffi::c_void; - use block::Block; - -use cocoa::foundation::{NSRect, NSPoint, NSSize, NSString, NSArray, NSInteger}; - +use cocoa::foundation::{NSArray, NSInteger, NSPoint, NSRect, NSSize, NSString}; use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel, BOOL}; use objc::{class, msg_send, sel, sel_impl}; -use crate::foundation::{id, nil, YES, NO}; +use crate::foundation::{id, nil, NO, YES}; use crate::webview::traits::WebViewController; extern "C" fn download_delegate(this: &Object, _: Sel) -> id { println!("YO!"); - unsafe { - NSString::alloc(nil).init_str("") - } + unsafe { NSString::alloc(nil).init_str("") } } pub fn register_process_pool() -> *const Object { - static mut PROCESS_POOL: *const Object = 0 as *const Object; - static INIT: Once = Once::new(); - const CLASS_NAME: &str = "RSTWebViewProcessPool"; - - if let Some(c) = Class::get(CLASS_NAME) { - unsafe { PROCESS_POOL = c }; - } else { - INIT.call_once(|| unsafe { - let superclass = Class::get("WKProcessPool").unwrap(); - let mut decl = ClassDecl::new("RSTWebViewProcessPool", superclass).unwrap(); - - //decl.add_ivar::(DOWNLOAD_DELEGATE_PTR); - decl.add_method(sel!(_downloadDelegate), download_delegate as extern "C" fn(&Object, _) -> id); - - //PROCESS_POOL = decl.register(); - PROCESS_POOL = msg_send![decl.register(), new]; - }); - } - - unsafe { PROCESS_POOL } + load_or_register_class("WKProcessPool", "RSTWebViewProcessPool", |decl| unsafe { + //decl.add_ivar::(DOWNLOAD_DELEGATE_PTR); + decl.add_method(sel!(_downloadDelegate), download_delegate as extern "C" fn(&Object, _) -> id); + }) }