Webview patches

This commit is contained in:
Ryan McGrath 2020-03-30 00:37:10 -07:00
parent ad54670ffd
commit ccaf61f56f
No known key found for this signature in database
GPG key ID: 811674B62B666830
3 changed files with 54 additions and 100 deletions

View file

@ -4,7 +4,6 @@
use std::ffi::c_void;
use std::sync::Once;
use std::rc::Rc;
use block::Block;
@ -50,11 +49,8 @@ extern fn on_message<T: WebViewDelegate>(this: &Object, _: Sel, _: id, script_me
unsafe {
let name = NSString::wrap(msg_send![script_message, name]).to_str();
let body = NSString::wrap(msg_send![script_message, body]).to_str();
let d = delegate.borrow();
(*d).on_message(name, body);
delegate.on_message(name, body);
}
Rc::into_raw(delegate);
}
/// Fires when deciding a navigation policy - i.e, should something be allowed or not.
@ -63,16 +59,10 @@ extern fn decide_policy_for_action<T: WebViewDelegate>(this: &Object, _: Sel, _:
let action = NavigationAction::new(action);
{
let d = delegate.borrow();
(*d).policy_for_navigation_action(action, |policy| unsafe {
let handler = handler as *const Block<(NSInteger,), c_void>;
(*handler).call((policy.into(),));
});
}
Rc::into_raw(delegate);
delegate.policy_for_navigation_action(action, |policy| unsafe {
let handler = handler as *const Block<(NSInteger,), c_void>;
(*handler).call((policy.into(),));
});
}
/// Fires when deciding a navigation policy - i.e, should something be allowed or not.
@ -81,44 +71,32 @@ extern fn decide_policy_for_response<T: WebViewDelegate>(this: &Object, _: Sel,
let response = NavigationResponse::new(response);
{
let d = delegate.borrow();
(*d).policy_for_navigation_response(response, |policy| unsafe {
let handler = handler as *const Block<(NSInteger,), c_void>;
(*handler).call((policy.into(),));
});
}
Rc::into_raw(delegate);
delegate.policy_for_navigation_response(response, |policy| unsafe {
let handler = handler as *const Block<(NSInteger,), c_void>;
(*handler).call((policy.into(),));
});
}
/// Fires when deciding a navigation policy - i.e, should something be allowed or not.
extern fn run_open_panel<T: WebViewDelegate>(this: &Object, _: Sel, _: id, params: id, _: id, handler: usize) {
let delegate = load::<T>(this, WEBVIEW_DELEGATE_PTR);
{
let d = delegate.borrow();
delegate.run_open_panel(params.into(), move |urls| unsafe {
let handler = handler as *const Block<(id,), c_void>;
(*d).run_open_panel(params.into(), move |urls| unsafe {
let handler = handler as *const Block<(id,), c_void>;
match urls {
Some(u) => {
let nsurls: NSArray = u.iter().map(|s| {
let s = NSString::new(s);
msg_send![class!(NSURL), URLWithString:s.into_inner()]
}).collect::<Vec<id>>().into();
match urls {
Some(u) => {
let nsurls: NSArray = u.iter().map(|s| {
let s = NSString::new(s);
msg_send![class!(NSURL), URLWithString:s.into_inner()]
}).collect::<Vec<id>>().into();
(*handler).call((nsurls.into_inner(),));
},
(*handler).call((nsurls.into_inner(),));
},
None => { (*handler).call((nil,)); }
}
});
}
Rc::into_raw(delegate);
None => { (*handler).call((nil,)); }
}
});
}
/// Called when a download has been initiated in the WebView, and when the navigation policy
@ -131,24 +109,18 @@ extern fn handle_download<T: WebViewDelegate>(this: &Object, _: Sel, download: i
let handler = handler as *const Block<(objc::runtime::BOOL, id), c_void>;
let filename = NSString::wrap(suggested_filename).to_str();
{
let d = delegate.borrow();
delegate.run_save_panel(filename, move |can_overwrite, path| unsafe {
if path.is_none() {
let _: () = msg_send![download, cancel];
}
(*d).run_save_panel(filename, move |can_overwrite, path| unsafe {
if path.is_none() {
let _: () = msg_send![download, cancel];
}
let path = NSString::new(&path.unwrap());
(*handler).call((match can_overwrite {
true => YES,
false => NO
}, path.into_inner()));
});
}
Rc::into_raw(delegate);
let path = NSString::new(&path.unwrap());
(*handler).call((match can_overwrite {
true => YES,
false => NO
}, path.into_inner()));
});
}
/// Registers an `NSViewController` that we effectively turn into a `WebViewController`. Acts as

