diff --git a/appkit/src/utils.rs b/appkit/src/utils.rs index 364592e..bdf5591 100644 --- a/appkit/src/utils.rs +++ b/appkit/src/utils.rs @@ -2,6 +2,8 @@ //! belong to. These are typically internal, and if you rely on them... well, don't be surprised if //! they go away one day. +use std::rc::Rc; +use std::cell::RefCell; use std::{slice, str}; use std::os::raw::c_char; @@ -9,6 +11,7 @@ use cocoa::base::id; use cocoa::foundation::NSString; use objc::{msg_send, sel, sel_impl}; +use objc::runtime::Object; /// A utility method for taking an `NSString` and bridging it to a Rust `&str`. pub fn str_from(nsstring: id) -> &'static str { @@ -23,3 +26,14 @@ pub fn str_from(nsstring: id) -> &'static str { str::from_utf8(bytes).unwrap() } } + +/// Used for moving a pointer back into an Rc, so we can work with the object held behind it. Note +/// that it's very important to make sure you reverse this when you're done (using +/// `Rc::into_raw()`) otherwise you'll cause problems due to the `Drop` logic. +pub fn load(this: &Object, ptr: &str) -> Rc> { + unsafe { + let ptr: usize = *this.get_ivar(ptr); + let view_ptr = ptr as *const RefCell; + Rc::from_raw(view_ptr) + } +} diff --git a/appkit/src/view/class.rs b/appkit/src/view/class.rs index 263a979..2bcd529 100644 --- a/appkit/src/view/class.rs +++ b/appkit/src/view/class.rs @@ -7,7 +7,6 @@ //! for in the modern era. It also implements a few helpers for things like setting a background //! color, and enforcing layer backing by default. -use std::cell::RefCell; use std::rc::Rc; use std::sync::Once; @@ -22,6 +21,8 @@ use objc_id::Id; use crate::constants::{BACKGROUND_COLOR, VIEW_CONTROLLER_PTR}; use crate::dragdrop::DragInfo; use crate::view::traits::ViewController; +use crate::utils::load; + /// Enforces normalcy, or: a needlessly cruel method in terms of the name. You get the idea though. extern fn enforce_normalcy(_: &Object, _: Sel) -> BOOL { @@ -42,106 +43,84 @@ extern fn update_layer(this: &Object, _: Sel) { /// Called when a drag/drop operation has entered this view. extern fn dragging_entered(this: &mut Object, _: Sel, info: id) -> NSUInteger { - unsafe { - let ptr: usize = *this.get_ivar(VIEW_CONTROLLER_PTR); - let view_ptr = ptr as *const RefCell; - let view = Rc::from_raw(view_ptr); - - let response = { - let v = view.borrow(); - - (*v).dragging_entered(DragInfo { - info: Id::from_ptr(info) - }).into() - }; + let view = load::(this, VIEW_CONTROLLER_PTR); - Rc::into_raw(view); - response - } + let response = { + let v = view.borrow(); + + (*v).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(this: &mut Object, _: Sel, info: id) -> BOOL { - unsafe { - let ptr: usize = *this.get_ivar(VIEW_CONTROLLER_PTR); - let view_ptr = ptr as *const RefCell; - let view = Rc::from_raw(view_ptr); + let view = load::(this, VIEW_CONTROLLER_PTR); + + let response = { + let v = view.borrow(); - let response = { - let v = view.borrow(); - - match (*v).prepare_for_drag_operation(DragInfo { - info: Id::from_ptr(info) - }) { - true => YES, - false => NO - } - }; + match (*v).prepare_for_drag_operation(DragInfo { + info: unsafe { Id::from_ptr(info) } + }) { + true => YES, + false => NO + } + }; - Rc::into_raw(view); - response - } + Rc::into_raw(view); + response } /// Called when a drag/drop operation has entered this view. extern fn perform_drag_operation(this: &mut Object, _: Sel, info: id) -> BOOL { - unsafe { - let ptr: usize = *this.get_ivar(VIEW_CONTROLLER_PTR); - let view_ptr = ptr as *const RefCell; - let view = Rc::from_raw(view_ptr); + let view = load::(this, VIEW_CONTROLLER_PTR); - let response = { - let v = view.borrow(); - - match (*v).perform_drag_operation(DragInfo { - info: Id::from_ptr(info) - }) { - true => YES, - false => NO - } - }; + let response = { + let v = view.borrow(); + + match (*v).perform_drag_operation(DragInfo { + info: unsafe { Id::from_ptr(info) } + }) { + true => YES, + false => NO + } + }; - Rc::into_raw(view); - response - } + Rc::into_raw(view); + response } /// Called when a drag/drop operation has entered this view. extern fn conclude_drag_operation(this: &mut Object, _: Sel, info: id) { - unsafe { - let ptr: usize = *this.get_ivar(VIEW_CONTROLLER_PTR); - let view_ptr = ptr as *const RefCell; - let view = Rc::from_raw(view_ptr); - - let response = { - let v = view.borrow(); - (*v).conclude_drag_operation(DragInfo { - info: Id::from_ptr(info) - }); - }; + let view = load::(this, VIEW_CONTROLLER_PTR); - Rc::into_raw(view); - response + { + let v = view.borrow(); + (*v).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(this: &mut Object, _: Sel, info: id) { - unsafe { - let ptr: usize = *this.get_ivar(VIEW_CONTROLLER_PTR); - let view_ptr = ptr as *const RefCell; - let view = Rc::from_raw(view_ptr); + let view = load::(this, VIEW_CONTROLLER_PTR); - let response = { - let v = view.borrow(); - (*v).dragging_exited(DragInfo { - info: Id::from_ptr(info) - }); - }; - - Rc::into_raw(view); - response + { + let v = view.borrow(); + (*v).dragging_exited(DragInfo { + info: unsafe { Id::from_ptr(info) } + }); } + + Rc::into_raw(view); } /// Injects an `NSView` subclass, with some callback and pointer ivars for what we diff --git a/appkit/src/window/controller.rs b/appkit/src/window/controller.rs index 9d2a2bb..3f35b4a 100644 --- a/appkit/src/window/controller.rs +++ b/appkit/src/window/controller.rs @@ -1,6 +1,7 @@ //! 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::rc::Rc; use std::sync::Once; use cocoa::base::id; @@ -9,18 +10,21 @@ use objc::declare::ClassDecl; use objc::runtime::{Class, Object, Sel}; use objc::{class, sel, sel_impl}; +use crate::constants::WINDOW_CONTROLLER_PTR; +use crate::utils::load; use crate::window::WindowController; -static WINDOW_CONTROLLER_PTR: &str = "rstWindowController"; - /// Called when an `NSWindow` receives a `windowWillClose:` event. /// Good place to clean up memory and what not. extern fn will_close(this: &Object, _: Sel, _: id) { - unsafe { - let window_ptr: usize = *this.get_ivar(WINDOW_CONTROLLER_PTR); - let window = window_ptr as *const T; + let window = load::(this, WINDOW_CONTROLLER_PTR); + + { + let window = window.borrow(); (*window).will_close(); } + + Rc::into_raw(window); } /// Injects an `NSWindowController` subclass, with some callback and pointer ivars for what we diff --git a/appkit/src/window/window.rs b/appkit/src/window/window.rs index 1f7d705..b6bd341 100644 --- a/appkit/src/window/window.rs +++ b/appkit/src/window/window.rs @@ -4,8 +4,7 @@ use std::rc::Rc; use std::cell::RefCell; -use cocoa::base::{id, nil, YES, NO}; -use cocoa::foundation::{NSSize, NSString}; +use cocoa::base::{id, nil}; use objc::{msg_send, sel, sel_impl}; use objc_id::ShareId;