Webview patches
This commit is contained in:
parent
ad54670ffd
commit
ccaf61f56f
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::sync::Once;
|
use std::sync::Once;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use block::Block;
|
use block::Block;
|
||||||
|
|
||||||
|
@ -50,11 +49,8 @@ extern fn on_message<T: WebViewDelegate>(this: &Object, _: Sel, _: id, script_me
|
||||||
unsafe {
|
unsafe {
|
||||||
let name = NSString::wrap(msg_send![script_message, name]).to_str();
|
let name = NSString::wrap(msg_send![script_message, name]).to_str();
|
||||||
let body = NSString::wrap(msg_send![script_message, body]).to_str();
|
let body = NSString::wrap(msg_send![script_message, body]).to_str();
|
||||||
let d = delegate.borrow();
|
delegate.on_message(name, body);
|
||||||
(*d).on_message(name, body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rc::into_raw(delegate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fires when deciding a navigation policy - i.e, should something be allowed or not.
|
/// 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 action = NavigationAction::new(action);
|
||||||
|
|
||||||
{
|
delegate.policy_for_navigation_action(action, |policy| unsafe {
|
||||||
let d = delegate.borrow();
|
let handler = handler as *const Block<(NSInteger,), c_void>;
|
||||||
|
(*handler).call((policy.into(),));
|
||||||
(*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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fires when deciding a navigation policy - i.e, should something be allowed or not.
|
/// 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 response = NavigationResponse::new(response);
|
||||||
|
|
||||||
{
|
delegate.policy_for_navigation_response(response, |policy| unsafe {
|
||||||
let d = delegate.borrow();
|
let handler = handler as *const Block<(NSInteger,), c_void>;
|
||||||
|
(*handler).call((policy.into(),));
|
||||||
(*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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fires when deciding a navigation policy - i.e, should something be allowed or not.
|
/// 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) {
|
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 delegate = load::<T>(this, WEBVIEW_DELEGATE_PTR);
|
||||||
|
|
||||||
{
|
delegate.run_open_panel(params.into(), move |urls| unsafe {
|
||||||
let d = delegate.borrow();
|
let handler = handler as *const Block<(id,), c_void>;
|
||||||
|
|
||||||
(*d).run_open_panel(params.into(), move |urls| unsafe {
|
match urls {
|
||||||
let handler = handler as *const Block<(id,), c_void>;
|
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 {
|
(*handler).call((nsurls.into_inner(),));
|
||||||
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(),));
|
None => { (*handler).call((nil,)); }
|
||||||
},
|
}
|
||||||
|
});
|
||||||
None => { (*handler).call((nil,)); }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Rc::into_raw(delegate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when a download has been initiated in the WebView, and when the navigation policy
|
/// 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 handler = handler as *const Block<(objc::runtime::BOOL, id), c_void>;
|
||||||
let filename = NSString::wrap(suggested_filename).to_str();
|
let filename = NSString::wrap(suggested_filename).to_str();
|
||||||
|
|
||||||
{
|
delegate.run_save_panel(filename, move |can_overwrite, path| unsafe {
|
||||||
let d = delegate.borrow();
|
if path.is_none() {
|
||||||
|
let _: () = msg_send![download, cancel];
|
||||||
|
}
|
||||||
|
|
||||||
(*d).run_save_panel(filename, move |can_overwrite, path| unsafe {
|
let path = NSString::new(&path.unwrap());
|
||||||
if path.is_none() {
|
|
||||||
let _: () = msg_send![download, cancel];
|
(*handler).call((match can_overwrite {
|
||||||
}
|
true => YES,
|
||||||
|
false => NO
|
||||||
let path = NSString::new(&path.unwrap());
|
}, path.into_inner()));
|
||||||
|
});
|
||||||
(*handler).call((match can_overwrite {
|
|
||||||
true => YES,
|
|
||||||
false => NO
|
|
||||||
}, path.into_inner()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Rc::into_raw(delegate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers an `NSViewController` that we effectively turn into a `WebViewController`. Acts as
|
/// 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
|
//! Apple does not ship `WKWebView` on tvOS, and as a result this control is not provided on that
|
||||||
//! platform.
|
//! platform.
|
||||||
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
use core_graphics::geometry::CGRect;
|
use core_graphics::geometry::CGRect;
|
||||||
|
|
||||||
use objc_id::ShareId;
|
use objc_id::ShareId;
|
||||||
use objc::runtime::Object;
|
use objc::runtime::Object;
|
||||||
use objc::{class, msg_send, sel, sel_impl};
|
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::geometry::Rect;
|
||||||
use crate::layout::{Layout, LayoutAnchorX, LayoutAnchorY, LayoutAnchorDimension};
|
use crate::layout::{Layout, LayoutAnchorX, LayoutAnchorY, LayoutAnchorDimension};
|
||||||
|
|
||||||
pub mod actions;
|
mod actions;
|
||||||
pub mod enums;
|
pub use actions::*;
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
pub use config::WebViewConfig;
|
||||||
|
|
||||||
|
mod enums;
|
||||||
|
pub use enums::*;
|
||||||
|
|
||||||
pub(crate) mod class;
|
pub(crate) mod class;
|
||||||
use class::{register_webview_class, register_webview_delegate_class};
|
use class::{register_webview_class, register_webview_delegate_class};
|
||||||
//pub(crate) mod process_pool;
|
//pub(crate) mod process_pool;
|
||||||
|
|
||||||
pub mod traits;
|
mod traits;
|
||||||
pub use traits::WebViewDelegate;
|
pub use traits::WebViewDelegate;
|
||||||
|
|
||||||
pub mod config;
|
|
||||||
pub use config::WebViewConfig;
|
|
||||||
|
|
||||||
pub(crate) static WEBVIEW_DELEGATE_PTR: &str = "rstWebViewDelegatePtr";
|
pub(crate) static WEBVIEW_DELEGATE_PTR: &str = "rstWebViewDelegatePtr";
|
||||||
|
|
||||||
fn allocate_webview(
|
fn allocate_webview(
|
||||||
|
@ -87,12 +87,8 @@ pub struct WebView<T = ()> {
|
||||||
/// we do so.
|
/// we do so.
|
||||||
pub objc_delegate: Option<ShareId<Object>>,
|
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.
|
/// 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.
|
/// A pointer to the Objective-C runtime top layout constraint.
|
||||||
pub top: LayoutAnchorY,
|
pub top: LayoutAnchorY,
|
||||||
|
@ -130,7 +126,6 @@ impl WebView {
|
||||||
let view = allocate_webview(config, None);
|
let view = allocate_webview(config, None);
|
||||||
|
|
||||||
WebView {
|
WebView {
|
||||||
internal_callback_ptr: None,
|
|
||||||
delegate: None,
|
delegate: None,
|
||||||
objc_delegate: None,
|
objc_delegate: None,
|
||||||
top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }),
|
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
|
/// 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.
|
/// and customize the view as a module, similar to class-based systems.
|
||||||
pub fn with(config: WebViewConfig, delegate: T) -> WebView<T> {
|
pub fn with(config: WebViewConfig, delegate: T) -> WebView<T> {
|
||||||
let delegate = Rc::new(RefCell::new(delegate));
|
let delegate = Box::new(delegate);
|
||||||
|
|
||||||
let internal_callback_ptr = {
|
|
||||||
let cloned = Rc::clone(&delegate);
|
|
||||||
Rc::into_raw(cloned)
|
|
||||||
};
|
|
||||||
|
|
||||||
let objc_delegate = unsafe {
|
let objc_delegate = unsafe {
|
||||||
let objc_delegate: id = msg_send![register_webview_delegate_class::<T>(), new];
|
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)
|
ShareId::from_ptr(objc_delegate)
|
||||||
};
|
};
|
||||||
|
|
||||||
let view = allocate_webview(config, Some(&objc_delegate));
|
let view = allocate_webview(config, Some(&objc_delegate));
|
||||||
|
|
||||||
let mut view = WebView {
|
let mut view = WebView {
|
||||||
internal_callback_ptr: Some(internal_callback_ptr),
|
|
||||||
delegate: None,
|
delegate: None,
|
||||||
objc_delegate: Some(objc_delegate),
|
objc_delegate: Some(objc_delegate),
|
||||||
top: LayoutAnchorY::new(unsafe { msg_send![view, topAnchor] }),
|
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) },
|
objc: unsafe { ShareId::from_ptr(view) },
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
&delegate.did_load(view.clone_as_handle());
|
||||||
let mut delegate = delegate.borrow_mut();
|
|
||||||
(*delegate).did_load(view.clone_as_handle());
|
|
||||||
}
|
|
||||||
|
|
||||||
view.delegate = Some(delegate);
|
view.delegate = Some(delegate);
|
||||||
view
|
view
|
||||||
}
|
}
|
||||||
|
@ -197,7 +183,6 @@ impl<T> WebView<T> {
|
||||||
/// delegate - the `View` is the only true holder of those.
|
/// delegate - the `View` is the only true holder of those.
|
||||||
pub(crate) fn clone_as_handle(&self) -> WebView {
|
pub(crate) fn clone_as_handle(&self) -> WebView {
|
||||||
WebView {
|
WebView {
|
||||||
internal_callback_ptr: None,
|
|
||||||
delegate: None,
|
delegate: None,
|
||||||
top: self.top.clone(),
|
top: self.top.clone(),
|
||||||
leading: self.leading.clone(),
|
leading: self.leading.clone(),
|
||||||
|
@ -245,14 +230,11 @@ impl<T> std::fmt::Debug for WebView<T> {
|
||||||
impl<T> Drop for WebView<T> {
|
impl<T> Drop for WebView<T> {
|
||||||
/// A bit of extra cleanup for delegate callback pointers.
|
/// A bit of extra cleanup for delegate callback pointers.
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
/*println!("... {}", self.delegate.is_some());
|
if self.delegate.is_some() {
|
||||||
if let Some(delegate) = &self.delegate {
|
unsafe {
|
||||||
println!("Strong count: {}", Rc::strong_count(&delegate));
|
let _: () = msg_send![&*self.objc, setNavigationDelegate:nil];
|
||||||
if Rc::strong_count(&delegate) == 1 {
|
let _: () = msg_send![&*self.objc, setUIDelegate:nil];
|
||||||
let _ = unsafe {
|
|
||||||
Rc::from_raw(self.internal_callback_ptr.unwrap())
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
/// 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
|
/// store and use repeatedly, but it's not thread safe - any UI calls must be made from the
|
||||||
/// main thread!
|
/// 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.
|
/// Called when this is about to be added to the view heirarchy.
|
||||||
fn will_appear(&self) {}
|
fn will_appear(&self) {}
|
||||||
|
|
Loading…
Reference in a new issue