Skip to content

Commit 5399823

Browse files
authored
feat(linux): craete webview on new_window_req (#1600)
follow-up for #1596 ref tauri-apps/tauri#13876
1 parent af1cc13 commit 5399823

File tree

4 files changed

+134
-63
lines changed

4 files changed

+134
-63
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wry": patch
3+
---
4+
5+
Fixes `new_window_req_handler` not creating the webview on Linux when executing `window.open()`.

src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,6 +1709,7 @@ impl WebViewBuilderExtAndroid for WebViewBuilder<'_> {
17091709
#[derive(Default)]
17101710
pub(crate) struct PlatformSpecificWebViewAttributes {
17111711
extension_path: Option<PathBuf>,
1712+
related_view: Option<webkit2gtk::WebView>,
17121713
}
17131714

17141715
#[cfg(any(
@@ -1735,6 +1736,9 @@ pub trait WebViewBuilderExtUnix<'a> {
17351736

17361737
/// Set the path from which to load extensions from.
17371738
fn with_extensions_path(self, path: impl Into<PathBuf>) -> Self;
1739+
1740+
/// Creates a new webview sharing the same web process with the provided webview.
1741+
fn with_related_view(self, webview: webkit2gtk::WebView) -> Self;
17381742
}
17391743

17401744
#[cfg(any(
@@ -1759,6 +1763,11 @@ impl<'a> WebViewBuilderExtUnix<'a> for WebViewBuilder<'a> {
17591763
self.platform_specific.extension_path = Some(path.into());
17601764
self
17611765
}
1766+
1767+
fn with_related_view(mut self, webview: webkit2gtk::WebView) -> Self {
1768+
self.platform_specific.related_view.replace(webview);
1769+
self
1770+
}
17621771
}
17631772

17641773
/// The fundamental type to present a [`WebView`].

src/webkitgtk/mod.rs

