From 98fdc7c5fa4b28bf083658e70bb9d81ec320c3b6 Mon Sep 17 00:00:00 2001 From: Lucas Nogueira Date: Mon, 26 Jan 2026 09:54:45 -0300 Subject: [PATCH] new window opener --- crates/tauri-runtime-cef/src/cef_impl.rs | 94 +++++++++++++++++- crates/tauri-runtime-cef/src/lib.rs | 4 + crates/tauri-runtime-wry/src/lib.rs | 104 ++++++++++++++++++-- crates/tauri-runtime/src/lib.rs | 2 + crates/tauri-runtime/src/webview.rs | 91 ++++-------------- crates/tauri/src/webview/mod.rs | 97 +++++++++++++------ crates/tauri/src/webview/webview_window.rs | 106 +++++++++------------ 7 files changed, 321 insertions(+), 177 deletions(-) diff --git a/crates/tauri-runtime-cef/src/cef_impl.rs b/crates/tauri-runtime-cef/src/cef_impl.rs index 9c28a077a..fb4d77f7d 100644 --- a/crates/tauri-runtime-cef/src/cef_impl.rs +++ b/crates/tauri-runtime-cef/src/cef_impl.rs @@ -608,6 +608,7 @@ wrap_life_span_handler! { window_kind: WindowKind, window_id: WindowId, context: Context, + new_window_handler: Option>>>, } impl LifeSpanHandler { @@ -616,6 +617,81 @@ wrap_life_span_handler! { on_window_destroyed(self.window_id, &self.context.windows, &self.context.callback); } } + + fn on_before_popup( + &self, + _browser: Option<&mut Browser>, + _frame: Option<&mut Frame>, + _popup_id: std::os::raw::c_int, + target_url: Option<&CefString>, + _target_frame_name: Option<&CefString>, + _target_disposition: WindowOpenDisposition, + _user_gesture: std::os::raw::c_int, + popup_features: Option<&PopupFeatures>, + _window_info: Option<&mut WindowInfo>, + _client: Option<&mut Option>, + _settings: Option<&mut BrowserSettings>, + _extra_info: Option<&mut Option>, + _no_javascript_access: Option<&mut i32>, + ) -> std::os::raw::c_int { + let Some(handler) = &self.new_window_handler else { + // No handler, allow default behavior + return 0; + }; + + let Some(target_url) = target_url else { + // No URL, deny + return 1; + }; + + let url_str = target_url.to_string(); + let Ok(url) = url::Url::parse(&url_str) else { + // Invalid URL, deny + return 1; + }; + + // Extract size and position from popup_features + // Note: PopupFeatures fields may vary by CEF version, so we handle them defensively + let size = popup_features.and_then(|_features| { + // Try to access width/height fields - structure may vary + // For now, we'll use None if we can't determine the size + None // TODO: Implement proper PopupFeatures field access when CEF API is available + }); + + let position = popup_features.and_then(|_features| { + // Try to access x/y fields - structure may vary + // For now, we'll use None if we can't determine the position + None // TODO: Implement proper PopupFeatures field access when CEF API is available + }); + + let features = tauri_runtime::webview::NewWindowFeatures::new( + size, + position, + crate::NewWindowOpener {}, + ); + + let response = handler(url, features); + + match response { + tauri_runtime::webview::NewWindowResponse::Allow => { + // Allow CEF to handle the popup with default behavior + 0 + } + tauri_runtime::webview::NewWindowResponse::Create { window_id: _window_id } => { + // We need to create a window and associate it with the popup + // For now, we'll deny the popup and let the handler create the window + // The window creation should happen via the message system + // This is a limitation - CEF doesn't easily support creating a window + // and associating it with a popup in the callback + // We return 1 to cancel the popup, and the handler should create the window + 1 + } + tauri_runtime::webview::NewWindowResponse::Deny => { + // Deny the popup + 1 + } + } + } } } @@ -627,6 +703,7 @@ wrap_client! { on_page_load_handler: Option>, document_title_changed_handler: Option>, navigation_handler: Option>, + new_window_handler: Option>>>, download_handler: Option>, devtools_enabled: bool, custom_scheme_domain_names: Vec, @@ -643,7 +720,12 @@ wrap_client! { } fn life_span_handler(&self) -> Option { - Some(BrowserLifeSpanHandler::new(self.window_kind, self.window_id, self.context.clone())) + Some(BrowserLifeSpanHandler::new( + self.window_kind, + self.window_id, + self.context.clone(), + self.new_window_handler.clone(), + )) } fn load_handler(&self) -> Option { @@ -2459,12 +2541,13 @@ fn create_browser_window( ) { let PendingWebview { label: webview_label, + opener: _, mut webview_attributes, platform_specific_attributes: _, uri_scheme_protocols, ipc_handler: _, navigation_handler, - new_window_handler: _, + new_window_handler, document_title_changed_handler, url, web_resource_request_handler: _, @@ -2481,6 +2564,7 @@ fn create_browser_window( let on_page_load_handler = on_page_load_handler.take().map(Arc::from); let document_title_changed_handler = document_title_changed_handler.map(Arc::from); let navigation_handler = navigation_handler.map(Arc::from); + let new_window_handler = new_window_handler.map(Arc::from); let devtools_enabled = (cfg!(debug_assertions) || cfg!(feature = "devtools")) && webview_attributes.devtools.unwrap_or(true); @@ -2528,6 +2612,7 @@ fn create_browser_window( on_page_load_handler, document_title_changed_handler, navigation_handler, + new_window_handler, download_handler, devtools_enabled, custom_scheme_domain_names.clone(), @@ -2795,12 +2880,13 @@ pub(crate) fn create_webview( ) { let PendingWebview { label, + opener: _, mut webview_attributes, platform_specific_attributes, uri_scheme_protocols, ipc_handler: _, navigation_handler, - new_window_handler: _, + new_window_handler, document_title_changed_handler, url, web_resource_request_handler: _, @@ -2830,6 +2916,7 @@ pub(crate) fn create_webview( let on_page_load_handler = on_page_load_handler.take().map(Arc::from); let document_title_changed_handler = document_title_changed_handler.map(Arc::from); let navigation_handler = navigation_handler.map(Arc::from); + let new_window_handler = new_window_handler.map(Arc::from); let devtools_enabled = (cfg!(debug_assertions) || cfg!(feature = "devtools")) && webview_attributes.devtools.unwrap_or(true); @@ -2853,6 +2940,7 @@ pub(crate) fn create_webview( on_page_load_handler, document_title_changed_handler, navigation_handler, + new_window_handler, download_handler, devtools_enabled, custom_scheme_domain_names.clone(), diff --git a/crates/tauri-runtime-cef/src/lib.rs b/crates/tauri-runtime-cef/src/lib.rs index db24f0a7a..6371d5a49 100644 --- a/crates/tauri-runtime-cef/src/lib.rs +++ b/crates/tauri-runtime-cef/src/lib.rs @@ -2017,6 +2017,9 @@ pub enum RuntimeStyle { Chrome, } +#[derive(Debug)] +pub struct NewWindowOpener {} + impl Runtime for CefRuntime { type WindowDispatcher = CefWindowDispatcher; type WebviewDispatcher = CefWebviewDispatcher; @@ -2024,6 +2027,7 @@ impl Runtime for CefRuntime { type EventLoopProxy = EventProxy; type PlatformSpecificWebviewAttribute = WebviewAtribute; type PlatformSpecificInitAttribute = RuntimeInitAttribute; + type WindowOpener = NewWindowOpener; fn new(args: RuntimeInitArgs) -> Result { Ok(Self::init(args)) diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 388d65783..5be76daaa 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -163,6 +163,69 @@ mod window; pub use webview::Webview; use window::WindowExt as _; +/// Information about the webview that initiated a new window request. +#[derive(Debug)] +pub struct NewWindowOpener { + /// The instance of the webview that initiated the new window request. + /// + /// This must be set as the related view of the new webview. + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", + ))] + pub webview: webkit2gtk::WebView, + /// The instance of the webview that initiated the new window request. + /// + /// The target webview environment **MUST** match the environment of the opener webview. + #[cfg(windows)] + pub webview: webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2, + #[cfg(windows)] + pub environment: webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Environment, + /// The instance of the webview that initiated the new window request. + #[cfg(target_os = "macos")] + pub webview: objc2::rc::Retained, + /// Configuration of the target webview. + /// + /// This **MUST** be used when creating the target webview. + #[cfg(target_os = "macos")] + pub target_configuration: objc2::rc::Retained, +} + +// opener is only used on the main thread +unsafe impl Send for NewWindowOpener {} +unsafe impl Sync for NewWindowOpener {} + +/// Platform-specific webview attributes. +pub enum WebviewAttribute { + /// Set the environment for the webview. + /// Useful if you need to share the same environment, for instance when using the [`PendingWebview::new_window_handler`]. + #[cfg(windows)] + Environment(webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Environment), + + /// Creates a new webview sharing the same web process with the provided webview. + /// Useful if you need to link a webview to another, for instance when using the [`PendingWebview::new_window_handler`]. + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", + ))] + RelatedView(webkit2gtk::WebView), + + /// Set the webview configuration. + /// Useful if you need to share the use a predefined webview configuration, for instance when using the [`PendingWebview::new_window_handler`]. + #[cfg(target_os = "macos")] + WebviewConfiguration(objc2::rc::Retained), +} + +// attribute is only used on the main thread +unsafe impl Send for WebviewAttribute {} +unsafe impl Sync for WebviewAttribute {} + #[derive(Debug)] pub struct WebContext { pub inner: WryWebContext, @@ -2850,8 +2913,9 @@ impl Runtime for Wry { type Handle = WryHandle; type EventLoopProxy = EventProxy; - type PlatformSpecificWebviewAttribute = (); + type PlatformSpecificWebviewAttribute = WebviewAttribute; type PlatformSpecificInitAttribute = (); + type WindowOpener = NewWindowOpener; fn new(args: RuntimeInitArgs<()>) -> Result { Self::init_with_builder(EventLoopBuilder::>::with_user_event(), args) @@ -4620,10 +4684,12 @@ You may have it installed on another user account, but it is not available for t #[allow(unused_mut)] let PendingWebview { webview_attributes, + platform_specific_attributes, uri_scheme_protocols, label, ipc_handler, url, + opener, .. } = pending; @@ -4672,7 +4738,15 @@ You may have it installed on another user account, but it is not available for t } #[cfg(target_os = "macos")] - if let Some(webview_configuration) = webview_attributes.webview_configuration { + if let Some(webview_configuration) = platform_specific_attributes + .iter() + .find_map(|attr| match attr { + WebviewAttribute::WebviewConfiguration(config) => Some(config), + #[allow(unreachable_patterns)] + _ => None, + }) + .or_else(|| opener.as_ref().map(|opener| &opener.target_configuration)) + { webview_builder = webview_builder.with_webview_configuration(webview_configuration); } @@ -4761,7 +4835,7 @@ You may have it installed on another user account, but it is not available for t tauri_runtime::webview::NewWindowFeatures::new( features.size, features.position, - tauri_runtime::webview::NewWindowOpener { + NewWindowOpener { #[cfg(desktop)] webview: features.opener.webview, #[cfg(windows)] @@ -4907,8 +4981,16 @@ You may have it installed on another user account, but it is not available for t webview_builder = webview_builder.with_additional_browser_args(&additional_browser_args); } - if let Some(environment) = webview_attributes.environment { - webview_builder = webview_builder.with_environment(environment); + if let Some(environment) = platform_specific_attributes + .iter() + .find_map(|attr| match attr { + WebviewAttribute::Environment(env) => Some(env), + #[allow(unreachable_patterns)] + _ => None, + }) + .or_else(|| opener.as_ref().map(|opener| &opener.environment)) + { + webview_builder = webview_builder.with_environment(environment.clone()); } webview_builder = webview_builder.with_theme(match window.theme() { @@ -4953,8 +5035,16 @@ You may have it installed on another user account, but it is not available for t target_os = "openbsd" ))] { - if let Some(related_view) = webview_attributes.related_view { - webview_builder = webview_builder.with_related_view(related_view); + if let Some(related_view) = platform_specific_attributes + .iter() + .find_map(|attr| match attr { + WebviewAttribute::RelatedView(view) => Some(view), + #[allow(unreachable_patterns)] + _ => None, + }) + .or_else(|| opener.as_ref().map(|opener| &opener.webview)) + { + webview_builder = webview_builder.with_related_view(related_view.clone()); } } diff --git a/crates/tauri-runtime/src/lib.rs b/crates/tauri-runtime/src/lib.rs index ecfac165c..e4bfcc17e 100644 --- a/crates/tauri-runtime/src/lib.rs +++ b/crates/tauri-runtime/src/lib.rs @@ -411,6 +411,8 @@ pub trait Runtime: Debug + Sized + 'static { type PlatformSpecificWebviewAttribute: Send + Sync + 'static; /// The platform specific runtime init arguments. type PlatformSpecificInitAttribute: Send + Sync + 'static; + /// Data about the window that requested the new window for [`PendingWebview::new_window_handler`]. + type WindowOpener: Send + Sync + Debug; /// Creates a new webview runtime. Must be used on the main thread. fn new(args: RuntimeInitArgs) -> Result; diff --git a/crates/tauri-runtime/src/webview.rs b/crates/tauri-runtime/src/webview.rs index 87ec256d3..dbf94b1a6 100644 --- a/crates/tauri-runtime/src/webview.rs +++ b/crates/tauri-runtime/src/webview.rs @@ -33,7 +33,8 @@ pub type WebResourceRequestHandler = pub type NavigationHandler = dyn Fn(&Url) -> bool + Send; -pub type NewWindowHandler = dyn Fn(Url, NewWindowFeatures) -> NewWindowResponse + Send + Sync; +pub type NewWindowHandler = + dyn Fn(Url, NewWindowFeatures) -> NewWindowResponse + Send + Sync; pub type OnPageLoadHandler = dyn Fn(Url, PageLoadEvent) + Send; @@ -85,50 +86,19 @@ pub enum PageLoadEvent { Finished, } -/// Information about the webview that initiated a new window request. -#[derive(Debug)] -pub struct NewWindowOpener { - /// The instance of the webview that initiated the new window request. - /// - /// This must be set as the related view of the new webview. See [`WebviewAttributes::related_view`]. - #[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - ))] - pub webview: webkit2gtk::WebView, - /// The instance of the webview that initiated the new window request. - /// - /// The target webview environment **MUST** match the environment of the opener webview. See [`WebviewAttributes::environment`]. - #[cfg(windows)] - pub webview: webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2, - #[cfg(windows)] - pub environment: webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Environment, - /// The instance of the webview that initiated the new window request. - #[cfg(target_os = "macos")] - pub webview: objc2::rc::Retained, - /// Configuration of the target webview. - /// - /// This **MUST** be used when creating the target webview. See [`WebviewAttributes::webview_configuration`]. - #[cfg(target_os = "macos")] - pub target_configuration: objc2::rc::Retained, -} - /// Window features of a window requested to open. #[derive(Debug)] -pub struct NewWindowFeatures { +pub struct NewWindowFeatures> { pub(crate) size: Option>, pub(crate) position: Option>, - pub(crate) opener: NewWindowOpener, + pub(crate) opener: R::WindowOpener, } -impl NewWindowFeatures { +impl> NewWindowFeatures { pub fn new( size: Option>, position: Option>, - opener: NewWindowOpener, + opener: R::WindowOpener, ) -> Self { Self { size, @@ -150,9 +120,14 @@ impl NewWindowFeatures { } /// Returns information about the webview that initiated a new window request. - pub fn opener(&self) -> &NewWindowOpener { + pub fn opener(&self) -> &R::WindowOpener { &self.opener } + + /// Returns information about the webview that initiated a new window request. + pub fn into_opener(self) -> R::WindowOpener { + self.opener + } } /// Response for the new window request handler. @@ -161,10 +136,7 @@ pub enum NewWindowResponse { Allow, /// Allow the window to be opened, with the given window. /// - /// ## Platform-specific: - /// - /// **Linux**: The webview must be related to the caller webview. See [`WebviewAttributes::related_view`]. - /// **Windows**: The webview must use the same environment as the caller webview. See [`WebviewAttributes::environment`]. + /// The window must be created referencing the opener window so it can inherit the appropriate attributes. #[cfg(not(any(target_os = "android", target_os = "ios")))] Create { window_id: WindowId }, /// Deny the window from being opened. @@ -199,6 +171,9 @@ pub struct PendingWebview> { /// The [`WebviewAttributes`] that the webview will be created with. pub webview_attributes: WebviewAttributes, + /// Information about the webview that initiated a new window request. + pub opener: Option, + /// Runtime specific attributes. pub platform_specific_attributes: Vec, @@ -211,7 +186,7 @@ pub struct PendingWebview> { /// A handler to decide if incoming url is allowed to navigate. pub navigation_handler: Option>, - pub new_window_handler: Option>, + pub new_window_handler: Option>>, pub document_title_changed_handler: Option>, @@ -243,6 +218,7 @@ impl> PendingWebview { } else { Ok(Self { webview_attributes, + opener: None, platform_specific_attributes, uri_scheme_protocols: Default::default(), label, @@ -381,25 +357,6 @@ pub struct WebviewAttributes { /// This relies on [`objc2_ui_kit`] which does not provide a stable API yet, so it can receive breaking changes in minor releases. #[cfg(target_os = "ios")] pub input_accessory_view_builder: Option, - - /// Set the environment for the webview. - /// Useful if you need to share the same environment, for instance when using the [`PendingWebview::new_window_handler`]. - #[cfg(windows)] - pub environment: Option, - - /// Creates a new webview sharing the same web process with the provided webview. - /// Useful if you need to link a webview to another, for instance when using the [`PendingWebview::new_window_handler`]. - #[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - ))] - pub related_view: Option, - - #[cfg(target_os = "macos")] - pub webview_configuration: Option>, } unsafe impl Send for WebviewAttributes {} @@ -515,18 +472,6 @@ impl WebviewAttributes { scroll_bar_style: ScrollBarStyle::Default, #[cfg(target_os = "ios")] input_accessory_view_builder: None, - #[cfg(windows)] - environment: None, - #[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - ))] - related_view: None, - #[cfg(target_os = "macos")] - webview_configuration: None, } } diff --git a/crates/tauri/src/webview/mod.rs b/crates/tauri/src/webview/mod.rs index fa53137bd..a37540a27 100644 --- a/crates/tauri/src/webview/mod.rs +++ b/crates/tauri/src/webview/mod.rs @@ -18,6 +18,12 @@ pub use cookie; use http::HeaderMap; use serde::Serialize; use tauri_macros::default_runtime; + +#[cfg(feature = "cef")] +pub use tauri_runtime_cef::NewWindowOpener as CefWindowOpener; +#[cfg(feature = "wry")] +pub use tauri_runtime_wry::NewWindowOpener as WryWindowOpener; + pub use tauri_runtime::webview::{NewWindowFeatures, PageLoadEvent, ScrollBarStyle}; // Remove this re-export in v3 pub use tauri_runtime::Cookie; @@ -58,8 +64,9 @@ use std::{ pub(crate) type WebResourceRequestHandler = dyn Fn(http::Request>, &mut http::Response>) + Send + Sync; pub(crate) type NavigationHandler = dyn Fn(&Url) -> bool + Send; -pub(crate) type NewWindowHandler = - dyn Fn(Url, NewWindowFeatures) -> NewWindowResponse + Send + Sync; +pub(crate) type NewWindowHandler = dyn Fn(Url, tauri_runtime::webview::NewWindowFeatures) -> NewWindowResponse + + Send + + Sync; pub(crate) type UriSchemeProtocolHandler = Box>, UriSchemeResponder) + Send + Sync>; pub(crate) type OnPageLoad = dyn Fn(Webview, PageLoadPayload<'_>) + Send + Sync + 'static; @@ -272,6 +279,7 @@ unstable_struct!( struct WebviewBuilder { pub(crate) label: String, pub(crate) webview_attributes: WebviewAttributes, + pub(crate) opener: Option, pub(crate) platform_specific_attributes: Vec, pub(crate) web_resource_request_handler: Option>, pub(crate) navigation_handler: Option>, @@ -365,6 +373,7 @@ async fn create_window(app: tauri::AppHandle) { Self { label: label.into(), webview_attributes: WebviewAttributes::new(url), + opener: None, platform_specific_attributes: Vec::new(), web_resource_request_handler: None, navigation_handler: None, @@ -445,6 +454,7 @@ async fn create_window(app: tauri::AppHandle) { Self { label: config.label.clone(), webview_attributes: WebviewAttributes::from(&config), + opener: None, platform_specific_attributes: Vec::new(), web_resource_request_handler: None, navigation_handler: None, @@ -602,7 +612,13 @@ tauri::Builder::default() /// /// [window.open]: https://developer.mozilla.org/en-US/docs/Web/API/Window/open pub fn on_new_window< - F: Fn(Url, NewWindowFeatures) -> NewWindowResponse + Send + Sync + 'static, + F: Fn( + Url, + tauri_runtime::webview::NewWindowFeatures, + ) -> NewWindowResponse + + Send + + Sync + + 'static, >( mut self, f: F, @@ -714,6 +730,11 @@ tauri::Builder::default() self } + pub fn opener(mut self, opener: R::WindowOpener) -> Self { + self.opener.replace(opener); + self + } + pub(crate) fn into_pending_webview>( mut self, manager: &M, @@ -724,26 +745,32 @@ tauri::Builder::default() self.platform_specific_attributes, self.label.clone(), )?; + pending.opener = self.opener.take(); pending.navigation_handler = self.navigation_handler.take(); pending.new_window_handler = self.new_window_handler.take().map(|handler| { Box::new( - move |url, features: NewWindowFeatures| match handler(url, features) { - NewWindowResponse::Allow => tauri_runtime::webview::NewWindowResponse::Allow, - #[cfg(mobile)] - NewWindowResponse::Create { window: _ } => { - tauri_runtime::webview::NewWindowResponse::Allow - } - #[cfg(desktop)] - NewWindowResponse::Create { window } => { - tauri_runtime::webview::NewWindowResponse::Create { - window_id: window.window.window.id, + move |url, features: tauri_runtime::webview::NewWindowFeatures| { + match handler(url, features) { + NewWindowResponse::Allow => tauri_runtime::webview::NewWindowResponse::Allow, + #[cfg(mobile)] + NewWindowResponse::Create { window: _ } => { + tauri_runtime::webview::NewWindowResponse::Allow } + #[cfg(desktop)] + NewWindowResponse::Create { window } => { + tauri_runtime::webview::NewWindowResponse::Create { + window_id: window.window.window.id, + } + } + NewWindowResponse::Deny => tauri_runtime::webview::NewWindowResponse::Deny, } - NewWindowResponse::Deny => tauri_runtime::webview::NewWindowResponse::Deny, }, ) as Box< - dyn Fn(Url, NewWindowFeatures) -> tauri_runtime::webview::NewWindowResponse + dyn Fn( + Url, + tauri_runtime::webview::NewWindowFeatures, + ) -> tauri_runtime::webview::NewWindowResponse + Send + Sync + 'static, @@ -1252,32 +1279,41 @@ fn main() { )); self } +} +/// Wry APIs +#[cfg(feature = "wry")] +impl WebviewBuilder { /// Set the environment for the webview. /// Useful if you need to share the same environment, for instance when using the [`Self::on_new_window`]. - #[cfg(all(feature = "wry", windows))] + #[cfg(windows)] pub fn with_environment( mut self, environment: webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Environment, ) -> Self { - self.webview_attributes.environment.replace(environment); + self + .platform_specific_attributes + .push(tauri_runtime_wry::WebviewAttribute::Environment( + environment, + )); self } /// Creates a new webview sharing the same web process with the provided webview. /// Useful if you need to link a webview to another, for instance when using the [`Self::on_new_window`]. - #[cfg(all( - feature = "wry", - any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - ) + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", ))] pub fn with_related_view(mut self, related_view: webkit2gtk::WebView) -> Self { - self.webview_attributes.related_view.replace(related_view); + self + .platform_specific_attributes + .push(tauri_runtime_wry::WebviewAttribute::RelatedView( + related_view, + )); self } @@ -1288,10 +1324,9 @@ fn main() { mut self, webview_configuration: objc2::rc::Retained, ) -> Self { - self - .webview_attributes - .webview_configuration - .replace(webview_configuration); + self.platform_specific_attributes.push( + tauri_runtime_wry::WebviewAttribute::WebviewConfiguration(webview_configuration), + ); self } } diff --git a/crates/tauri/src/webview/webview_window.rs b/crates/tauri/src/webview/webview_window.rs index b5a185ae1..af8400850 100644 --- a/crates/tauri/src/webview/webview_window.rs +++ b/crates/tauri/src/webview/webview_window.rs @@ -339,7 +339,10 @@ impl<'a, R: Runtime, M: Manager> WebviewWindowBuilder<'a, R, M> { /// /// [window.open]: https://developer.mozilla.org/en-US/docs/Web/API/Window/open pub fn on_new_window< - F: Fn(Url, NewWindowFeatures) -> NewWindowResponse + Send + Sync + 'static, + F: Fn(Url, NewWindowFeatures) -> NewWindowResponse + + Send + + Sync + + 'static, >( mut self, f: F, @@ -1307,9 +1310,41 @@ impl> WebviewWindowBuilder<'_, R, M> { self } + /// Set the window features. + /// Useful if you need to share the same window features, for instance when using the [`Self::on_new_window`]. + #[cfg(any( + target_os = "macos", + windows, + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + pub fn window_features( + mut self, + features: NewWindowFeatures, + ) -> Self { + if let Some(position) = features.position() { + self.window_builder = self.window_builder.position(position.x, position.y); + } + + if let Some(size) = features.size() { + self.window_builder = self.window_builder.inner_size(size.width, size.height); + } + + self.webview_builder = self.webview_builder.opener(features.into_opener()); + + self + } +} + +/// Wry APIs +#[cfg(feature = "wry")] +impl> WebviewWindowBuilder<'_, crate::Wry, M> { /// Set the environment for the webview. /// Useful if you need to share the same environment, for instance when using the [`Self::on_new_window`]. - #[cfg(all(feature = "wry", windows))] + #[cfg(windows)] pub fn with_environment( mut self, environment: webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Environment, @@ -1320,15 +1355,12 @@ impl> WebviewWindowBuilder<'_, R, M> { /// Creates a new webview sharing the same web process with the provided webview. /// Useful if you need to link a webview to another, for instance when using the [`Self::on_new_window`]. - #[cfg(all( - feature = "wry", - any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - ) + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" ))] pub fn with_related_view(mut self, related_view: webkit2gtk::WebView) -> Self { self.webview_builder = self.webview_builder.with_related_view(related_view); @@ -1347,58 +1379,6 @@ impl> WebviewWindowBuilder<'_, R, M> { .with_webview_configuration(webview_configuration); self } - - /// Set the window features. - /// Useful if you need to share the same window features, for instance when using the [`Self::on_new_window`]. - #[cfg(any( - target_os = "macos", - windows, - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" - ))] - pub fn window_features(mut self, features: NewWindowFeatures) -> Self { - if let Some(position) = features.position() { - self.window_builder = self.window_builder.position(position.x, position.y); - } - - if let Some(size) = features.size() { - self.window_builder = self.window_builder.inner_size(size.width, size.height); - } - - #[cfg(target_os = "macos")] - { - self.webview_builder = self - .webview_builder - .with_webview_configuration(features.opener().target_configuration.clone()); - } - - #[cfg(all(feature = "wry", windows))] - { - self.webview_builder = self - .webview_builder - .with_environment(features.opener().environment.clone()); - } - - #[cfg(all( - feature = "wry", - any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd", - ) - ))] - { - self.webview_builder = self - .webview_builder - .with_related_view(features.opener().webview.clone()); - } - self - } } /// A type that wraps a [`Window`] together with a [`Webview`].