use std::sync::Weak;
use tao::window::Window;
use tauri::{App, AppHandle, EventLoopMessage, Manager, Runtime, Webview, WebviewWindow};
use tauri_runtime::dynamic::{DynRuntimeHandle, DynWebviewAttributes};
use crate::{
Message, PluginBuilder, TaoWindowBuilder, TaoWindowId, WindowMessage, WryHandle,
WryWebviewAttributes,
};
type Result<T> = std::result::Result<T, tauri::Error>;
fn not_wry() -> tauri::Error {
tauri_runtime::Error::RuntimeTypeMismatch(
"the application is not running on the wry runtime".into(),
)
.into()
}
pub trait AsWryHandle {
fn as_wry_handle(&self) -> Option<&WryHandle<EventLoopMessage>>;
}
impl AsWryHandle for WryHandle<EventLoopMessage> {
fn as_wry_handle(&self) -> Option<&WryHandle<EventLoopMessage>> {
Some(self)
}
}
impl AsWryHandle for DynRuntimeHandle<EventLoopMessage> {
fn as_wry_handle(&self) -> Option<&WryHandle<EventLoopMessage>> {
self.downcast_ref()
}
}
pub trait AsWryWebviewAttributes {
fn as_wry_webview_attributes_mut(&mut self) -> Option<&mut WryWebviewAttributes>;
}
impl AsWryWebviewAttributes for WryWebviewAttributes {
fn as_wry_webview_attributes_mut(&mut self) -> Option<&mut WryWebviewAttributes> {
Some(self)
}
}
impl AsWryWebviewAttributes for DynWebviewAttributes {
fn as_wry_webview_attributes_mut(&mut self) -> Option<&mut WryWebviewAttributes> {
self.get_or_default()
}
}
#[cfg(any(
windows,
target_os = "macos",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
fn with_wry_webview_attributes<A: AsWryWebviewAttributes>(
attributes: &mut A,
f: impl FnOnce(&mut WryWebviewAttributes),
) {
match attributes.as_wry_webview_attributes_mut() {
Some(attributes) => f(attributes),
None => log::warn!(
"ignoring the wry webview attributes: attributes of another runtime were already set on the webview builder"
),
}
}
pub trait AppHandleWryExt {
fn create_tao_window<F: FnOnce() -> (String, TaoWindowBuilder) + Send + 'static>(
&self,
f: F,
) -> Result<Weak<Window>>;
fn send_tao_window_event(&self, window_id: TaoWindowId, message: WindowMessage) -> Result<()>;
fn wry_plugin<P: PluginBuilder<EventLoopMessage> + 'static>(&self, plugin: P) -> Result<()>
where
<P as PluginBuilder<EventLoopMessage>>::Plugin: Send;
}
impl<R: Runtime> AppHandleWryExt for AppHandle<R>
where
R::Handle: AsWryHandle,
{
fn create_tao_window<F: FnOnce() -> (String, TaoWindowBuilder) + Send + 'static>(
&self,
f: F,
) -> Result<Weak<Window>> {
self
.runtime_handle()
.as_wry_handle()
.ok_or_else(not_wry)?
.create_tao_window(f)
.map_err(Into::into)
}
fn send_tao_window_event(&self, window_id: TaoWindowId, message: WindowMessage) -> Result<()> {
let handle = self.runtime_handle().as_wry_handle().ok_or_else(not_wry)?;
handle
.send_event(Message::Window(handle.window_id(window_id), message))
.map_err(Into::into)
}
fn wry_plugin<P: PluginBuilder<EventLoopMessage> + 'static>(&self, plugin: P) -> Result<()>
where
<P as PluginBuilder<EventLoopMessage>>::Plugin: Send,
{
self
.runtime_handle()
.as_wry_handle()
.ok_or_else(not_wry)?
.plugin(plugin);
Ok(())
}
}
pub trait AppWryExt {
fn wry_plugin<P: PluginBuilder<EventLoopMessage> + 'static>(&self, plugin: P) -> Result<()>
where
<P as PluginBuilder<EventLoopMessage>>::Plugin: Send;
}
impl<R: Runtime> AppWryExt for App<R>
where
R::Handle: AsWryHandle,
{
fn wry_plugin<P: PluginBuilder<EventLoopMessage> + 'static>(&self, plugin: P) -> Result<()>
where
<P as PluginBuilder<EventLoopMessage>>::Plugin: Send,
{
self.handle().wry_plugin(plugin)
}
}
pub trait WebviewWryExt {
fn with_wry_webview<F: FnOnce(&crate::Webview) + Send + 'static>(&self, f: F) -> Result<()>;
}
impl<R: Runtime> WebviewWryExt for Webview<R>
where
R::Handle: AsWryHandle,
{
fn with_wry_webview<F: FnOnce(&crate::Webview) + Send + 'static>(&self, f: F) -> Result<()> {
if self.app_handle().runtime_handle().as_wry_handle().is_none() {
return Err(not_wry());
}
self.with_webview(move |webview| {
if let Some(webview) = webview.downcast_ref::<crate::Webview>() {
f(webview)
}
})
}
}
impl<R: Runtime> WebviewWryExt for WebviewWindow<R>
where
R::Handle: AsWryHandle,
{
fn with_wry_webview<F: FnOnce(&crate::Webview) + Send + 'static>(&self, f: F) -> Result<()> {
self.as_ref().with_wry_webview(f)
}
}
macro_rules! webview_builder_ext {
($(#[$meta:meta])* $trait:ident) => {
$(#[$meta])*
pub trait $trait {
#[cfg(windows)]
#[must_use]
fn with_environment(
self,
environment: webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Environment,
) -> Self;
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
#[must_use]
fn with_related_view(self, related_view: webkit2gtk::WebView) -> Self;
#[cfg(target_os = "macos")]
#[must_use]
fn with_webview_configuration(
self,
webview_configuration: objc2::rc::Retained<objc2_web_kit::WKWebViewConfiguration>,
) -> Self;
}
};
}
macro_rules! webview_builder_ext_impl {
($trait:ident, $($impl_header:tt)*) => {
$($impl_header)* {
#[cfg(windows)]
fn with_environment(
mut self,
environment: webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Environment,
) -> Self {
with_wry_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.environment = Some(environment);
});
self
}
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
fn with_related_view(mut self, related_view: webkit2gtk::WebView) -> Self {
with_wry_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.related_view = Some(related_view);
});
self
}
#[cfg(target_os = "macos")]
fn with_webview_configuration(
mut self,
webview_configuration: objc2::rc::Retained<objc2_web_kit::WKWebViewConfiguration>,
) -> Self {
with_wry_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.webview_configuration = Some(webview_configuration);
});
self
}
}
};
}
webview_builder_ext!(
WebviewWindowBuilderWryExt
);
webview_builder_ext_impl!(
WebviewWindowBuilderWryExt,
impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilderWryExt for tauri::WebviewWindowBuilder<'a, R, M>
where
R::RuntimeWebviewAttributes: AsWryWebviewAttributes,
);
webview_builder_ext!(
/// wry-specific APIs of [`tauri::webview::WebviewBuilder`].
#[cfg(feature = "unstable")]
WebviewBuilderWryExt
);
#[cfg(feature = "unstable")]
webview_builder_ext_impl!(
WebviewBuilderWryExt,
impl<R: Runtime> WebviewBuilderWryExt for tauri::webview::WebviewBuilder<R>
where
R::RuntimeWebviewAttributes: AsWryWebviewAttributes,
);