Lines changed: 119 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ use raw_window_handle::RawWindowHandle;
2727
use std::ffi::c_ulong;
2828
#[cfg(any(debug_assertions, feature = "devtools"))]
2929
use std::sync::atomic::{AtomicBool, Ordering};
30-
use std::sync::{Arc, Mutex};
30+
use std::{
31+
collections::HashMap,
32+
rc::Rc,
33+
sync::{Arc, Mutex},
34+
};
3135
#[cfg(any(debug_assertions, feature = "devtools"))]
3236
use webkit2gtk::WebInspectorExt;
3337
use webkit2gtk::{
@@ -275,11 +279,11 @@ impl InnerWebView {
275279
}
276280

277281
// Extension loading
278-
if let Some(extension_path) = pl_attrs.extension_path {
279-
web_context.os.set_web_extensions_directory(&extension_path);
282+
if let Some(extension_path) = &pl_attrs.extension_path {
283+
web_context.os.set_web_extensions_directory(extension_path);
280284
}
281285

282-
let webview = Self::create_webview(web_context, &attributes);
286+
let webview = Self::create_webview(web_context, &attributes, &pl_attrs);
283287

284288
// Transparent
285289
if attributes.transparent {
@@ -379,10 +383,13 @@ impl InnerWebView {
379383
Ok(w)
380384
}
381385

382-
fn create_webview(web_context: &WebContext, attributes: &WebViewAttributes) -> WebView {
386+
fn create_webview(
387+
web_context: &WebContext,
388+
attributes: &WebViewAttributes,
389+
pl_attrs: &super::PlatformSpecificWebViewAttributes,
390+
) -> WebView {
383391
let mut builder = WebView::builder()
384392
.user_content_manager(&UserContentManager::new())
385-
.web_context(web_context.context())
386393
.is_controlled_by_automation(web_context.allows_automation());
387394

388395
if attributes.autoplay {
@@ -393,6 +400,12 @@ impl InnerWebView {
393400
);
394401
}
395402

403+
if let Some(related_view) = &pl_attrs.related_view {
404+
builder = builder.related_view(related_view);
405+
} else {
406+
builder = builder.web_context(web_context.context());
407+
}
408+
396409
builder.build()
397410
}
398411

@@ -468,35 +481,79 @@ impl InnerWebView {
468481
});
469482
}
470483

471-
// Navigation handler && New window handler
472-
if attributes.navigation_handler.is_some() || attributes.new_window_req_handler.is_some() {
473-
let new_window_req_handler = attributes.new_window_req_handler.take();
474-
let navigation_handler = attributes.navigation_handler.take();
484+
// window creation handler
485+
if let Some(new_window_req_handler) = attributes.new_window_req_handler.take() {
486+
let related_webviews = Rc::new(Mutex::new(HashMap::new()));
487+
webview.connect_create(move |webview, action| {
488+
let url = action
489+
.request()
490+
.and_then(|request| request.uri())
491+
.map(|uri| uri.as_str().to_string())?;
492+
if new_window_req_handler(url.clone()) {
493+
let related_webviews = related_webviews.clone();
494+
let toplevel = webview.toplevel().unwrap();
495+
let window = toplevel.downcast::<gtk::ApplicationWindow>().unwrap();
496+
let id = window.id();
497+
let app = window.application().unwrap();
498+
499+
let window = gtk::ApplicationWindow::builder()
500+
.application(&app)
501+
.title(&url)
502+
.build();
503+
let box_ = gtk::Box::new(gtk::Orientation::Vertical, 0);
504+
window.add(&box_);
505+
506+
let related_webviews_ = related_webviews.clone();
507+
window.connect_destroy(move |_| {
508+
related_webviews_.lock().unwrap().remove(&id);
509+
});
475510

511+
window.show_all();
512+
Self::new_gtk(
513+
&box_,
514+
WebViewAttributes {
515+
..Default::default()
516+
},
517+
super::PlatformSpecificWebViewAttributes {
518+
related_view: Some(webview.clone()),
519+
..Default::default()
520+
},
521+
)
522+
.map(|webview| {
523+
let widget = webview.webview.upcast_ref::<gtk::Widget>().clone();
524+
related_webviews.lock().unwrap().insert(id, webview);
525+
widget
526+
})
527+
.ok()
528+
} else {
529+
None
530+
}
531+
});
532+
}
533+
534+
// Navigation handler
535+
if let Some(navigation_handler) = attributes.navigation_handler.take() {
476536
webview.connect_decide_policy(move |_webview, policy_decision, policy_type| {
477537
let handler = match policy_type {
478538
PolicyDecisionType::NavigationAction => &navigation_handler,
479-
PolicyDecisionType::NewWindowAction => &new_window_req_handler,
480539
_ => return false,
481540
};
482541

483-
if let Some(handler) = handler {
484-
if let Some(policy) = policy_decision.dynamic_cast_ref::<NavigationPolicyDecision>() {
485-
if let Some(nav_action) = policy.navigation_action() {
486-
if let Some(uri_req) = nav_action.request() {
487-
if let Some(uri) = uri_req.uri() {
488-
let allow = handler(uri.to_string());
489-
let pointer = policy_decision.as_ptr();
490-
unsafe {
491-
if allow {
492-
webkit_policy_decision_use(pointer)
493-
} else {
494-
webkit_policy_decision_ignore(pointer)
495-
}
542+
if let Some(policy) = policy_decision.dynamic_cast_ref::<NavigationPolicyDecision>() {
543+
if let Some(nav_action) = policy.navigation_action() {
544+
if let Some(uri_req) = nav_action.request() {
545+
if let Some(uri) = uri_req.uri() {
546+
let allow = handler(uri.to_string());
547+
let pointer = policy_decision.as_ptr();
548+
unsafe {
549+
if allow {
550+
webkit_policy_decision_use(pointer)
551+
} else {
552+
webkit_policy_decision_ignore(pointer)
496553
}
497-
498-
return true;
499554
}
555+
556+
return true;
500557
}
501558
}
502559
}
@@ -936,21 +993,21 @@ impl InnerWebView {
936993

937994
pub fn cookies_for_url(&self, url: &str) -> Result<Vec<cookie::Cookie<'static>>> {
938995
let (tx, rx) = std::sync::mpsc::channel();
939-
self
996+
if let Some(cookies_manager) = self
940997
.webview
941998
.website_data_manager()
942999
.and_then(|manager| manager.cookie_manager())
943-
.map(|cookies_manager| {
944-
cookies_manager.cookies(url, None::<&Cancellable>, move |cookies| {
945-
let cookies = cookies.map(|cookies| {
946-
cookies
947-
.into_iter()
948-
.map(Self::cookie_from_soup_cookie)
949-
.collect()
950-
});
951-
let _ = tx.send(cookies);
952-
})
953-
});
1000+
{
1001+
cookies_manager.cookies(url, None::<&Cancellable>, move |cookies| {
1002+
let cookies = cookies.map(|cookies| {
1003+
cookies
1004+
.into_iter()
1005+
.map(Self::cookie_from_soup_cookie)
1006+
.collect()
1007+
});
1008+
let _ = tx.send(cookies);
1009+
})
1010+
}
9541011

9551012
loop {
9561013
gtk::main_iteration();
@@ -963,21 +1020,21 @@ impl InnerWebView {
9631020

9641021
pub fn cookies(&self) -> Result<Vec<cookie::Cookie<'static>>> {
9651022
let (tx, rx) = std::sync::mpsc::channel();
966-
self
1023+
if let Some(cookies_manager) = self
9671024
.webview
9681025
.website_data_manager()
9691026
.and_then(|manager| manager.cookie_manager())
970-
.map(|cookies_manager| {
971-
cookies_manager.all_cookies(None::<&Cancellable>, move |cookies| {
972-
let cookies = cookies.map(|cookies| {
973-
cookies
974-
.into_iter()
975-
.map(Self::cookie_from_soup_cookie)
976-
.collect()
977-
});
978-
let _ = tx.send(cookies);
979-
})
980-
});
1027+
{
1028+
cookies_manager.all_cookies(None::<&Cancellable>, move |cookies| {
1029+
let cookies = cookies.map(|cookies| {
1030+
cookies
1031+
.into_iter()
1032+
.map(Self::cookie_from_soup_cookie)
1033+
.collect()
1034+
});
1035+
let _ = tx.send(cookies);
1036+
})
1037+
}
9811038

9821039
loop {
9831040
gtk::main_iteration();
@@ -990,16 +1047,16 @@ impl InnerWebView {
9901047

9911048
pub fn set_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
9921049
let (tx, rx) = std::sync::mpsc::channel();
993-
self
1050+
if let Some(cookies_manager) = self
9941051
.webview
9951052
.website_data_manager()
9961053
.and_then(|manager| manager.cookie_manager())
997-
.map(|cookies_manager| {
998-
let mut soup_cookie = Self::cookie_into_soup_cookie(cookie);
999-
cookies_manager.add_cookie(&mut soup_cookie, None::<&Cancellable>, move |ret| {
1000-
let _ = tx.send(ret);
1001-
});
1054+
{
1055+
let mut soup_cookie = Self::cookie_into_soup_cookie(cookie);
1056+
cookies_manager.add_cookie(&mut soup_cookie, None::<&Cancellable>, move |ret| {
1057+
let _ = tx.send(ret);
10021058
});
1059+
}
10031060

10041061
loop {
10051062
gtk::main_iteration();
@@ -1012,16 +1069,16 @@ impl InnerWebView {
10121069

10131070
pub fn delete_cookie(&self, cookie: &cookie::Cookie<'_>) -> Result<()> {
10141071
let (tx, rx) = std::sync::mpsc::channel();
1015-
self
1072+
if let Some(cookies_manager) = self
10161073
.webview
10171074
.website_data_manager()
10181075
.and_then(|manager| manager.cookie_manager())
1019-
.map(|cookies_manager| {
1020-
let mut soup_cookie = Self::cookie_into_soup_cookie(cookie);
1021-
cookies_manager.delete_cookie(&mut soup_cookie, None::<&Cancellable>, move |ret| {
1022-
let _ = tx.send(ret);
1023-
});
1076+
{
1077+
let mut soup_cookie = Self::cookie_into_soup_cookie(cookie);
1078+
cookies_manager.delete_cookie(&mut soup_cookie, None::<&Cancellable>, move |ret| {
1079+
let _ = tx.send(ret);
10241080
});
1081+
}
10251082

10261083
loop {
10271084
gtk::main_iteration();

src/webkitgtk/web_context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ impl WebContextExt for super::WebContext {
144144
where
145145
F: Fn(crate::WebViewId, Request<Vec<u8>>, RequestAsyncResponder) + 'static,
146146
{
147-
self.register_custom_protocol(name.to_owned());
147+
self.register_custom_protocol(name.to_owned())?;
148148

149149
// Enable secure context
150150
self

0 commit comments

Comments
 (0)