View file

@ -13,32 +13,32 @@
//! Apple does not ship `WKWebView` on tvOS, and as a result this control is not provided on that
//! platform.
use std::rc::Rc;
use std::cell::RefCell;
use core_graphics::geometry::CGRect;
use objc_id::ShareId;
use objc::runtime::Object;
use objc::{class, msg_send, sel, sel_impl};
use crate::foundation::{id, YES, NO, NSString};
use crate::foundation::{id, nil, YES, NO, NSString};
use crate::geometry::Rect;
use crate::layout::{Layout, LayoutAnchorX, LayoutAnchorY, LayoutAnchorDimension};
pub mod actions;
pub mod enums;
mod actions;
pub use actions::*;
mod config;
pub use config::WebViewConfig;
mod enums;
pub use enums::*;
pub(crate) mod class;
use class::{register_webview_class, register_webview_delegate_class};
//pub(crate) mod process_pool;
pub mod traits;
mod traits;
pub use traits::WebViewDelegate;
pub mod config;
pub use config::WebViewConfig;
pub(crate) static WEBVIEW_DELEGATE_PTR: &str = "rstWebViewDelegatePtr";
fn allocate_webview(
@ -87,12 +87,8 @@ pub struct WebView<T = ()> {
/// we do so.
pub objc_delegate: Option<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,
@ -130,7 +126,6 @@ impl WebView {
let view = allocate_webview(config, None);
WebView {
internal_callback_ptr: None,
delegate: None,
objc_delegate: None,
top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }),
@ -150,23 +145,18 @@ impl<T> WebView<T> where T: WebViewDelegate + 'static {
/// Initializes a new WebView with a given `WebViewDelegate`. This enables you to respond to events
/// and customize the view as a module, similar to class-based systems.
pub fn with(config: WebViewConfig, delegate: T) -> WebView<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 objc_delegate = unsafe {
let objc_delegate: id = msg_send![register_webview_delegate_class::<T>(), new];
(&mut *objc_delegate).set_ivar(WEBVIEW_DELEGATE_PTR, internal_callback_ptr as usize);
let ptr: *const T = &*delegate;
(&mut *objc_delegate).set_ivar(WEBVIEW_DELEGATE_PTR, ptr as usize);
ShareId::from_ptr(objc_delegate)
};
let view = allocate_webview(config, Some(&objc_delegate));
let mut view = WebView {
internal_callback_ptr: Some(internal_callback_ptr),
delegate: None,
objc_delegate: Some(objc_delegate),
top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }),
@ -180,11 +170,7 @@ impl<T> WebView<T> where T: WebViewDelegate + '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
}
@ -197,7 +183,6 @@ impl<T> WebView<T> {
/// delegate - the `View` is the only true holder of those.
pub(crate) fn clone_as_handle(&self) -> WebView {
WebView {
internal_callback_ptr: None,
delegate: None,
top: self.top.clone(),
leading: self.leading.clone(),
@ -245,14 +230,11 @@ impl<T> std::fmt::Debug for WebView<T> {
impl<T> Drop for WebView<T> {
/// A bit of extra cleanup for delegate callback pointers.
fn drop(&mut self) {
/*println!("... {}", self.delegate.is_some());
if let Some(delegate) = &self.delegate {
println!("Strong count: {}", Rc::strong_count(&delegate));
if Rc::strong_count(&delegate) == 1 {
let _ = unsafe {
Rc::from_raw(self.internal_callback_ptr.unwrap())
};
if self.delegate.is_some() {
unsafe {
let _: () = msg_send![&*self.objc, setNavigationDelegate:nil];
let _: () = msg_send![&*self.objc, setUIDelegate:nil];
}
}*/
}
}
}

View file

@ -11,7 +11,7 @@ pub trait WebViewDelegate {
/// 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, _webview: WebView) {}
fn did_load(&self, _webview: WebView) {}
/// Called when this is about to be added to the view heirarchy.
fn will_appear(&self) {}