Webview patches
This commit is contained in:
parent
ad54670ffd
commit
ccaf61f56f
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {}
|
||||
|
|
Loading…
Reference in a new issue