use std::sync::Arc;
use tauri::{EventLoopMessage, Manager, Runtime, Webview, WebviewWindow};
use tauri_runtime::dynamic::{DynWebviewAttributes, DynWebviewDispatcher, DynWindowOpener};
use crate::{
CefWebviewAttributes, CefWebviewDispatcher, ChromeCommandGroup, ConsoleMessage, DevToolsProtocol,
FrameEvent, NewWindowOpener, RuntimeStyle,
};
type Result<T> = std::result::Result<T, tauri::Error>;
fn not_cef() -> tauri::Error {
tauri_runtime::Error::RuntimeTypeMismatch(
"the application is not running on the CEF runtime".into(),
)
.into()
}
pub trait AsCefWebviewDispatcher {
fn as_cef_webview_dispatcher(&self) -> Option<&CefWebviewDispatcher<EventLoopMessage>>;
}
impl AsCefWebviewDispatcher for CefWebviewDispatcher<EventLoopMessage> {
fn as_cef_webview_dispatcher(&self) -> Option<&CefWebviewDispatcher<EventLoopMessage>> {
Some(self)
}
}
impl AsCefWebviewDispatcher for DynWebviewDispatcher<EventLoopMessage> {
fn as_cef_webview_dispatcher(&self) -> Option<&CefWebviewDispatcher<EventLoopMessage>> {
self.downcast_ref()
}
}
pub trait AsCefWindowOpener {
fn as_cef_window_opener(&self) -> Option<&NewWindowOpener>;
}
impl AsCefWindowOpener for NewWindowOpener {
fn as_cef_window_opener(&self) -> Option<&NewWindowOpener> {
Some(self)
}
}
impl AsCefWindowOpener for DynWindowOpener {
fn as_cef_window_opener(&self) -> Option<&NewWindowOpener> {
self.downcast_ref()
}
}
pub trait AsCefWebviewAttributes {
fn as_cef_webview_attributes_mut(&mut self) -> Option<&mut CefWebviewAttributes>;
}
impl AsCefWebviewAttributes for CefWebviewAttributes {
fn as_cef_webview_attributes_mut(&mut self) -> Option<&mut CefWebviewAttributes> {
Some(self)
}
}
impl AsCefWebviewAttributes for DynWebviewAttributes {
fn as_cef_webview_attributes_mut(&mut self) -> Option<&mut CefWebviewAttributes> {
self.get_or_default()
}
}
fn with_cef_webview_attributes<A: AsCefWebviewAttributes>(
attributes: &mut A,
f: impl FnOnce(&mut CefWebviewAttributes),
) {
match attributes.as_cef_webview_attributes_mut() {
Some(attributes) => f(attributes),
None => log::warn!(
"ignoring the CEF webview attributes: attributes of another runtime were already set on the webview builder"
),
}
}
pub trait WebviewCefExt {
fn send_dev_tools_message(&self, message: &[u8]) -> Result<()>;
fn on_dev_tools_protocol<F: Fn(DevToolsProtocol) + Send + Sync + 'static>(
&self,
f: F,
) -> Result<()>;
fn with_cef_webview<F: FnOnce(&crate::Webview) + Send + 'static>(&self, f: F) -> Result<()>;
}
impl<R: Runtime> WebviewCefExt for Webview<R>
where
R::WebviewDispatcher: AsCefWebviewDispatcher,
{
fn send_dev_tools_message(&self, message: &[u8]) -> Result<()> {
self
.dispatcher()
.as_cef_webview_dispatcher()
.ok_or_else(not_cef)?
.send_dev_tools_message(message)
.map_err(Into::into)
}
fn on_dev_tools_protocol<F: Fn(DevToolsProtocol) + Send + Sync + 'static>(
&self,
f: F,
) -> Result<()> {
self
.dispatcher()
.as_cef_webview_dispatcher()
.ok_or_else(not_cef)?
.on_dev_tools_protocol(f)
.map_err(Into::into)
}
fn with_cef_webview<F: FnOnce(&crate::Webview) + Send + 'static>(&self, f: F) -> Result<()> {
if self.dispatcher().as_cef_webview_dispatcher().is_none() {
return Err(not_cef());
}
self.with_webview(move |webview| {
if let Some(webview) = webview.downcast_ref::<crate::Webview>() {
f(webview)
}
})
}
}
impl<R: Runtime> WebviewCefExt for WebviewWindow<R>
where
R::WebviewDispatcher: AsCefWebviewDispatcher,
{
fn send_dev_tools_message(&self, message: &[u8]) -> Result<()> {
self.as_ref().send_dev_tools_message(message)
}
fn on_dev_tools_protocol<F: Fn(DevToolsProtocol) + Send + Sync + 'static>(
&self,
f: F,
) -> Result<()> {
self.as_ref().on_dev_tools_protocol(f)
}
fn with_cef_webview<F: FnOnce(&crate::Webview) + Send + 'static>(&self, f: F) -> Result<()> {
self.as_ref().with_cef_webview(f)
}
}
pub trait WebviewWindowBuilderCefExt {
#[must_use]
fn browser_runtime_style(self, style: RuntimeStyle) -> Self;
#[must_use]
fn on_frame_event<F: Fn(FrameEvent) + Send + Sync + 'static>(self, handler: F) -> Self;
#[must_use]
fn on_console_message<F: Fn(ConsoleMessage) + Send + Sync + 'static>(self, handler: F) -> Self;
#[must_use]
fn allow_chrome_commands<I: IntoIterator<Item = ChromeCommandGroup>>(self, groups: I) -> Self;
#[must_use]
fn with_browser_settings<F: Fn(&mut cef::BrowserSettings) + Send + Sync + 'static>(
self,
callback: F,
) -> Self;
}
impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilderCefExt
for tauri::WebviewWindowBuilder<'a, R, M>
where
R::RuntimeWebviewAttributes: AsCefWebviewAttributes,
{
fn browser_runtime_style(mut self, style: RuntimeStyle) -> Self {
with_cef_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.runtime_style = Some(style);
});
self
}
fn on_frame_event<F: Fn(FrameEvent) + Send + Sync + 'static>(mut self, handler: F) -> Self {
let handler = Arc::new(handler);
with_cef_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.frame_event_handler = Some(handler);
});
self
}
fn on_console_message<F: Fn(ConsoleMessage) + Send + Sync + 'static>(
mut self,
handler: F,
) -> Self {
let handler = Arc::new(handler);
with_cef_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.console_message_handler = Some(handler);
});
self
}
fn allow_chrome_commands<I: IntoIterator<Item = ChromeCommandGroup>>(
mut self,
groups: I,
) -> Self {
let groups = groups.into_iter().collect::<Vec<_>>();
with_cef_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.allowed_chrome_commands = groups.clone();
});
self
}
fn with_browser_settings<F: Fn(&mut cef::BrowserSettings) + Send + Sync + 'static>(
mut self,
callback: F,
) -> Self {
let callback = Arc::new(callback);
with_cef_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.browser_settings_callback = Some(callback.clone());
});
self
}
}
#[cfg(feature = "unstable")]
pub trait WebviewBuilderCefExt {
#[must_use]
fn browser_runtime_style(self, style: RuntimeStyle) -> Self;
#[must_use]
fn on_frame_event<F: Fn(FrameEvent) + Send + Sync + 'static>(self, handler: F) -> Self;
#[must_use]
fn on_console_message<F: Fn(ConsoleMessage) + Send + Sync + 'static>(self, handler: F) -> Self;
#[must_use]
fn allow_chrome_commands<I: IntoIterator<Item = ChromeCommandGroup>>(self, groups: I) -> Self;
#[must_use]
fn with_browser_settings<F: Fn(&mut cef::BrowserSettings) + Send + Sync + 'static>(
self,
callback: F,
) -> Self;
}
#[cfg(feature = "unstable")]
impl<R: Runtime> WebviewBuilderCefExt for tauri::webview::WebviewBuilder<R>
where
R::RuntimeWebviewAttributes: AsCefWebviewAttributes,
{
fn browser_runtime_style(mut self, style: RuntimeStyle) -> Self {
with_cef_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.runtime_style = Some(style);
});
self
}
fn on_frame_event<F: Fn(FrameEvent) + Send + Sync + 'static>(mut self, handler: F) -> Self {
let handler = Arc::new(handler);
with_cef_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.frame_event_handler = Some(handler);
});
self
}
fn on_console_message<F: Fn(ConsoleMessage) + Send + Sync + 'static>(
mut self,
handler: F,
) -> Self {
let handler = Arc::new(handler);
with_cef_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.console_message_handler = Some(handler);
});
self
}
fn allow_chrome_commands<I: IntoIterator<Item = ChromeCommandGroup>>(
mut self,
groups: I,
) -> Self {
let groups = groups.into_iter().collect::<Vec<_>>();
with_cef_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.allowed_chrome_commands = groups.clone();
});
self
}
fn with_browser_settings<F: Fn(&mut cef::BrowserSettings) + Send + Sync + 'static>(
mut self,
callback: F,
) -> Self {
let callback = Arc::new(callback);
with_cef_webview_attributes(self.runtime_specific_attributes_mut(), |attributes| {
attributes.browser_settings_callback = Some(callback.clone());
});
self
}
}