mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-02-06 13:37:09 +00:00
new window opener
This commit is contained in:
parent
fc405b3ae6
commit
98fdc7c5fa
@ -608,6 +608,7 @@ wrap_life_span_handler! {
|
||||
window_kind: WindowKind,
|
||||
window_id: WindowId,
|
||||
context: Context<T>,
|
||||
new_window_handler: Option<Arc<tauri_runtime::webview::NewWindowHandler<T, crate::CefRuntime<T>>>>,
|
||||
}
|
||||
|
||||
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<Client>>,
|
||||
_settings: Option<&mut BrowserSettings>,
|
||||
_extra_info: Option<&mut Option<DictionaryValue>>,
|
||||
_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<Arc<tauri_runtime::webview::OnPageLoadHandler>>,
|
||||
document_title_changed_handler: Option<Arc<tauri_runtime::webview::DocumentTitleChangedHandler>>,
|
||||
navigation_handler: Option<Arc<tauri_runtime::webview::NavigationHandler>>,
|
||||
new_window_handler: Option<Arc<tauri_runtime::webview::NewWindowHandler<T, crate::CefRuntime<T>>>>,
|
||||
download_handler: Option<Arc<tauri_runtime::webview::DownloadHandler>>,
|
||||
devtools_enabled: bool,
|
||||
custom_scheme_domain_names: Vec<String>,
|
||||
@ -643,7 +720,12 @@ wrap_client! {
|
||||
}
|
||||
|
||||
fn life_span_handler(&self) -> Option<LifeSpanHandler> {
|
||||
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<LoadHandler> {
|
||||
@ -2459,12 +2541,13 @@ fn create_browser_window<T: UserEvent>(
|
||||
) {
|
||||
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<T: UserEvent>(
|
||||
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<T: UserEvent>(
|
||||
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<T: UserEvent>(
|
||||
) {
|
||||
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<T: UserEvent>(
|
||||
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<T: UserEvent>(
|
||||
on_page_load_handler,
|
||||
document_title_changed_handler,
|
||||
navigation_handler,
|
||||
new_window_handler,
|
||||
download_handler,
|
||||
devtools_enabled,
|
||||
custom_scheme_domain_names.clone(),
|
||||
|
||||
@ -2017,6 +2017,9 @@ pub enum RuntimeStyle {
|
||||
Chrome,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NewWindowOpener {}
|
||||
|
||||
impl<T: UserEvent> Runtime<T> for CefRuntime<T> {
|
||||
type WindowDispatcher = CefWindowDispatcher<T>;
|
||||
type WebviewDispatcher = CefWebviewDispatcher<T>;
|
||||
@ -2024,6 +2027,7 @@ impl<T: UserEvent> Runtime<T> for CefRuntime<T> {
|
||||
type EventLoopProxy = EventProxy<T>;
|
||||
type PlatformSpecificWebviewAttribute = WebviewAtribute;
|
||||
type PlatformSpecificInitAttribute = RuntimeInitAttribute;
|
||||
type WindowOpener = NewWindowOpener;
|
||||
|
||||
fn new(args: RuntimeInitArgs<RuntimeInitAttribute>) -> Result<Self> {
|
||||
Ok(Self::init(args))
|
||||
|
||||
@ -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<objc2_web_kit::WKWebView>,
|
||||
/// Configuration of the target webview.
|
||||
///
|
||||
/// This **MUST** be used when creating the target webview.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub target_configuration: objc2::rc::Retained<objc2_web_kit::WKWebViewConfiguration>,
|
||||
}
|
||||
|
||||
// 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<objc2_web_kit::WKWebViewConfiguration>),
|
||||
}
|
||||
|
||||
// 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<T: UserEvent> Runtime<T> for Wry<T> {
|
||||
type Handle = WryHandle<T>;
|
||||
|
||||
type EventLoopProxy = EventProxy<T>;
|
||||
type PlatformSpecificWebviewAttribute = ();
|
||||
type PlatformSpecificWebviewAttribute = WebviewAttribute;
|
||||
type PlatformSpecificInitAttribute = ();
|
||||
type WindowOpener = NewWindowOpener;
|
||||
|
||||
fn new(args: RuntimeInitArgs<()>) -> Result<Self> {
|
||||
Self::init_with_builder(EventLoopBuilder::<Message<T>>::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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -411,6 +411,8 @@ pub trait Runtime<T: UserEvent>: 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<Self::PlatformSpecificInitAttribute>) -> Result<Self>;
|
||||
|
||||
@ -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<T, R> =
|
||||
dyn Fn(Url, NewWindowFeatures<T, R>) -> 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<objc2_web_kit::WKWebView>,
|
||||
/// 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<objc2_web_kit::WKWebViewConfiguration>,
|
||||
}
|
||||
|
||||
/// Window features of a window requested to open.
|
||||
#[derive(Debug)]
|
||||
pub struct NewWindowFeatures {
|
||||
pub struct NewWindowFeatures<T: UserEvent, R: Runtime<T>> {
|
||||
pub(crate) size: Option<crate::dpi::LogicalSize<f64>>,
|
||||
pub(crate) position: Option<crate::dpi::LogicalPosition<f64>>,
|
||||
pub(crate) opener: NewWindowOpener,
|
||||
pub(crate) opener: R::WindowOpener,
|
||||
}
|
||||
|
||||
impl NewWindowFeatures {
|
||||
impl<T: UserEvent, R: Runtime<T>> NewWindowFeatures<T, R> {
|
||||
pub fn new(
|
||||
size: Option<crate::dpi::LogicalSize<f64>>,
|
||||
position: Option<crate::dpi::LogicalPosition<f64>>,
|
||||
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<T: UserEvent, R: Runtime<T>> {
|
||||
/// 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<R::WindowOpener>,
|
||||
|
||||
/// Runtime specific attributes.
|
||||
pub platform_specific_attributes: Vec<R::PlatformSpecificWebviewAttribute>,
|
||||
|
||||
@ -211,7 +186,7 @@ pub struct PendingWebview<T: UserEvent, R: Runtime<T>> {
|
||||
/// A handler to decide if incoming url is allowed to navigate.
|
||||
pub navigation_handler: Option<Box<NavigationHandler>>,
|
||||
|
||||
pub new_window_handler: Option<Box<NewWindowHandler>>,
|
||||
pub new_window_handler: Option<Box<NewWindowHandler<T, R>>>,
|
||||
|
||||
pub document_title_changed_handler: Option<Box<DocumentTitleChangedHandler>>,
|
||||
|
||||
@ -243,6 +218,7 @@ impl<T: UserEvent, R: Runtime<T>> PendingWebview<T, R> {
|
||||
} 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<InputAccessoryViewBuilder>,
|
||||
|
||||
/// 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<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",
|
||||
))]
|
||||
pub related_view: Option<webkit2gtk::WebView>,
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub webview_configuration: Option<objc2::rc::Retained<objc2_web_kit::WKWebViewConfiguration>>,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<Vec<u8>>, &mut http::Response<Cow<'static, [u8]>>) + Send + Sync;
|
||||
pub(crate) type NavigationHandler = dyn Fn(&Url) -> bool + Send;
|
||||
pub(crate) type NewWindowHandler<R> =
|
||||
dyn Fn(Url, NewWindowFeatures) -> NewWindowResponse<R> + Send + Sync;
|
||||
pub(crate) type NewWindowHandler<R> = dyn Fn(Url, tauri_runtime::webview::NewWindowFeatures<EventLoopMessage, R>) -> NewWindowResponse<R>
|
||||
+ Send
|
||||
+ Sync;
|
||||
pub(crate) type UriSchemeProtocolHandler =
|
||||
Box<dyn Fn(&str, http::Request<Vec<u8>>, UriSchemeResponder) + Send + Sync>;
|
||||
pub(crate) type OnPageLoad<R> = dyn Fn(Webview<R>, PageLoadPayload<'_>) + Send + Sync + 'static;
|
||||
@ -272,6 +279,7 @@ unstable_struct!(
|
||||
struct WebviewBuilder<R: Runtime> {
|
||||
pub(crate) label: String,
|
||||
pub(crate) webview_attributes: WebviewAttributes,
|
||||
pub(crate) opener: Option<R::WindowOpener>,
|
||||
pub(crate) platform_specific_attributes: Vec<R::PlatformSpecificWebviewAttribute>,
|
||||
pub(crate) web_resource_request_handler: Option<Box<WebResourceRequestHandler>>,
|
||||
pub(crate) navigation_handler: Option<Box<NavigationHandler>>,
|
||||
@ -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<R> + Send + Sync + 'static,
|
||||
F: Fn(
|
||||
Url,
|
||||
tauri_runtime::webview::NewWindowFeatures<EventLoopMessage, R>,
|
||||
) -> NewWindowResponse<R>
|
||||
+ 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<M: Manager<R>>(
|
||||
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<EventLoopMessage, R>| {
|
||||
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<EventLoopMessage, R>,
|
||||
) -> tauri_runtime::webview::NewWindowResponse
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
@ -1252,32 +1279,41 @@ fn main() {
|
||||
));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Wry APIs
|
||||
#[cfg(feature = "wry")]
|
||||
impl WebviewBuilder<crate::Wry> {
|
||||
/// 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<objc2_web_kit::WKWebViewConfiguration>,
|
||||
) -> Self {
|
||||
self
|
||||
.webview_attributes
|
||||
.webview_configuration
|
||||
.replace(webview_configuration);
|
||||
self.platform_specific_attributes.push(
|
||||
tauri_runtime_wry::WebviewAttribute::WebviewConfiguration(webview_configuration),
|
||||
);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,7 +339,10 @@ impl<'a, R: Runtime, M: Manager<R>> 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<R> + Send + Sync + 'static,
|
||||
F: Fn(Url, NewWindowFeatures<crate::EventLoopMessage, R>) -> NewWindowResponse<R>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>(
|
||||
mut self,
|
||||
f: F,
|
||||
@ -1307,9 +1310,41 @@ impl<R: Runtime, M: Manager<R>> 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<crate::EventLoopMessage, R>,
|
||||
) -> 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<M: Manager<crate::Wry>> 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<R: Runtime, M: Manager<R>> 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<R: Runtime, M: Manager<R>> 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`].
|
||||
|
||||
Loading…
Reference in New Issue
Block a user