#![allow(clippy::new_without_default)]
#![allow(clippy::default_constructed_unit_structs)]
#![allow(clippy::type_complexity)]
#![cfg_attr(docsrs, feature(doc_cfg))]
mod error;
mod proxy;
#[cfg(any(target_os = "macos", target_os = "android", target_os = "ios"))]
mod util;
mod web_context;
#[cfg(target_os = "android")]
pub(crate) mod android;
#[cfg(target_os = "android")]
pub use crate::android::android_setup;
#[cfg(target_os = "android")]
pub mod prelude {
pub use crate::android::{binding::*, dispatch, find_class, Context};
pub use tao_macros::{android_fn, generate_package_name};
}
#[cfg(target_os = "android")]
pub use android::JniHandle;
#[cfg(target_os = "android")]
use android::*;
#[cfg(gtk)]
pub(crate) mod webkitgtk;
pub use raw_window_handle;
use raw_window_handle::HasWindowHandle;
#[cfg(gtk)]
use webkitgtk::*;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use objc2::rc::Retained;
#[cfg(target_os = "macos")]
use objc2_app_kit::NSWindow;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use objc2_web_kit::WKUserContentController;
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub(crate) mod wkwebview;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use wkwebview::*;
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub use wkwebview::{PrintMargin, PrintOptions, WryWebView};
#[cfg(target_os = "windows")]
pub(crate) mod webview2;
#[cfg(target_os = "windows")]
pub use self::webview2::ScrollBarStyle;
#[cfg(target_os = "windows")]
use self::webview2::*;
#[cfg(target_os = "windows")]
use webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Controller;
use std::{borrow::Cow, collections::HashMap, path::PathBuf, rc::Rc};
use http::{Request, Response};
pub use dpi;
pub use error::*;
pub use http;
pub use proxy::{ProxyConfig, ProxyEndpoint};
pub use web_context::WebContext;
#[derive(Clone, Copy, Debug)]
pub struct Rect {
pub position: dpi::Position,
pub size: dpi::Size,
}
impl Default for Rect {
fn default() -> Self {
Self {
position: dpi::LogicalPosition::new(0, 0).into(),
size: dpi::LogicalSize::new(0, 0).into(),
}
}
}
pub struct RequestAsyncResponder {
pub(crate) responder: Box<dyn FnOnce(Response<Cow<'static, [u8]>>)>,
}
unsafe impl Send for RequestAsyncResponder {}
impl RequestAsyncResponder {
pub fn respond<T: Into<Cow<'static, [u8]>>>(self, response: Response<T>) {
let (parts, body) = response.into_parts();
(self.responder)(Response::from_parts(parts, body.into()))
}
}
pub type WebViewId<'a> = &'a str;
pub struct WebViewAttributes<'a> {
pub id: Option<WebViewId<'a>>,
pub context: Option<&'a mut WebContext>,
pub user_agent: Option<String>,
pub visible: bool,
pub transparent: bool,
pub background_color: Option<RGBA>,
pub url: Option<String>,
pub headers: Option<http::HeaderMap>,
pub zoom_hotkeys_enabled: bool,
pub html: Option<String>,
pub initialization_scripts: Vec<String>,
pub custom_protocols:
HashMap<String, Box<dyn Fn(WebViewId, Request<Vec<u8>>, RequestAsyncResponder)>>,
pub ipc_handler: Option<Box<dyn Fn(Request<String>)>>,
#[cfg(feature = "drag-drop")]
#[cfg_attr(docsrs, doc(cfg(feature = "drag-drop")))]
pub drag_drop_handler: Option<Box<dyn Fn(DragDropEvent) -> bool>>,
#[cfg(not(feature = "drag-drop"))]
drag_drop_handler: Option<Box<dyn Fn(DragDropEvent) -> bool>>,
pub navigation_handler: Option<Box<dyn Fn(String) -> bool>>,
pub download_started_handler: Option<Box<dyn FnMut(String, &mut PathBuf) -> bool + 'static>>,
pub download_completed_handler: Option<Rc<dyn Fn(String, Option<PathBuf>, bool) + 'static>>,
pub new_window_req_handler: Option<Box<dyn Fn(String) -> bool>>,
pub clipboard: bool,
pub devtools: bool,
pub accept_first_mouse: bool,
pub back_forward_navigation_gestures: bool,
pub document_title_changed_handler: Option<Box<dyn Fn(String)>>,
pub incognito: bool,
pub autoplay: bool,
pub on_page_load_handler: Option<Box<dyn Fn(PageLoadEvent, String)>>,
pub proxy_config: Option<ProxyConfig>,
pub focused: bool,
pub bounds: Option<Rect>,
}
impl<'a> Default for WebViewAttributes<'a> {
fn default() -> Self {
Self {
id: Default::default(),
context: None,
user_agent: None,
visible: true,
transparent: false,
background_color: None,
url: None,
headers: None,
html: None,
initialization_scripts: Default::default(),
custom_protocols: Default::default(),
ipc_handler: None,
drag_drop_handler: None,
navigation_handler: None,
download_started_handler: None,
download_completed_handler: None,
new_window_req_handler: None,
clipboard: false,
#[cfg(debug_assertions)]
devtools: true,
#[cfg(not(debug_assertions))]
devtools: false,
zoom_hotkeys_enabled: false,
accept_first_mouse: false,
back_forward_navigation_gestures: false,
document_title_changed_handler: None,
incognito: false,
autoplay: true,
on_page_load_handler: None,
proxy_config: None,
focused: true,
bounds: Some(Rect {
position: dpi::LogicalPosition::new(0, 0).into(),
size: dpi::LogicalSize::new(200, 200).into(),
}),
}
}
}
struct WebviewBuilderParts<'a> {
attrs: WebViewAttributes<'a>,
platform_specific: PlatformSpecificWebViewAttributes,
}
pub struct WebViewBuilder<'a> {
inner: Result<WebviewBuilderParts<'a>>,
}
impl<'a> WebViewBuilder<'a> {
pub fn new() -> Self {
Self {
inner: Ok(WebviewBuilderParts {
attrs: WebViewAttributes::default(),
#[allow(clippy::default_constructed_unit_structs)]
platform_specific: PlatformSpecificWebViewAttributes::default(),
}),
}
}
pub fn with_web_context(web_context: &'a mut WebContext) -> Self {
let mut attrs = WebViewAttributes::default();
attrs.context = Some(web_context);
Self {
inner: Ok(WebviewBuilderParts {
attrs,
#[allow(clippy::default_constructed_unit_structs)]
platform_specific: PlatformSpecificWebViewAttributes::default(),
}),
}
}
pub fn with_attributes(attrs: WebViewAttributes<'a>) -> Self {
Self {
inner: Ok(WebviewBuilderParts {
attrs,
#[allow(clippy::default_constructed_unit_structs)]
platform_specific: PlatformSpecificWebViewAttributes::default(),
}),
}
}
fn and_then<F>(self, func: F) -> Self
where
F: FnOnce(WebviewBuilderParts<'a>) -> Result<WebviewBuilderParts<'a>>,
{
Self {
inner: self.inner.and_then(func),
}
}
pub fn with_id(self, id: WebViewId<'a>) -> Self {
self.and_then(|mut b| {
b.attrs.id = Some(id);
Ok(b)
})
}
pub fn with_back_forward_navigation_gestures(self, gesture: bool) -> Self {
self.and_then(|mut b| {
b.attrs.back_forward_navigation_gestures = gesture;
Ok(b)
})
}
pub fn with_transparent(self, transparent: bool) -> Self {
self.and_then(|mut b| {
b.attrs.transparent = transparent;
Ok(b)
})
}
pub fn with_background_color(self, background_color: RGBA) -> Self {
self.and_then(|mut b| {
b.attrs.background_color = Some(background_color);
Ok(b)
})
}
pub fn with_visible(self, visible: bool) -> Self {
self.and_then(|mut b| {
b.attrs.visible = visible;
Ok(b)
})
}
pub fn with_autoplay(self, autoplay: bool) -> Self {
self.and_then(|mut b| {
b.attrs.autoplay = autoplay;
Ok(b)
})
}
pub fn with_initialization_script(self, js: &str) -> Self {
self.and_then(|mut b| {
if !js.is_empty() {
b.attrs.initialization_scripts.push(js.to_string());
}
Ok(b)
})
}
#[cfg(feature = "protocol")]
pub fn with_custom_protocol<F>(self, name: String, handler: F) -> Self
where
F: Fn(WebViewId, Request<Vec<u8>>) -> Response<Cow<'static, [u8]>> + 'static,
{
self.and_then(|mut b| {
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
if let Some(context) = &mut b.attrs.context {
context.register_custom_protocol(name.clone())?;
}
if b.attrs.custom_protocols.iter().any(|(n, _)| n == &name) {
return Err(Error::DuplicateCustomProtocol(name));
}
b.attrs.custom_protocols.insert(
name,
Box::new(move |id, request, responder| {
let http_response = handler(id, request);
responder.respond(http_response);
}),
);
Ok(b)
})
}
#[cfg(feature = "protocol")]
pub fn with_asynchronous_custom_protocol<F>(self, name: String, handler: F) -> Self
where
F: Fn(WebViewId, Request<Vec<u8>>, RequestAsyncResponder) + 'static,
{
self.and_then(|mut b| {
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
if let Some(context) = &mut b.attrs.context {
context.register_custom_protocol(name.clone())?;
}
if b.attrs.custom_protocols.iter().any(|(n, _)| n == &name) {
return Err(Error::DuplicateCustomProtocol(name));
}
b.attrs.custom_protocols.insert(name, Box::new(handler));
Ok(b)
})
}
pub fn with_ipc_handler<F>(self, handler: F) -> Self
where
F: Fn(Request<String>) + 'static,
{
self.and_then(|mut b| {
b.attrs.ipc_handler = Some(Box::new(handler));
Ok(b)
})
}
#[cfg(feature = "drag-drop")]
#[cfg_attr(docsrs, doc(cfg(feature = "drag-drop")))]
pub fn with_drag_drop_handler<F>(self, handler: F) -> Self
where
F: Fn(DragDropEvent) -> bool + 'static,
{
self.and_then(|mut b| {
b.attrs.drag_drop_handler = Some(Box::new(handler));
Ok(b)
})
}
pub fn with_url_and_headers(self, url: impl Into<String>, headers: http::HeaderMap) -> Self {
self.and_then(|mut b| {
b.attrs.url = Some(url.into());
b.attrs.headers = Some(headers);
Ok(b)
})
}
pub fn with_url(self, url: impl Into<String>) -> Self {
self.and_then(|mut b| {
b.attrs.url = Some(url.into());
b.attrs.headers = None;
Ok(b)
})
}
pub fn with_headers(self, headers: http::HeaderMap) -> Self {
self.and_then(|mut b| {
b.attrs.headers = Some(headers);
Ok(b)
})
}
pub fn with_html(self, html: impl Into<String>) -> Self {
self.and_then(|mut b| {
b.attrs.html = Some(html.into());
Ok(b)
})
}
pub fn with_user_agent(self, user_agent: impl Into<String>) -> Self {
self.and_then(|mut b| {
b.attrs.user_agent = Some(user_agent.into());
Ok(b)
})
}
pub fn with_devtools(self, devtools: bool) -> Self {
self.and_then(|mut b| {
b.attrs.devtools = devtools;
Ok(b)
})
}
pub fn with_hotkeys_zoom(self, zoom: bool) -> Self {
self.and_then(|mut b| {
b.attrs.zoom_hotkeys_enabled = zoom;
Ok(b)
})
}
pub fn with_navigation_handler(self, callback: impl Fn(String) -> bool + 'static) -> Self {
self.and_then(|mut b| {
b.attrs.navigation_handler = Some(Box::new(callback));
Ok(b)
})
}
pub fn with_download_started_handler(
self,
download_started_handler: impl FnMut(String, &mut PathBuf) -> bool + 'static,
) -> Self {
self.and_then(|mut b| {
b.attrs.download_started_handler = Some(Box::new(download_started_handler));
Ok(b)
})
}
pub fn with_download_completed_handler(
self,
download_completed_handler: impl Fn(String, Option<PathBuf>, bool) + 'static,
) -> Self {
self.and_then(|mut b| {
b.attrs.download_completed_handler = Some(Rc::new(download_completed_handler));
Ok(b)
})
}
pub fn with_clipboard(self, clipboard: bool) -> Self {
self.and_then(|mut b| {
b.attrs.clipboard = clipboard;
Ok(b)
})
}
pub fn with_new_window_req_handler(self, callback: impl Fn(String) -> bool + 'static) -> Self {
self.and_then(|mut b| {
b.attrs.new_window_req_handler = Some(Box::new(callback));
Ok(b)
})
}
pub fn with_accept_first_mouse(self, accept_first_mouse: bool) -> Self {
self.and_then(|mut b| {
b.attrs.accept_first_mouse = accept_first_mouse;
Ok(b)
})
}
pub fn with_document_title_changed_handler(self, callback: impl Fn(String) + 'static) -> Self {
self.and_then(|mut b| {
b.attrs.document_title_changed_handler = Some(Box::new(callback));
Ok(b)
})
}
pub fn with_incognito(self, incognito: bool) -> Self {
self.and_then(|mut b| {
b.attrs.incognito = incognito;
Ok(b)
})
}
pub fn with_on_page_load_handler(
self,
handler: impl Fn(PageLoadEvent, String) + 'static,
) -> Self {
self.and_then(|mut b| {
b.attrs.on_page_load_handler = Some(Box::new(handler));
Ok(b)
})
}
pub fn with_proxy_config(self, configuration: ProxyConfig) -> Self {
self.and_then(|mut b| {
b.attrs.proxy_config = Some(configuration);
Ok(b)
})
}
pub fn with_focused(self, focused: bool) -> Self {
self.and_then(|mut b| {
b.attrs.focused = focused;
Ok(b)
})
}
pub fn with_bounds(self, bounds: Rect) -> Self {
self.and_then(|mut b| {
b.attrs.bounds = Some(bounds);
Ok(b)
})
}
pub fn build<W: HasWindowHandle>(self, window: &'a W) -> Result<WebView> {
let parts = self.inner?;
InnerWebView::new(window, parts.attrs, parts.platform_specific)
.map(|webview| WebView { webview })
}
pub fn build_as_child<W: HasWindowHandle>(self, window: &'a W) -> Result<WebView> {
let parts = self.inner?;
InnerWebView::new_as_child(window, parts.attrs, parts.platform_specific)
.map(|webview| WebView { webview })
}
}
#[cfg(any(target_os = "macos", target_os = "ios",))]
#[derive(Clone, Default)]
pub(crate) struct PlatformSpecificWebViewAttributes {
data_store_identifier: Option<[u8; 16]>,
}
#[cfg(any(target_os = "macos", target_os = "ios",))]
pub trait WebViewBuilderExtDarwin {
fn with_data_store_identifier(self, identifier: [u8; 16]) -> Self;
}
#[cfg(any(target_os = "macos", target_os = "ios",))]
impl WebViewBuilderExtDarwin for WebViewBuilder<'_> {
fn with_data_store_identifier(self, identifier: [u8; 16]) -> Self {
self.and_then(|mut b| {
b.platform_specific.data_store_identifier = Some(identifier);
Ok(b)
})
}
}
#[cfg(windows)]
#[derive(Clone)]
pub(crate) struct PlatformSpecificWebViewAttributes {
additional_browser_args: Option<String>,
browser_accelerator_keys: bool,
theme: Option<Theme>,
use_https: bool,
scroll_bar_style: ScrollBarStyle,
browser_extensions_enabled: bool,
}
#[cfg(windows)]
impl Default for PlatformSpecificWebViewAttributes {
fn default() -> Self {
Self {
additional_browser_args: None,
browser_accelerator_keys: true, theme: None,
use_https: false, scroll_bar_style: ScrollBarStyle::default(),
browser_extensions_enabled: false,
}
}
}
#[cfg(windows)]
pub trait WebViewBuilderExtWindows {
fn with_additional_browser_args<S: Into<String>>(self, additional_args: S) -> Self;
fn with_browser_accelerator_keys(self, enabled: bool) -> Self;
fn with_theme(self, theme: Theme) -> Self;
fn with_https_scheme(self, enabled: bool) -> Self;
fn with_scroll_bar_style(self, style: ScrollBarStyle) -> Self;
fn with_browser_extensions_enabled(self, enabled: bool) -> Self;
}
#[cfg(windows)]
impl WebViewBuilderExtWindows for WebViewBuilder<'_> {
fn with_additional_browser_args<S: Into<String>>(self, additional_args: S) -> Self {
self.and_then(|mut b| {
b.platform_specific.additional_browser_args = Some(additional_args.into());
Ok(b)
})
}
fn with_browser_accelerator_keys(self, enabled: bool) -> Self {
self.and_then(|mut b| {
b.platform_specific.browser_accelerator_keys = enabled;
Ok(b)
})
}
fn with_theme(self, theme: Theme) -> Self {
self.and_then(|mut b| {
b.platform_specific.theme = Some(theme);
Ok(b)
})
}
fn with_https_scheme(self, enabled: bool) -> Self {
self.and_then(|mut b| {
b.platform_specific.use_https = enabled;
Ok(b)
})
}
fn with_scroll_bar_style(self, style: ScrollBarStyle) -> Self {
self.and_then(|mut b| {
b.platform_specific.scroll_bar_style = style;
Ok(b)
})
}
fn with_browser_extensions_enabled(self, enabled: bool) -> Self {
self.and_then(|mut b| {
b.platform_specific.browser_extensions_enabled = enabled;
Ok(b)
})
}
}
#[cfg(target_os = "android")]
#[derive(Default)]
pub(crate) struct PlatformSpecificWebViewAttributes {
on_webview_created:
Option<Box<dyn Fn(prelude::Context) -> std::result::Result<(), jni::errors::Error> + Send>>,
with_asset_loader: bool,
asset_loader_domain: Option<String>,
https_scheme: bool,
}
#[cfg(target_os = "android")]
pub trait WebViewBuilderExtAndroid {
fn on_webview_created<
F: Fn(prelude::Context<'_, '_>) -> std::result::Result<(), jni::errors::Error> + Send + 'static,
>(
self,
f: F,
) -> Self;
#[cfg(feature = "protocol")]
fn with_asset_loader(self, protocol: String) -> Self;
fn with_https_scheme(self, enabled: bool) -> Self;
}
#[cfg(target_os = "android")]
impl WebViewBuilderExtAndroid for WebViewBuilder<'_> {
fn on_webview_created<
F: Fn(prelude::Context<'_, '_>) -> std::result::Result<(), jni::errors::Error> + Send + 'static,
>(
self,
f: F,
) -> Self {
self.and_then(|mut b| {
b.platform_specific.on_webview_created = Some(Box::new(f));
Ok(b)
})
}
#[cfg(feature = "protocol")]
fn with_asset_loader(self, protocol: String) -> Self {
self.and_then(|mut b| {
b.attrs.custom_protocols.insert(
protocol.clone(),
Box::new(|_, _, api| {
api.respond(Response::builder().body(Vec::new()).unwrap());
}),
);
b.platform_specific.with_asset_loader = true;
b.platform_specific.asset_loader_domain = Some(format!("{}.assets", protocol));
Ok(b)
})
}
fn with_https_scheme(self, enabled: bool) -> Self {
self.and_then(|mut b| {
b.platform_specific.https_scheme = enabled;
Ok(b)
})
}
}
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
pub trait WebViewBuilderExtUnix<'a> {
fn build_gtk<W>(self, widget: &'a W) -> Result<WebView>
where
W: gtk::prelude::IsA<gtk::Container>;
}
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
impl<'a> WebViewBuilderExtUnix<'a> for WebViewBuilder<'a> {
fn build_gtk<W>(self, widget: &'a W) -> Result<WebView>
where
W: gtk::prelude::IsA<gtk::Container>,
{
let parts = self.inner?;
InnerWebView::new_gtk(widget, parts.attrs, parts.platform_specific)
.map(|webview| WebView { webview })
}
}
pub struct WebView {
webview: InnerWebView,
}
impl WebView {
pub fn new(window: &impl HasWindowHandle, attrs: WebViewAttributes) -> Result<Self> {
WebViewBuilder::with_attributes(attrs).build(window)
}
pub fn new_as_child(parent: &impl HasWindowHandle, attrs: WebViewAttributes) -> Result<Self> {
WebViewBuilder::with_attributes(attrs).build_as_child(parent)
}
pub fn id(&self) -> WebViewId {
self.webview.id()
}
pub fn url(&self) -> Result<String> {
self.webview.url()
}
pub fn evaluate_script(&self, js: &str) -> Result<()> {
self
.webview
.eval(js, None::<Box<dyn Fn(String) + Send + 'static>>)
}
pub fn evaluate_script_with_callback(
&self,
js: &str,
callback: impl Fn(String) + Send + 'static,
) -> Result<()> {
self.webview.eval(js, Some(callback))
}
pub fn print(&self) -> Result<()> {
self.webview.print()
}
#[cfg(any(debug_assertions, feature = "devtools"))]
pub fn open_devtools(&self) {
self.webview.open_devtools()
}
#[cfg(any(debug_assertions, feature = "devtools"))]
pub fn close_devtools(&self) {
self.webview.close_devtools()
}
#[cfg(any(debug_assertions, feature = "devtools"))]
pub fn is_devtools_open(&self) -> bool {
self.webview.is_devtools_open()
}
pub fn zoom(&self, scale_factor: f64) -> Result<()> {
self.webview.zoom(scale_factor)
}
pub fn set_background_color(&self, background_color: RGBA) -> Result<()> {
self.webview.set_background_color(background_color)
}
pub fn load_url(&self, url: &str) -> Result<()> {
self.webview.load_url(url)
}
pub fn load_url_with_headers(&self, url: &str, headers: http::HeaderMap) -> Result<()> {
self.webview.load_url_with_headers(url, headers)
}
pub fn load_html(&self, html: &str) -> Result<()> {
self.webview.load_html(html)
}
pub fn clear_all_browsing_data(&self) -> Result<()> {
self.webview.clear_all_browsing_data()
}
pub fn bounds(&self) -> Result<Rect> {
self.webview.bounds()
}
pub fn set_bounds(&self, bounds: Rect) -> Result<()> {
self.webview.set_bounds(bounds)
}
pub fn set_visible(&self, visible: bool) -> Result<()> {
self.webview.set_visible(visible)
}
pub fn focus(&self) -> Result<()> {
self.webview.focus()
}
pub fn focus_parent(&self) -> Result<()> {
self.webview.focus_parent()
}
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum DragDropEvent {
Enter {
paths: Vec<PathBuf>,
position: (i32, i32),
},
Over {
position: (i32, i32),
},
Drop {
paths: Vec<PathBuf>,
position: (i32, i32),
},
Leave,
}
pub fn webview_version() -> Result<String> {
platform_webview_version()
}
#[cfg(target_os = "windows")]
#[non_exhaustive]
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MemoryUsageLevel {
#[default]
Normal,
Low,
}
#[cfg(target_os = "windows")]
pub trait WebViewExtWindows {
fn controller(&self) -> ICoreWebView2Controller;
fn set_theme(&self, theme: Theme) -> Result<()>;
fn set_memory_usage_level(&self, level: MemoryUsageLevel) -> Result<()>;
fn reparent(&self, hwnd: isize) -> Result<()>;
}
#[cfg(target_os = "windows")]
impl WebViewExtWindows for WebView {
fn controller(&self) -> ICoreWebView2Controller {
self.webview.controller.clone()
}
fn set_theme(&self, theme: Theme) -> Result<()> {
self.webview.set_theme(theme)
}
fn set_memory_usage_level(&self, level: MemoryUsageLevel) -> Result<()> {
self.webview.set_memory_usage_level(level)
}
fn reparent(&self, hwnd: isize) -> Result<()> {
self.webview.reparent(hwnd)
}
}
#[cfg(gtk)]
pub trait WebViewExtUnix: Sized {
fn new_gtk<W>(widget: &W) -> Result<Self>
where
W: gtk::prelude::IsA<gtk::Container>;
fn webview(&self) -> webkit2gtk::WebView;
fn reparent<W>(&self, widget: &W) -> Result<()>
where
W: gtk::prelude::IsA<gtk::Container>;
}
#[cfg(gtk)]
impl WebViewExtUnix for WebView {
fn new_gtk<W>(widget: &W) -> Result<Self>
where
W: gtk::prelude::IsA<gtk::Container>,
{
WebViewBuilder::new().build_gtk(widget)
}
fn webview(&self) -> webkit2gtk::WebView {
self.webview.webview.clone()
}
fn reparent<W>(&self, widget: &W) -> Result<()>
where
W: gtk::prelude::IsA<gtk::Container>,
{
self.webview.reparent(widget)
}
}
#[cfg(target_os = "macos")]
pub trait WebViewExtMacOS {
fn webview(&self) -> Retained<WryWebView>;
fn manager(&self) -> Retained<WKUserContentController>;
fn ns_window(&self) -> Retained<NSWindow>;
fn reparent(&self, window: *mut NSWindow) -> Result<()>;
fn print_with_options(&self, options: &PrintOptions) -> Result<()>;
}
#[cfg(target_os = "macos")]
impl WebViewExtMacOS for WebView {
fn webview(&self) -> Retained<WryWebView> {
self.webview.webview.clone()
}
fn manager(&self) -> Retained<WKUserContentController> {
self.webview.manager.clone()
}
fn ns_window(&self) -> Retained<NSWindow> {
self.webview.webview.window().unwrap().clone()
}
fn reparent(&self, window: *mut NSWindow) -> Result<()> {
self.webview.reparent(window)
}
fn print_with_options(&self, options: &PrintOptions) -> Result<()> {
self.webview.print_with_options(options)
}
}
#[cfg(target_os = "ios")]
pub trait WebViewExtIOS {
fn webview(&self) -> Retained<WryWebView>;
fn manager(&self) -> Retained<WKUserContentController>;
}
#[cfg(target_os = "ios")]
impl WebViewExtIOS for WebView {
fn webview(&self) -> Retained<WryWebView> {
self.webview.webview.clone()
}
fn manager(&self) -> Retained<WKUserContentController> {
self.webview.manager.clone()
}
}
#[cfg(target_os = "android")]
pub trait WebViewExtAndroid {
fn handle(&self) -> JniHandle;
}
#[cfg(target_os = "android")]
impl WebViewExtAndroid for WebView {
fn handle(&self) -> JniHandle {
JniHandle
}
}
#[derive(Debug, Clone, Copy)]
pub enum Theme {
Dark,
Light,
Auto,
}
pub type RGBA = (u8, u8, u8, u8);
pub enum PageLoadEvent {
Started,
Finished,
}
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
#[derive(Default)]
pub(crate) struct PlatformSpecificWebViewAttributes;
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg_attr(miri, ignore)]
fn should_get_webview_version() {
if let Err(error) = webview_version() {
panic!("{}", error);
}
}
}