Skip to content

Commit

Permalink
fix: #160 drop handler closures properly (#211)
Browse files Browse the repository at this point in the history
* Update multiwindow example

* Drop handler closuers properly

* Add change file

* Remove unused import

* Make clippy happy
  • Loading branch information
Ngo Iok Ui (Wu Yu Wei) authored Apr 27, 2021
1 parent 35d82f9 commit f905503
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 31 deletions.
5 changes: 5 additions & 0 deletions .changes/drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wry": minor
---

Drop handler closures properly on macOS.
56 changes: 36 additions & 20 deletions examples/multi_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::time::{Duration, Instant};
use std::{
collections::HashMap,
time::{Duration, Instant},
};

#[derive(Debug, Serialize, Deserialize)]
struct MessageParameters {
Expand All @@ -23,7 +26,7 @@ fn main() -> wry::Result<()> {
};

let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
let window1 = WindowBuilder::new().build(&event_loop).unwrap();

let (window_tx, window_rx) = std::sync::mpsc::channel::<String>();
let handler = move |_window: &Window, req: RpcRequest| {
Expand All @@ -37,7 +40,8 @@ fn main() -> wry::Result<()> {
None
};

let mut webview = WebViewBuilder::new(window)
let id = window1.id();
let webview1 = WebViewBuilder::new(window1)
.unwrap()
.with_url("https://tauri.studio")?
.with_initialization_script(
Expand All @@ -47,39 +51,51 @@ fn main() -> wry::Result<()> {
)
.with_rpc_handler(handler)
.build()?;
let mut webviews = HashMap::new();
webviews.insert(id, webview1);

let instant = Instant::now();
let eight_secs = Duration::from_secs(8);
let mut trigger = true;
let mut _new_webview = None;
event_loop.run(move |event, event_loop, control_flow| {
*control_flow = ControlFlow::Poll;

if let Ok(url) = window_rx.try_recv() {
let new_window = WindowBuilder::new()
let window2 = WindowBuilder::new()
.with_title("RODA RORA DA")
.with_inner_size(PhysicalSize::new(426, 197))
.build(&event_loop)
.unwrap();
_new_webview = Some(
WebViewBuilder::new(new_window)
.unwrap()
.with_url(&url)
.unwrap()
.build()
.unwrap(),
);
let id = window2.id();
let webview2 = WebViewBuilder::new(window2)
.unwrap()
.with_url(&url)
.unwrap()
.build()
.unwrap();
webviews.insert(id, webview2);
} else if trigger && instant.elapsed() >= eight_secs {
webview.dispatch_script("openWindow()").unwrap();
webviews
.get_mut(&id)
.unwrap()
.dispatch_script("openWindow()")
.unwrap();
trigger = false;
}

match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => *control_flow = ControlFlow::Exit,
_ => webview.evaluate_script().unwrap(),
for webview in webviews.values() {
webview.evaluate_script().unwrap();
}

if let Event::WindowEvent {
window_id,
event: WindowEvent::CloseRequested,
} = event
{
webviews.remove(&window_id);
if webviews.is_empty() {
*control_flow = ControlFlow::Exit;
}
}
});
}
3 changes: 2 additions & 1 deletion src/webview/macos/file_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ pub(crate) unsafe fn set_file_drop_handler(
webview: *mut Object,
window: Rc<Window>,
handler: Box<dyn Fn(&Window, FileDropEvent) -> bool>,
) {
) -> *mut (Box<dyn Fn(&Window, FileDropEvent) -> bool>, Rc<Window>) {
let listener = Box::into_raw(Box::new((handler, window)));
(*webview).set_ivar("FileDropHandler", listener as *mut _ as *mut c_void);
listener
}

#[allow(clippy::mut_from_ref)]
Expand Down
54 changes: 44 additions & 10 deletions src/webview/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{
ffi::{c_void, CStr},
os::raw::c_char,
path::PathBuf,
ptr::null,
ptr::{null, null_mut},
rc::Rc,
slice, str,
};
Expand Down Expand Up @@ -36,6 +36,12 @@ mod file_drop;
pub struct InnerWebView {
webview: Id<Object>,
manager: id,
rpc_handler_ptr: *mut (
Box<dyn Fn(&Window, RpcRequest) -> Option<RpcResponse>>,
Rc<Window>,
),
file_drop_ptr: *mut (Box<dyn Fn(&Window, FileDropEvent) -> bool>, Rc<Window>),
protocol_ptrs: Vec<*mut (Box<dyn Fn(&Window, &str) -> Result<Vec<u8>>>, Rc<Window>)>,
}

impl InnerWebView {
Expand Down Expand Up @@ -126,6 +132,7 @@ impl InnerWebView {
unsafe {
// Config and custom protocol
let config: id = msg_send![class!(WKWebViewConfiguration), new];
let mut protocol_ptrs = Vec::new();
for (name, function) in custom_protocols {
let scheme_name = format!("{}URLSchemeHandler", name);
let cls = ClassDecl::new(&scheme_name, class!(NSObject));
Expand All @@ -146,10 +153,10 @@ impl InnerWebView {
};
let handler: id = msg_send![cls, new];
let w = window.clone();
let function: Box<(Box<dyn Fn(&Window, &str) -> Result<Vec<u8>>>, Rc<Window>)> =
Box::new((Box::new(function), w));
let function = Box::into_raw(Box::new((function, w)));
protocol_ptrs.push(function);

(*handler).set_ivar("function", Box::into_raw(function) as *mut _ as *mut c_void);
(*handler).set_ivar("function", function as *mut _ as *mut c_void);
let () = msg_send![config, setURLSchemeHandler:handler forURLScheme:NSString::new(&name)];
}

Expand Down Expand Up @@ -190,7 +197,7 @@ impl InnerWebView {
webview.setAutoresizingMask_(NSViewHeightSizable | NSViewWidthSizable);

// Message handler
if let Some(rpc_handler) = rpc_handler {
let rpc_handler_ptr = if let Some(rpc_handler) = rpc_handler {
let cls = ClassDecl::new("WebViewDelegate", class!(NSObject));
let cls = match cls {
Some(mut cls) => {
Expand All @@ -204,26 +211,32 @@ impl InnerWebView {
None => class!(WebViewDelegate),
};
let handler: id = msg_send![cls, new];
let function = Box::new((rpc_handler, window.clone()));
let rpc_handler_ptr = Box::into_raw(Box::new((rpc_handler, window.clone())));

(*handler).set_ivar("function", Box::into_raw(function) as *mut _ as *mut c_void);
(*handler).set_ivar("function", rpc_handler_ptr as *mut _ as *mut c_void);
let external = NSString::new("external");
let _: () = msg_send![manager, addScriptMessageHandler:handler name:external];
}
rpc_handler_ptr
} else {
null_mut()
};

// File drop handling
match file_drop_handler {
let file_drop_ptr = match file_drop_handler {
// if we have a file_drop_handler defined, use the defined handler
Some(file_drop_handler) => {
set_file_drop_handler(webview, window.clone(), file_drop_handler)
}
// prevent panic by using a blank handler
None => set_file_drop_handler(webview, window.clone(), Box::new(|_, _| false)),
}
};

let w = Self {
webview: Id::from_ptr(webview),
manager,
rpc_handler_ptr,
file_drop_ptr,
protocol_ptrs,
};

// Initialize scripts
Expand Down Expand Up @@ -321,6 +334,27 @@ impl InnerWebView {
}
}

impl Drop for InnerWebView {
fn drop(&mut self) {
// We need to drop handler closures here
unsafe {
if !self.rpc_handler_ptr.is_null() {
let _ = Box::from_raw(self.rpc_handler_ptr);
}

if !self.file_drop_ptr.is_null() {
let _ = Box::from_raw(self.file_drop_ptr);
}

for ptr in self.protocol_ptrs.iter() {
if !ptr.is_null() {
let _ = Box::from_raw(*ptr);
}
}
}
}
}

const UTF8_ENCODING: usize = 4;

struct NSString(Id<Object>);
Expand Down

0 comments on commit f905503

Please sign in to comment.