From 8b7a9e4a9122f90e9fc1ba7d3d5abbebe556c8bb Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 13 May 2021 17:19:41 -0700 Subject: [PATCH 01/44] Add `Application` back, require it for `WebviewBuilder` Linux only so far. Until further notice, this entire branch is going to only work on Linux until I can decide on a good interface to expose WebDriver stuff. `Application` makes it so that multiple windows can share a single WebContext and UserContentManager (data directory). This is required for WebDriver because only a single `WebContext` is allowed to be marked to allow automation. It seems that macOS and Windows have similar limitations to some extent. Only the multi_window example has been updated so far. --- Cargo.toml | 1 + examples/multi_window.rs | 6 ++-- src/application/mod.rs | 68 ++++++++++++++++++++++++++++++++++++++++ src/webview/linux/mod.rs | 42 +++++++++---------------- src/webview/mod.rs | 24 ++++++-------- 5 files changed, 97 insertions(+), 44 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index de16aa563..2d48a9bd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ url = "2.2" image = "0.23" infer = "0.4" tao = { version = "0.2", default-features = false, features = [ "serde" ] } +uuid = { version = "0.8.2", features = [ "v4" ] } [target."cfg(target_os = \"linux\")".dependencies] webkit2gtk = { version = "0.11", features = [ "v2_10" ] } diff --git a/examples/multi_window.rs b/examples/multi_window.rs index eb7c4b60b..076ece79f 100644 --- a/examples/multi_window.rs +++ b/examples/multi_window.rs @@ -17,6 +17,7 @@ struct MessageParameters { fn main() -> wry::Result<()> { use wry::{ application::{ + Application, dpi::PhysicalSize, event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, @@ -26,6 +27,7 @@ fn main() -> wry::Result<()> { }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window1 = WindowBuilder::new().build(&event_loop).unwrap(); let (window_tx, window_rx) = std::sync::mpsc::channel::(); @@ -41,7 +43,7 @@ fn main() -> wry::Result<()> { }; let id = window1.id(); - let webview1 = WebViewBuilder::new(window1) + let webview1 = WebViewBuilder::new(window1, &application) .unwrap() .with_url("https://tauri.studio")? .with_initialization_script( @@ -67,7 +69,7 @@ fn main() -> wry::Result<()> { .build(&event_loop) .unwrap(); let id = window2.id(); - let webview2 = WebViewBuilder::new(window2) + let webview2 = WebViewBuilder::new(window2, &application) .unwrap() .with_url(&url) .unwrap() diff --git a/src/application/mod.rs b/src/application/mod.rs index 80751a03c..6f9159e4a 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -9,4 +9,72 @@ //! //! [tao]: https://crates.io/crates/tao +use std::path::PathBuf; pub use tao::*; + +/// A single browser context. +/// +/// Think of this like a browser session. Incognito mode would be a single context even though +/// it has multiple tab/windows. +pub struct Application { + inner: ApplicationInner, +} + +impl Application { + pub fn new(data_directory: Option) -> Self { + Self { + inner: ApplicationInner::new(data_directory), + } + } +} + +#[cfg(target_os = "linux")] +use self::gtk::{ApplicationGtkExt, ApplicationInner}; + +#[cfg(target_os = "linux")] +pub(crate) mod gtk { + use std::path::PathBuf; + use webkit2gtk::{WebContext, WebContextBuilder, WebsiteDataManagerBuilder}; + + pub struct ApplicationInner { + context: WebContext, + } + + impl ApplicationInner { + pub fn new(data_directory: Option) -> Self { + let mut context_builder = WebContextBuilder::new(); + if let Some(data_directory) = data_directory { + let data_manager = WebsiteDataManagerBuilder::new() + .local_storage_directory( + &data_directory + .join("localstorage") + .to_string_lossy() + .into_owned(), + ) + .indexeddb_directory( + &data_directory + .join("databases") + .join("indexeddb") + .to_string_lossy() + .into_owned(), + ) + .build(); + context_builder = context_builder.website_data_manager(&data_manager); + } + + Self { + context: context_builder.build(), + } + } + } + + pub trait ApplicationGtkExt { + fn context(&self) -> &WebContext; + } + + impl ApplicationGtkExt for super::Application { + fn context(&self) -> &WebContext { + &self.inner.context + } + } +} diff --git a/src/webview/linux/mod.rs b/src/webview/linux/mod.rs index f975209fc..baab63cbc 100644 --- a/src/webview/linux/mod.rs +++ b/src/webview/linux/mod.rs @@ -9,6 +9,7 @@ use gio::Cancellable; use glib::{signal::Inhibit, Bytes, Cast, FileError}; use gtk::{BoxExt, ContainerExt, WidgetExt}; use url::Url; +use uuid::Uuid; use webkit2gtk::{ SecurityManagerExt, SettingsExt, URISchemeRequestExt, UserContentInjectedFrames, UserContentManager, UserContentManagerExt, UserScript, UserScriptInjectionTime, @@ -20,7 +21,7 @@ use webkit2gtk_sys::{ }; use crate::{ - application::{platform::unix::*, window::Window}, + application::{gtk::ApplicationGtkExt, platform::unix::*, window::Window, Application}, webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse}, Error, Result, }; @@ -33,6 +34,7 @@ pub struct InnerWebView { impl InnerWebView { pub fn new( + application: &Application, window: Rc, scripts: Vec, url: Option, @@ -43,42 +45,23 @@ impl InnerWebView { )>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, - data_directory: Option, ) -> Result { + let id = Uuid::new_v4().to_string(); let window_rc = Rc::clone(&window); let window = &window.gtk_window(); + // Webview widget let manager = UserContentManager::new(); - let mut context_builder = WebContextBuilder::new(); - if let Some(data_directory) = data_directory { - let data_manager = WebsiteDataManagerBuilder::new() - .local_storage_directory( - &data_directory - .join("localstorage") - .to_string_lossy() - .into_owned(), - ) - .indexeddb_directory( - &data_directory - .join("databases") - .join("indexeddb") - .to_string_lossy() - .into_owned(), - ) - .build(); - context_builder = context_builder.website_data_manager(&data_manager); - } - let context = context_builder.build(); - + let context = application.context(); let webview = Rc::new(WebView::new_with_context_and_user_content_manager( - &context, &manager, + context, &manager, )); // Message handler let wv = Rc::clone(&webview); let w = window_rc.clone(); - manager.register_script_message_handler("external"); - manager.connect_script_message_received(move |_m, msg| { + manager.register_script_message_handler(&id); + manager.connect_script_message_received(move |m2, msg| { if let (Some(js), Some(context)) = (msg.get_value(), msg.get_global_context()) { if let Some(js) = js.to_string(&context) { if let Some(rpc_handler) = rpc_handler.as_ref() { @@ -167,8 +150,13 @@ impl InnerWebView { let w = Self { webview }; + let mut init = String::with_capacity(67 + 36 + 20); + init.push_str("window.external={invoke:function(x){window.webkit.messageHandlers[\""); + init.push_str(&id); + init.push_str("\"].postMessage(x);}}"); + // Initialize scripts - w.init("window.external={invoke:function(x){window.webkit.messageHandlers.external.postMessage(x);}}")?; + w.init(&init)?; for js in scripts { w.init(&js)?; } diff --git a/src/webview/mod.rs b/src/webview/mod.rs index f46646811..6124df48b 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -44,6 +44,7 @@ use crate::application::window::Window; #[cfg(target_os = "windows")] #[cfg(feature = "winrt")] use windows_webview2::Windows::Win32::WindowsAndMessaging::HWND; +use crate::application::Application; // Helper so all platforms handle RPC messages consistently. fn rpc_proxy( @@ -81,7 +82,8 @@ fn rpc_proxy( /// [`WebViewBuilder`] / [`WebView`] are the basic building blocks to constrcut WebView contents and /// scripts for those who prefer to control fine grained window creation and event handling. /// [`WebViewBuilder`] privides ability to setup initialization before web engine starts. -pub struct WebViewBuilder { +pub struct WebViewBuilder<'a> { + application: &'a Application, transparent: bool, tx: Sender, rx: Receiver, @@ -91,15 +93,15 @@ pub struct WebViewBuilder { custom_protocols: Vec<(String, Box Result>>)>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, - data_directory: Option, } -impl WebViewBuilder { +impl<'a> WebViewBuilder<'a> { /// Create [`WebViewBuilder`] from provided [`Window`]. - pub fn new(window: Window) -> Result { + pub fn new(window: Window, application: &'a Application) -> Result { let (tx, rx) = channel(); Ok(Self { + application, tx, rx, initialization_scripts: vec![], @@ -109,7 +111,6 @@ impl WebViewBuilder { custom_protocols: vec![], rpc_handler: None, file_drop_handler: None, - data_directory: None, }) } @@ -128,13 +129,6 @@ impl WebViewBuilder { self } - /// Whether the WebView window should have a custom user data path. This is usefull in Windows - /// when a bundled application can't have the webview data inside `Program Files`. - pub fn with_data_directory(mut self, data_directory: PathBuf) -> Self { - self.data_directory.replace(data_directory); - self - } - /// Create a [`Dispatcher`] to send evaluation scripts to the WebView. [`WebView`] is not thread /// safe because it must be run on the main thread who creates it. [`Dispatcher`] can let you /// send the scripts from other threads. @@ -255,6 +249,7 @@ impl WebViewBuilder { pub fn build(self) -> Result { let window = Rc::new(self.window); let webview = InnerWebView::new( + self.application, window.clone(), self.initialization_scripts, self.url, @@ -262,7 +257,6 @@ impl WebViewBuilder { self.custom_protocols, self.rpc_handler, self.file_drop_handler, - self.data_directory, )?; Ok(WebView { window, @@ -315,8 +309,8 @@ impl WebView { /// called in the same thread with the [`EventLoop`] you create. /// /// [`EventLoop`]: crate::application::event_loop::EventLoop - pub fn new(window: Window) -> Result { - WebViewBuilder::new(window)?.build() + pub fn new(window: Window, application: &Application) -> Result { + WebViewBuilder::new(window, application)?.build() } /// Dispatch javascript code to be evaluated later. Note this will not actually run the From 790061e9b328eb35a428ca3f2b3cf2fdaf175583 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 13 May 2021 22:10:50 -0700 Subject: [PATCH 02/44] Create automated webviews from webdriver clients again, linux only for now. updated detect_js_ecma example also --- Cargo.toml | 2 +- examples/detect_js_ecma.rs | 5 ++++- src/application/mod.rs | 19 ++++++++++++++----- src/webview/linux/mod.rs | 31 ++++++++++++++++++++++--------- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2d48a9bd8..0f597838f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ tao = { version = "0.2", default-features = false, features = [ "serde" ] } uuid = { version = "0.8.2", features = [ "v4" ] } [target."cfg(target_os = \"linux\")".dependencies] -webkit2gtk = { version = "0.11", features = [ "v2_10" ] } +webkit2gtk = { version = "0.11", features = [ "v2_18" ] } webkit2gtk-sys = "0.13.0" gio = "0.9" glib = "0.10" diff --git a/examples/detect_js_ecma.rs b/examples/detect_js_ecma.rs index a0c6517c0..b45542b60 100644 --- a/examples/detect_js_ecma.rs +++ b/examples/detect_js_ecma.rs @@ -2,6 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +use wry::application::Application; + fn main() -> wry::Result<()> { use wry::{ application::{ @@ -17,7 +19,8 @@ fn main() -> wry::Result<()> { .with_title("Detect ECMAScript") .build(&event_loop) .unwrap(); - let _webview = WebViewBuilder::new(window) + let app = Application::new(None); + let _webview = WebViewBuilder::new(window, &app) .unwrap() .with_initialization_script( r#" diff --git a/src/application/mod.rs b/src/application/mod.rs index 6f9159e4a..7b64c7698 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -29,12 +29,17 @@ impl Application { } #[cfg(target_os = "linux")] -use self::gtk::{ApplicationGtkExt, ApplicationInner}; +use self::gtk::{ApplicationInner}; + #[cfg(target_os = "linux")] pub(crate) mod gtk { + use std::env::var; use std::path::PathBuf; - use webkit2gtk::{WebContext, WebContextBuilder, WebsiteDataManagerBuilder}; + use webkit2gtk::{ + AutomationSessionBuilder, AutomationSessionExt, UserContentManager, + WebContext, WebContextBuilder, WebContextExt, WebViewExtManual, WebsiteDataManagerBuilder, + }; pub struct ApplicationInner { context: WebContext, @@ -62,9 +67,13 @@ pub(crate) mod gtk { context_builder = context_builder.website_data_manager(&data_manager); } - Self { - context: context_builder.build(), - } + let context = context_builder.build(); + + let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("1"); + dbg!(automation); + context.set_automation_allowed(automation); + + Self { context } } } diff --git a/src/webview/linux/mod.rs b/src/webview/linux/mod.rs index baab63cbc..fe998f576 100644 --- a/src/webview/linux/mod.rs +++ b/src/webview/linux/mod.rs @@ -10,12 +10,7 @@ use glib::{signal::Inhibit, Bytes, Cast, FileError}; use gtk::{BoxExt, ContainerExt, WidgetExt}; use url::Url; use uuid::Uuid; -use webkit2gtk::{ - SecurityManagerExt, SettingsExt, URISchemeRequestExt, UserContentInjectedFrames, - UserContentManager, UserContentManagerExt, UserScript, UserScriptInjectionTime, - WebContextBuilder, WebContextExt, WebView, WebViewExt, WebViewExtManual, - WebsiteDataManagerBuilder, -}; +use webkit2gtk::{ApplicationInfo, AutomationSessionExt, SecurityManagerExt, SettingsExt, URISchemeRequestExt, UserContentInjectedFrames, UserContentManager, UserContentManagerExt, UserScript, UserScriptInjectionTime, WebContextBuilder, WebContextExt, WebView, WebViewExt, WebViewExtManual, WebsiteDataManagerBuilder, WebViewBuilder}; use webkit2gtk_sys::{ webkit_get_major_version, webkit_get_micro_version, webkit_get_minor_version, }; @@ -25,6 +20,7 @@ use crate::{ webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse}, Error, Result, }; +use std::env::var; mod file_drop; @@ -53,11 +49,28 @@ impl InnerWebView { // Webview widget let manager = UserContentManager::new(); let context = application.context(); - let webview = Rc::new(WebView::new_with_context_and_user_content_manager( - context, &manager, - )); + + let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("1"); + let mut webview = WebViewBuilder::new(); + webview = webview.web_context(context); + webview = webview.user_content_manager(&manager); + webview = webview.is_controlled_by_automation(automation); + let webview = webview.build(); + + let auto_webview = webview.clone(); + context.connect_automation_started(move |_, auto| { + let webview = auto_webview.clone(); + let app_into = ApplicationInfo::new(); + app_into.set_name("wry"); + app_into.set_version(0, 9, 0); + auto.set_application_info(&app_into); + auto.connect_create_web_view(move |auto| { + webview.clone() + }); + }); // Message handler + let webview = Rc::new(webview); let wv = Rc::clone(&webview); let w = window_rc.clone(); manager.register_script_message_handler(&id); From c6ae772d7b945fa7cbffe3157f9c7ab99d507bfb Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 13 May 2021 22:11:16 -0700 Subject: [PATCH 03/44] cargo +nightly fmt --- examples/multi_window.rs | 2 +- src/application/mod.rs | 10 ++++------ src/webview/linux/mod.rs | 11 +++++++---- src/webview/mod.rs | 3 +-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/multi_window.rs b/examples/multi_window.rs index 076ece79f..6aeb79f2e 100644 --- a/examples/multi_window.rs +++ b/examples/multi_window.rs @@ -17,11 +17,11 @@ struct MessageParameters { fn main() -> wry::Result<()> { use wry::{ application::{ - Application, dpi::PhysicalSize, event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, + Application, }, webview::{RpcRequest, WebViewBuilder}, }; diff --git a/src/application/mod.rs b/src/application/mod.rs index 7b64c7698..a5540e860 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -29,16 +29,14 @@ impl Application { } #[cfg(target_os = "linux")] -use self::gtk::{ApplicationInner}; - +use self::gtk::ApplicationInner; #[cfg(target_os = "linux")] pub(crate) mod gtk { - use std::env::var; - use std::path::PathBuf; + use std::{env::var, path::PathBuf}; use webkit2gtk::{ - AutomationSessionBuilder, AutomationSessionExt, UserContentManager, - WebContext, WebContextBuilder, WebContextExt, WebViewExtManual, WebsiteDataManagerBuilder, + AutomationSessionBuilder, AutomationSessionExt, UserContentManager, WebContext, + WebContextBuilder, WebContextExt, WebViewExtManual, WebsiteDataManagerBuilder, }; pub struct ApplicationInner { diff --git a/src/webview/linux/mod.rs b/src/webview/linux/mod.rs index fe998f576..ddd2dfe97 100644 --- a/src/webview/linux/mod.rs +++ b/src/webview/linux/mod.rs @@ -10,7 +10,12 @@ use glib::{signal::Inhibit, Bytes, Cast, FileError}; use gtk::{BoxExt, ContainerExt, WidgetExt}; use url::Url; use uuid::Uuid; -use webkit2gtk::{ApplicationInfo, AutomationSessionExt, SecurityManagerExt, SettingsExt, URISchemeRequestExt, UserContentInjectedFrames, UserContentManager, UserContentManagerExt, UserScript, UserScriptInjectionTime, WebContextBuilder, WebContextExt, WebView, WebViewExt, WebViewExtManual, WebsiteDataManagerBuilder, WebViewBuilder}; +use webkit2gtk::{ + ApplicationInfo, AutomationSessionExt, SecurityManagerExt, SettingsExt, URISchemeRequestExt, + UserContentInjectedFrames, UserContentManager, UserContentManagerExt, UserScript, + UserScriptInjectionTime, WebContextBuilder, WebContextExt, WebView, WebViewBuilder, WebViewExt, + WebViewExtManual, WebsiteDataManagerBuilder, +}; use webkit2gtk_sys::{ webkit_get_major_version, webkit_get_micro_version, webkit_get_minor_version, }; @@ -64,9 +69,7 @@ impl InnerWebView { app_into.set_name("wry"); app_into.set_version(0, 9, 0); auto.set_application_info(&app_into); - auto.connect_create_web_view(move |auto| { - webview.clone() - }); + auto.connect_create_web_view(move |auto| webview.clone()); }); // Message handler diff --git a/src/webview/mod.rs b/src/webview/mod.rs index 6124df48b..9a31a7755 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -40,11 +40,10 @@ use url::Url; #[cfg(target_os = "windows")] use crate::application::platform::windows::WindowExtWindows; -use crate::application::window::Window; +use crate::application::{window::Window, Application}; #[cfg(target_os = "windows")] #[cfg(feature = "winrt")] use windows_webview2::Windows::Win32::WindowsAndMessaging::HWND; -use crate::application::Application; // Helper so all platforms handle RPC messages consistently. fn rpc_proxy( From aae8a7aa23227fa94a13ae37cff6212d68fb428a Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 14 May 2021 19:40:55 -0700 Subject: [PATCH 04/44] update env var value for automation --- src/application/mod.rs | 2 +- src/webview/linux/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/application/mod.rs b/src/application/mod.rs index a5540e860..325770dba 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -67,7 +67,7 @@ pub(crate) mod gtk { let context = context_builder.build(); - let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("1"); + let automation = dbg!(var("TAURI_AUTOMATION_MODE")).as_deref() == Ok("TRUE"); dbg!(automation); context.set_automation_allowed(automation); diff --git a/src/webview/linux/mod.rs b/src/webview/linux/mod.rs index ddd2dfe97..7acdd5203 100644 --- a/src/webview/linux/mod.rs +++ b/src/webview/linux/mod.rs @@ -55,7 +55,7 @@ impl InnerWebView { let manager = UserContentManager::new(); let context = application.context(); - let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("1"); + let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("TRUE"); let mut webview = WebViewBuilder::new(); webview = webview.web_context(context); webview = webview.user_content_manager(&manager); From fba16ba37c78fd7dfb27ccadbc32576eb85b671d Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Mon, 17 May 2021 23:25:42 -0700 Subject: [PATCH 05/44] allow closing the window from the webdriver client --- src/application/mod.rs | 19 ++++++++++++------- src/webview/linux/mod.rs | 22 ++++++++++++---------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/application/mod.rs b/src/application/mod.rs index 325770dba..8d98dadf8 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -34,13 +34,11 @@ use self::gtk::ApplicationInner; #[cfg(target_os = "linux")] pub(crate) mod gtk { use std::{env::var, path::PathBuf}; - use webkit2gtk::{ - AutomationSessionBuilder, AutomationSessionExt, UserContentManager, WebContext, - WebContextBuilder, WebContextExt, WebViewExtManual, WebsiteDataManagerBuilder, - }; + use webkit2gtk::{WebContext, WebContextBuilder, WebContextExt, WebsiteDataManagerBuilder}; pub struct ApplicationInner { context: WebContext, + automation: bool, } impl ApplicationInner { @@ -67,21 +65,28 @@ pub(crate) mod gtk { let context = context_builder.build(); - let automation = dbg!(var("TAURI_AUTOMATION_MODE")).as_deref() == Ok("TRUE"); - dbg!(automation); + let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("TRUE"); context.set_automation_allowed(automation); - Self { context } + Self { + context, + automation, + } } } pub trait ApplicationGtkExt { fn context(&self) -> &WebContext; + fn is_automated(&self) -> bool; } impl ApplicationGtkExt for super::Application { fn context(&self) -> &WebContext { &self.inner.context } + + fn is_automated(&self) -> bool { + self.inner.automation + } } } diff --git a/src/webview/linux/mod.rs b/src/webview/linux/mod.rs index 7acdd5203..d5087091e 100644 --- a/src/webview/linux/mod.rs +++ b/src/webview/linux/mod.rs @@ -2,19 +2,18 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use std::{path::PathBuf, rc::Rc}; - use gdk::{WindowEdge, WindowExt, RGBA}; use gio::Cancellable; use glib::{signal::Inhibit, Bytes, Cast, FileError}; -use gtk::{BoxExt, ContainerExt, WidgetExt}; +use gtk::{BoxExt, ContainerExt, GtkWindowExt, WidgetExt}; +use std::rc::Rc; use url::Url; use uuid::Uuid; use webkit2gtk::{ ApplicationInfo, AutomationSessionExt, SecurityManagerExt, SettingsExt, URISchemeRequestExt, UserContentInjectedFrames, UserContentManager, UserContentManagerExt, UserScript, - UserScriptInjectionTime, WebContextBuilder, WebContextExt, WebView, WebViewBuilder, WebViewExt, - WebViewExtManual, WebsiteDataManagerBuilder, + UserScriptInjectionTime, WebContextExt, WebView, WebViewBuilder, WebViewExt, + }; use webkit2gtk_sys::{ webkit_get_major_version, webkit_get_micro_version, webkit_get_minor_version, @@ -25,7 +24,6 @@ use crate::{ webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse}, Error, Result, }; -use std::env::var; mod file_drop; @@ -55,11 +53,10 @@ impl InnerWebView { let manager = UserContentManager::new(); let context = application.context(); - let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("TRUE"); let mut webview = WebViewBuilder::new(); webview = webview.web_context(context); webview = webview.user_content_manager(&manager); - webview = webview.is_controlled_by_automation(automation); + webview = webview.is_controlled_by_automation(application.is_automated()); let webview = webview.build(); let auto_webview = webview.clone(); @@ -69,7 +66,7 @@ impl InnerWebView { app_into.set_name("wry"); app_into.set_version(0, 9, 0); auto.set_application_info(&app_into); - auto.connect_create_web_view(move |auto| webview.clone()); + auto.connect_create_web_view(move |_| webview.clone()); }); // Message handler @@ -77,7 +74,7 @@ impl InnerWebView { let wv = Rc::clone(&webview); let w = window_rc.clone(); manager.register_script_message_handler(&id); - manager.connect_script_message_received(move |m2, msg| { + manager.connect_script_message_received(move |_, msg| { if let (Some(js), Some(context)) = (msg.get_value(), msg.get_global_context()) { if let Some(js) = js.to_string(&context) { if let Some(rpc_handler) = rpc_handler.as_ref() { @@ -97,6 +94,11 @@ impl InnerWebView { } }); + let close_window = window_rc.clone(); + webview.connect_close(move |_| { + close_window.gtk_window().close(); + }); + webview.connect_button_press_event(|webview, event| { if event.get_button() == 1 { let (cx, cy) = event.get_root(); From 1909ba04a53247a51daaf71ffdb24b9402533954 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Tue, 18 May 2021 22:42:32 -0700 Subject: [PATCH 06/44] add support for win32 windows --- src/application/mod.rs | 49 +++++++++++++++++++++++++++++++++++++--- src/webview/linux/mod.rs | 2 +- src/webview/win32/mod.rs | 27 +++++++++++++++------- src/webview/winrt/mod.rs | 8 +++++-- 4 files changed, 72 insertions(+), 14 deletions(-) diff --git a/src/application/mod.rs b/src/application/mod.rs index 8d98dadf8..54ddcf142 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -26,11 +26,18 @@ impl Application { inner: ApplicationInner::new(data_directory), } } + + pub fn is_automated(&self) -> bool { + self.inner.is_automated() + } } #[cfg(target_os = "linux")] use self::gtk::ApplicationInner; +#[cfg(target_os = "windows")] +use self::windows::ApplicationInner; + #[cfg(target_os = "linux")] pub(crate) mod gtk { use std::{env::var, path::PathBuf}; @@ -73,20 +80,56 @@ pub(crate) mod gtk { automation, } } + + pub fn is_automated(&self) -> bool { + self.automation + } } pub trait ApplicationGtkExt { fn context(&self) -> &WebContext; - fn is_automated(&self) -> bool; } impl ApplicationGtkExt for super::Application { fn context(&self) -> &WebContext { &self.inner.context } + } +} + +#[cfg(target_os = "windows")] +pub(crate) mod windows { + use std::{ + env::var, + path::{Path, PathBuf}, + }; + + pub struct ApplicationInner { + data_directory: Option, + automation: bool, + } + + impl ApplicationInner { + pub fn new(data_directory: Option) -> Self { + let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("TRUE"); + Self { + data_directory, + automation, + } + } + + pub fn is_automated(&self) -> bool { + self.automation + } + } + + pub trait ApplicationWinExt { + fn data_directory(&self) -> Option<&Path>; + } - fn is_automated(&self) -> bool { - self.inner.automation + impl ApplicationWinExt for super::Application { + fn data_directory(&self) -> Option<&Path> { + self.inner.data_directory.as_deref() } } } diff --git a/src/webview/linux/mod.rs b/src/webview/linux/mod.rs index d5087091e..4616af1ad 100644 --- a/src/webview/linux/mod.rs +++ b/src/webview/linux/mod.rs @@ -13,7 +13,6 @@ use webkit2gtk::{ ApplicationInfo, AutomationSessionExt, SecurityManagerExt, SettingsExt, URISchemeRequestExt, UserContentInjectedFrames, UserContentManager, UserContentManagerExt, UserScript, UserScriptInjectionTime, WebContextExt, WebView, WebViewBuilder, WebViewExt, - }; use webkit2gtk_sys::{ webkit_get_major_version, webkit_get_micro_version, webkit_get_minor_version, @@ -94,6 +93,7 @@ impl InnerWebView { } }); + // todo: is this leaking memory when having programs longer than window close? let close_window = window_rc.clone(); webview.connect_close(move |_| { close_window.gtk_window().close(); diff --git a/src/webview/win32/mod.rs b/src/webview/win32/mod.rs index da76fdafc..f3f6bad91 100644 --- a/src/webview/win32/mod.rs +++ b/src/webview/win32/mod.rs @@ -11,17 +11,22 @@ use crate::{ use file_drop::FileDropController; -use std::{collections::HashSet, os::raw::c_void, path::PathBuf, rc::Rc}; +use std::{collections::HashSet, os::raw::c_void, rc::Rc}; use once_cell::unsync::OnceCell; use url::Url; use webview2::{Controller, PermissionKind, PermissionState, WebView}; -use winapi::{shared::windef::HWND, um::winuser::GetClientRect}; +use winapi::{ + shared::{windef::HWND, winerror::E_FAIL}, + um::winuser::{DestroyWindow, GetClientRect}, +}; use crate::application::{ event_loop::{ControlFlow, EventLoop}, platform::{run_return::EventLoopExtRunReturn, windows::WindowExtWindows}, window::Window, + windows::ApplicationWinExt, + Application, }; pub struct InnerWebView { @@ -35,6 +40,7 @@ pub struct InnerWebView { impl InnerWebView { pub fn new( + application: &Application, window: Rc, scripts: Vec, url: Option, @@ -45,7 +51,6 @@ impl InnerWebView { )>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, - data_directory: Option, ) -> Result { let hwnd = window.hwnd() as HWND; @@ -56,12 +61,9 @@ impl InnerWebView { let file_drop_controller_clone = file_drop_controller.clone(); let webview_builder: webview2::EnvironmentBuilder; - let data_directory_provided: PathBuf; - if let Some(data_directory) = data_directory { - data_directory_provided = data_directory; - webview_builder = - webview2::EnvironmentBuilder::new().with_user_data_folder(&data_directory_provided); + if let Some(data_directory) = application.data_directory() { + webview_builder = webview2::EnvironmentBuilder::new().with_user_data_folder(&data_directory); } else { webview_builder = webview2::EnvironmentBuilder::new(); } @@ -74,6 +76,15 @@ impl InnerWebView { let controller = controller?; let w = controller.get_webview()?; + // todo: is this leaking memory when having programs longer than window close? + w.add_window_close_requested(move |_| { + if unsafe { DestroyWindow(hwnd as HWND) } != 0 { + Ok(()) + } else { + Err(webview2::Error::new(E_FAIL)) + } + })?; + // Transparent if transparent { if let Ok(c2) = controller.get_controller2() { diff --git a/src/webview/winrt/mod.rs b/src/webview/winrt/mod.rs index 6cc8f8ac1..d00dc6b26 100644 --- a/src/webview/winrt/mod.rs +++ b/src/webview/winrt/mod.rs @@ -37,6 +37,8 @@ use crate::application::{ event_loop::{ControlFlow, EventLoop}, platform::{run_return::EventLoopExtRunReturn, windows::WindowExtWindows}, window::Window, + windows::ApplicationWinExt, + Application, }; pub struct InnerWebView { @@ -51,6 +53,7 @@ pub struct InnerWebView { impl InnerWebView { pub fn new( + application: &Application, window: Rc, scripts: Vec, url: Option, @@ -63,7 +66,6 @@ impl InnerWebView { )>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, - data_directory: Option, ) -> Result { let hwnd = HWND(window.hwnd() as _); @@ -71,7 +73,7 @@ impl InnerWebView { let webview_rc: Rc> = Rc::new(OnceCell::new()); let file_drop_controller_rc: Rc> = Rc::new(OnceCell::new()); - let env = wait_for_async_operation(match data_directory { + let env = wait_for_async_operation(match application.data_directory() { Some(data_directory_provided) => webview2::CoreWebView2Environment::CreateWithOptionsAsync( "", data_directory_provided.to_str().unwrap_or(""), @@ -106,6 +108,8 @@ impl InnerWebView { })?; } + // TODO: close window upon request like win32 add_window_close_requested + // Initialize scripts wait_for_async_operation(w.AddScriptToExecuteOnDocumentCreatedAsync( "window.external={invoke:s=>window.chrome.webview.postMessage(s)}", From 6486d5063562e8f6da995bbbffac0e2514e9a05a Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 20 May 2021 14:41:51 -0700 Subject: [PATCH 07/44] add wry::Application support to macOS --- src/application/mod.rs | 23 +++++++++++++++++++++++ src/webview/macos/mod.rs | 5 ++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/application/mod.rs b/src/application/mod.rs index 54ddcf142..1aa3cf44b 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -38,6 +38,9 @@ use self::gtk::ApplicationInner; #[cfg(target_os = "windows")] use self::windows::ApplicationInner; +#[cfg(target_os = "macos")] +use self::macos::ApplicationInner; + #[cfg(target_os = "linux")] pub(crate) mod gtk { use std::{env::var, path::PathBuf}; @@ -133,3 +136,23 @@ pub(crate) mod windows { } } } + +#[cfg(target_os = "macos")] +pub(crate) mod macos { + use std::{env::var, path::PathBuf}; + + pub struct ApplicationInner { + automation: bool, + } + + impl ApplicationInner { + pub fn new(_data_directory: Option) -> Self { + let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("TRUE"); + Self { automation } + } + + pub fn is_automated(&self) -> bool { + self.automation + } + } +} diff --git a/src/webview/macos/mod.rs b/src/webview/macos/mod.rs index a4f0f4740..c53f8735d 100644 --- a/src/webview/macos/mod.rs +++ b/src/webview/macos/mod.rs @@ -5,7 +5,6 @@ use std::{ ffi::{c_void, CStr}, os::raw::c_char, - path::PathBuf, ptr::{null, null_mut}, rc::Rc, slice, str, @@ -26,7 +25,7 @@ use url::Url; use file_drop::{add_file_drop_methods, set_file_drop_handler}; use crate::{ - application::{platform::macos::WindowExtMacOS, window::Window}, + application::{platform::macos::WindowExtMacOS, window::Window, Application}, webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse}, Result, }; @@ -47,6 +46,7 @@ pub struct InnerWebView { impl InnerWebView { pub fn new( + _application: &Application, window: Rc, scripts: Vec, url: Option, @@ -57,7 +57,6 @@ impl InnerWebView { )>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, - _data_directory: Option, ) -> Result { // Function for rpc handler extern "C" fn did_receive(this: &Object, _: Sel, _: id, msg: id) { From 2b6a8effe87079684a74ef74429a52bf0b96a008 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 20 May 2021 15:48:34 -0700 Subject: [PATCH 08/44] change how ApplicationExt work to match std --- Cargo.toml | 1 + src/application/mod.rs | 71 ++++++++++++++++++++-------------------- src/lib.rs | 2 ++ src/webview/linux/mod.rs | 4 +-- src/webview/win32/mod.rs | 2 +- 5 files changed, 41 insertions(+), 39 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0f597838f..d8f24b526 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ categories = [ "gui" ] [package.metadata.docs.rs] features = [ "dox" ] +rustdoc-args = [ "--cfg", "doc_cfg" ] default-target = "x86_64-unknown-linux-gnu" targets = [ "x86_64-pc-windows-msvc", diff --git a/src/application/mod.rs b/src/application/mod.rs index 1aa3cf44b..a9804a832 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -9,7 +9,6 @@ //! //! [tao]: https://crates.io/crates/tao -use std::path::PathBuf; pub use tao::*; /// A single browser context. @@ -21,19 +20,15 @@ pub struct Application { } impl Application { - pub fn new(data_directory: Option) -> Self { + pub fn new(data_directory: Option) -> Self { Self { inner: ApplicationInner::new(data_directory), } } - - pub fn is_automated(&self) -> bool { - self.inner.is_automated() - } } #[cfg(target_os = "linux")] -use self::gtk::ApplicationInner; +use self::unix::ApplicationInner; #[cfg(target_os = "windows")] use self::windows::ApplicationInner; @@ -42,11 +37,13 @@ use self::windows::ApplicationInner; use self::macos::ApplicationInner; #[cfg(target_os = "linux")] -pub(crate) mod gtk { - use std::{env::var, path::PathBuf}; - use webkit2gtk::{WebContext, WebContextBuilder, WebContextExt, WebsiteDataManagerBuilder}; +#[cfg_attr(doc_cfg, doc(cfg(target_os = "linux")))] +pub mod unix { + //! Unix platform extensions for [`Application`](super::Application). + use std::{path::PathBuf}; + use webkit2gtk::{WebContext, WebContextBuilder, WebsiteDataManagerBuilder}; - pub struct ApplicationInner { + pub(crate) struct ApplicationInner { context: WebContext, automation: bool, } @@ -73,34 +70,44 @@ pub(crate) mod gtk { context_builder = context_builder.website_data_manager(&data_manager); } - let context = context_builder.build(); - - let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("TRUE"); - context.set_automation_allowed(automation); - Self { - context, - automation, + context: context_builder.build(), + automation: true, } } - - pub fn is_automated(&self) -> bool { - self.automation - } } - pub trait ApplicationGtkExt { + /// [`Application`](super::Application) items that only matter on unix. + pub trait ApplicationExt { + /// The context of all webviews opened. fn context(&self) -> &WebContext; + + /// If the context allows automation. + /// + /// **Note:** `libwebkit2gtk` only allows 1 automation context at a time. + fn allows_automation(&self) -> bool; + + /// Set if this context allows automation (default: `true`). + fn set_automation_mode(&mut self, flag: bool); } - impl ApplicationGtkExt for super::Application { + impl ApplicationExt for super::Application { fn context(&self) -> &WebContext { &self.inner.context } + + fn allows_automation(&self) -> bool { + self.inner.automation + } + + fn set_automation_mode(&mut self, flag: bool) { + self.inner.automation = flag; + } } } #[cfg(target_os = "windows")] +#[cfg_attr(doc_cfg, doc(cfg(target_os = "windows")))] pub(crate) mod windows { use std::{ env::var, @@ -109,28 +116,23 @@ pub(crate) mod windows { pub struct ApplicationInner { data_directory: Option, - automation: bool, } impl ApplicationInner { pub fn new(data_directory: Option) -> Self { - let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("TRUE"); Self { data_directory, automation, } } - - pub fn is_automated(&self) -> bool { - self.automation - } } - pub trait ApplicationWinExt { + /// [`Application`](super::Application) items that only matter on windows. + pub trait ApplicationExt { fn data_directory(&self) -> Option<&Path>; } - impl ApplicationWinExt for super::Application { + impl ApplicationExt for super::Application { fn data_directory(&self) -> Option<&Path> { self.inner.data_directory.as_deref() } @@ -138,6 +140,7 @@ pub(crate) mod windows { } #[cfg(target_os = "macos")] +#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))] pub(crate) mod macos { use std::{env::var, path::PathBuf}; @@ -150,9 +153,5 @@ pub(crate) mod macos { let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("TRUE"); Self { automation } } - - pub fn is_automated(&self) -> bool { - self.automation - } } } diff --git a/src/lib.rs b/src/lib.rs index 7f25124e9..b7a118ba0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,6 +80,8 @@ //! [`with_file_drop_handler`]: crate::webview::WebView::with_file_drop_handler //! [`with_custom_protocol`]: crate::webview::WebView::with_custom_protocol +#![cfg_attr(doc_cfg, feature(doc_cfg))] + #![allow(clippy::new_without_default)] #![allow(clippy::wrong_self_convention)] #![allow(clippy::too_many_arguments)] diff --git a/src/webview/linux/mod.rs b/src/webview/linux/mod.rs index 4616af1ad..867fa8707 100644 --- a/src/webview/linux/mod.rs +++ b/src/webview/linux/mod.rs @@ -19,7 +19,7 @@ use webkit2gtk_sys::{ }; use crate::{ - application::{gtk::ApplicationGtkExt, platform::unix::*, window::Window, Application}, + application::{unix::ApplicationExt, platform::unix::*, window::Window, Application}, webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse}, Error, Result, }; @@ -55,7 +55,7 @@ impl InnerWebView { let mut webview = WebViewBuilder::new(); webview = webview.web_context(context); webview = webview.user_content_manager(&manager); - webview = webview.is_controlled_by_automation(application.is_automated()); + webview = webview.is_controlled_by_automation(application.allows_automation()); let webview = webview.build(); let auto_webview = webview.clone(); diff --git a/src/webview/win32/mod.rs b/src/webview/win32/mod.rs index f3f6bad91..75f134c74 100644 --- a/src/webview/win32/mod.rs +++ b/src/webview/win32/mod.rs @@ -25,7 +25,7 @@ use crate::application::{ event_loop::{ControlFlow, EventLoop}, platform::{run_return::EventLoopExtRunReturn, windows::WindowExtWindows}, window::Window, - windows::ApplicationWinExt, + windows::ApplicationExt, Application, }; From 79a703f425c53a7f294c2d60aabf4484115f796e Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 20 May 2021 15:48:43 -0700 Subject: [PATCH 09/44] update all examples to use wry::Application --- examples/custom_data_directory.rs | 5 +++-- examples/custom_protocol.rs | 4 +++- examples/custom_titlebar.rs | 4 +++- examples/detect_js_ecma.rs | 4 ++-- examples/dragndrop.rs | 4 +++- examples/fullscreen.rs | 4 +++- examples/hello_world.rs | 4 +++- examples/html_test.rs | 4 +++- examples/menu_bar.rs | 7 ++++++- examples/rpc.rs | 4 +++- examples/system_tray.rs | 4 +++- examples/transparent.rs | 4 +++- 12 files changed, 38 insertions(+), 14 deletions(-) diff --git a/examples/custom_data_directory.rs b/examples/custom_data_directory.rs index 0bcd76a33..3a470c668 100644 --- a/examples/custom_data_directory.rs +++ b/examples/custom_data_directory.rs @@ -10,6 +10,7 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, + Application }, webview::WebViewBuilder, }; @@ -24,14 +25,14 @@ fn main() -> wry::Result<()> { println!("Webview storage path: {:#?}", &test_path); let event_loop = EventLoop::new(); + let application = Application::new(Some(test_path)); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop) .unwrap(); - let _webview = WebViewBuilder::new(window) + let _webview = WebViewBuilder::new(window, &application) .unwrap() .with_url("https://tauri.studio")? - .with_data_directory(test_path) .build()?; event_loop.run(move |event, _, control_flow| { diff --git a/examples/custom_protocol.rs b/examples/custom_protocol.rs index 434bb3545..cfe737686 100644 --- a/examples/custom_protocol.rs +++ b/examples/custom_protocol.rs @@ -8,17 +8,19 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, + Application }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop) .unwrap(); - let _webview = WebViewBuilder::new(window) + let _webview = WebViewBuilder::new(window, &application) .unwrap() .with_custom_protocol("wry.dev".into(), move |_, requested_asset_path| { // remove the protocol from the path for easiest match diff --git a/examples/custom_titlebar.rs b/examples/custom_titlebar.rs index c07323605..63d8cefcd 100644 --- a/examples/custom_titlebar.rs +++ b/examples/custom_titlebar.rs @@ -8,11 +8,13 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, + Application }, webview::{RpcRequest, WebViewBuilder}, }; let event_loop = EventLoop::new(); + let application = Application::new(None); let mut webviews = std::collections::HashMap::new(); let window = WindowBuilder::new() .with_decorations(false) @@ -114,7 +116,7 @@ fn main() -> wry::Result<()> { None }; - let webview = WebViewBuilder::new(window) + let webview = WebViewBuilder::new(window, &application) .unwrap() .with_url(url)? .with_initialization_script(script) diff --git a/examples/detect_js_ecma.rs b/examples/detect_js_ecma.rs index b45542b60..f2d346896 100644 --- a/examples/detect_js_ecma.rs +++ b/examples/detect_js_ecma.rs @@ -15,12 +15,12 @@ fn main() -> wry::Result<()> { }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new() .with_title("Detect ECMAScript") .build(&event_loop) .unwrap(); - let app = Application::new(None); - let _webview = WebViewBuilder::new(window, &app) + let _webview = WebViewBuilder::new(window, &application) .unwrap() .with_initialization_script( r#" diff --git a/examples/dragndrop.rs b/examples/dragndrop.rs index 5ff3231fc..92d9ad400 100644 --- a/examples/dragndrop.rs +++ b/examples/dragndrop.rs @@ -14,13 +14,15 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, + Application }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new().build(&event_loop).unwrap(); - let webview = WebViewBuilder::new(window) + let webview = WebViewBuilder::new(window, &application) .unwrap() .with_url(HTML)? .with_file_drop_handler(|_, data| { diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index f3b6c3900..292713dda 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -8,17 +8,19 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Fullscreen, WindowBuilder}, + Application }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new() .with_title("3D Render Test") .with_fullscreen(Some(Fullscreen::Borderless(None))) .build(&event_loop) .unwrap(); - let webview = WebViewBuilder::new(window) + let webview = WebViewBuilder::new(window, &application) .unwrap() .with_url("https://www.wirple.com/")? .build()?; diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 5187154ee..f6662dfc3 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -8,15 +8,17 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, + Application }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop)?; - let _webview = WebViewBuilder::new(window)? + let _webview = WebViewBuilder::new(window, &application)? .with_url("https://tauri.studio")? .build()?; diff --git a/examples/html_test.rs b/examples/html_test.rs index 195f5376b..1d751e0c3 100644 --- a/examples/html_test.rs +++ b/examples/html_test.rs @@ -8,15 +8,17 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, + Application }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop)?; - let _webview = WebViewBuilder::new(window)? + let _webview = WebViewBuilder::new(window, &application)? .with_url("https://html5test.com")? .build()?; diff --git a/examples/menu_bar.rs b/examples/menu_bar.rs index 2189f7569..1a8b285dd 100644 --- a/examples/menu_bar.rs +++ b/examples/menu_bar.rs @@ -9,6 +9,7 @@ fn main() -> wry::Result<()> { event_loop::{ControlFlow, EventLoop}, menu::{Menu, MenuItem, MenuType}, window::WindowBuilder, + Application }, webview::WebViewBuilder, }; @@ -84,13 +85,17 @@ fn main() -> wry::Result<()> { // Build our event loop let event_loop = EventLoop::new(); + + // Build our application context + let application = Application::new(None); + // Build the window let window = WindowBuilder::new() .with_title("Hello World") .with_menu(menu) .build(&event_loop)?; // Build the webview - let webview = WebViewBuilder::new(window)? + let webview = WebViewBuilder::new(window, &application)? .with_url("https://tauri.studio")? .build()?; // launch WRY process diff --git a/examples/rpc.rs b/examples/rpc.rs index e8d884ad8..d50230f2d 100644 --- a/examples/rpc.rs +++ b/examples/rpc.rs @@ -16,11 +16,13 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Fullscreen, Window, WindowBuilder}, + Application }, webview::{RpcRequest, RpcResponse, WebViewBuilder}, }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new().build(&event_loop).unwrap(); let url = r#"data:text/html, @@ -76,7 +78,7 @@ async function getAsyncRpcResult() { response }; - let webview = WebViewBuilder::new(window) + let webview = WebViewBuilder::new(window, &application) .unwrap() .with_url(url)? .with_rpc_handler(handler) diff --git a/examples/system_tray.rs b/examples/system_tray.rs index d2bc91a21..df4301bfd 100644 --- a/examples/system_tray.rs +++ b/examples/system_tray.rs @@ -13,12 +13,14 @@ fn main() -> wry::Result<()> { menu::{MenuItem, MenuType}, platform::system_tray::SystemTrayBuilder, window::Window, + Application }, webview::WebViewBuilder, }; // Build our event loop let event_loop = EventLoop::new(); + let application = Application::new(None); let mut webviews = HashMap::new(); // Create sample menu item @@ -61,7 +63,7 @@ fn main() -> wry::Result<()> { if menu_id == open_new_window_id { let window = Window::new(&event_loop).unwrap(); let id = window.id(); - let webview = WebViewBuilder::new(window) + let webview = WebViewBuilder::new(window, &application) .unwrap() .with_url("https://tauri.studio") .unwrap() diff --git a/examples/transparent.rs b/examples/transparent.rs index 8d62b8196..4d039cc59 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -8,11 +8,13 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, + Application }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new() .with_decorations(false) // There are actually three layer of background color when creating webview window. @@ -21,7 +23,7 @@ fn main() -> wry::Result<()> { .build(&event_loop) .unwrap(); - let webview = WebViewBuilder::new(window)? + let webview = WebViewBuilder::new(window, &application)? // The second is on webview... .with_transparent(true) // And the last is in html. From f14453796298a6f667486cfcec9247f1a14ef641 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 20 May 2021 16:16:39 -0700 Subject: [PATCH 10/44] remove now unneeded uuid dependency --- Cargo.toml | 1 - src/webview/linux/mod.rs | 13 +++---------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 353f6e21c..42a6c7371 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,6 @@ thiserror = "1.0" url = "2.2" infer = "0.4" tao = { version = "0.2.6", default-features = false, features = [ "serde" ] } -uuid = { version = "0.8.2", features = [ "v4" ] } [dev-dependencies] anyhow = "1.0.40" diff --git a/src/webview/linux/mod.rs b/src/webview/linux/mod.rs index a5e2fd0f7..15471cdfa 100644 --- a/src/webview/linux/mod.rs +++ b/src/webview/linux/mod.rs @@ -8,7 +8,6 @@ use glib::{signal::Inhibit, Bytes, Cast, FileError}; use gtk::{BoxExt, ContainerExt, GtkWindowExt, WidgetExt}; use std::rc::Rc; use url::Url; -use uuid::Uuid; use webkit2gtk::{ ApplicationInfo, AutomationSessionExt, SecurityManagerExt, SettingsExt, URISchemeRequestExt, UserContentInjectedFrames, UserContentManager, UserContentManagerExt, UserScript, @@ -44,7 +43,6 @@ impl InnerWebView { rpc_handler: Option Option>>, file_drop_handler: Option bool>>, ) -> Result { - let id = Uuid::new_v4().to_string(); let window_rc = Rc::clone(&window); let window = &window.gtk_window(); @@ -72,8 +70,8 @@ impl InnerWebView { let webview = Rc::new(webview); let wv = Rc::clone(&webview); let w = window_rc.clone(); - manager.register_script_message_handler(&id); - manager.connect_script_message_received(move |_, msg| { + manager.register_script_message_handler("external"); + manager.connect_script_message_received(move |_m, msg| { if let (Some(js), Some(context)) = (msg.get_value(), msg.get_global_context()) { if let Some(js) = js.to_string(&context) { if let Some(rpc_handler) = rpc_handler.as_ref() { @@ -165,13 +163,8 @@ impl InnerWebView { let w = Self { webview }; - let mut init = String::with_capacity(67 + 36 + 20); - init.push_str("window.external={invoke:function(x){window.webkit.messageHandlers[\""); - init.push_str(&id); - init.push_str("\"].postMessage(x);}}"); - // Initialize scripts - w.init(&init)?; + w.init("window.external={invoke:function(x){window.webkit.messageHandlers.external.postMessage(x);}}")?; for js in scripts { w.init(&js)?; } From 0ea87fe2857daa8a225ca7ea7bede557603a89d6 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 20 May 2021 16:17:43 -0700 Subject: [PATCH 11/44] add webdriver support to new example --- examples/validate_webview.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/validate_webview.rs b/examples/validate_webview.rs index fd98644b6..50f333af5 100644 --- a/examples/validate_webview.rs +++ b/examples/validate_webview.rs @@ -8,6 +8,7 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, + Application, }, webview::{webview_version, WebViewBuilder}, }; @@ -21,10 +22,11 @@ fn main() -> wry::Result<()> { ); let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop)?; - let _webview = WebViewBuilder::new(window)? + let _webview = WebViewBuilder::new(window, &application)? .with_url("https://tauri.studio")? .build()?; From 95fcd28566ce2cbe137859da80800dbda6711b8c Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 20 May 2021 16:18:22 -0700 Subject: [PATCH 12/44] cargo +nightly fmt --- examples/custom_data_directory.rs | 2 +- examples/custom_protocol.rs | 2 +- examples/custom_titlebar.rs | 2 +- examples/dragndrop.rs | 2 +- examples/fullscreen.rs | 2 +- examples/hello_world.rs | 2 +- examples/html_test.rs | 2 +- examples/menu_bar.rs | 2 +- examples/rpc.rs | 2 +- examples/system_tray.rs | 2 +- examples/transparent.rs | 2 +- src/application/mod.rs | 4 ++-- src/lib.rs | 1 - src/webview/linux/mod.rs | 2 +- 14 files changed, 14 insertions(+), 15 deletions(-) diff --git a/examples/custom_data_directory.rs b/examples/custom_data_directory.rs index 3a470c668..334ecc35b 100644 --- a/examples/custom_data_directory.rs +++ b/examples/custom_data_directory.rs @@ -10,7 +10,7 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application + Application, }, webview::WebViewBuilder, }; diff --git a/examples/custom_protocol.rs b/examples/custom_protocol.rs index cfe737686..cbad56baf 100644 --- a/examples/custom_protocol.rs +++ b/examples/custom_protocol.rs @@ -8,7 +8,7 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application + Application, }, webview::WebViewBuilder, }; diff --git a/examples/custom_titlebar.rs b/examples/custom_titlebar.rs index 63d8cefcd..2ab1e232f 100644 --- a/examples/custom_titlebar.rs +++ b/examples/custom_titlebar.rs @@ -8,7 +8,7 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, - Application + Application, }, webview::{RpcRequest, WebViewBuilder}, }; diff --git a/examples/dragndrop.rs b/examples/dragndrop.rs index 92d9ad400..d60e33e62 100644 --- a/examples/dragndrop.rs +++ b/examples/dragndrop.rs @@ -14,7 +14,7 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application + Application, }, webview::WebViewBuilder, }; diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index 292713dda..3ae0f80b6 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -8,7 +8,7 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Fullscreen, WindowBuilder}, - Application + Application, }, webview::WebViewBuilder, }; diff --git a/examples/hello_world.rs b/examples/hello_world.rs index f6662dfc3..0470f42b3 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -8,7 +8,7 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application + Application, }, webview::WebViewBuilder, }; diff --git a/examples/html_test.rs b/examples/html_test.rs index 1d751e0c3..083de4785 100644 --- a/examples/html_test.rs +++ b/examples/html_test.rs @@ -8,7 +8,7 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application + Application, }, webview::WebViewBuilder, }; diff --git a/examples/menu_bar.rs b/examples/menu_bar.rs index 1a8b285dd..ea42e25a3 100644 --- a/examples/menu_bar.rs +++ b/examples/menu_bar.rs @@ -9,7 +9,7 @@ fn main() -> wry::Result<()> { event_loop::{ControlFlow, EventLoop}, menu::{Menu, MenuItem, MenuType}, window::WindowBuilder, - Application + Application, }, webview::WebViewBuilder, }; diff --git a/examples/rpc.rs b/examples/rpc.rs index d50230f2d..d26d2b8a2 100644 --- a/examples/rpc.rs +++ b/examples/rpc.rs @@ -16,7 +16,7 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Fullscreen, Window, WindowBuilder}, - Application + Application, }, webview::{RpcRequest, RpcResponse, WebViewBuilder}, }; diff --git a/examples/system_tray.rs b/examples/system_tray.rs index df4301bfd..0c8fe14a6 100644 --- a/examples/system_tray.rs +++ b/examples/system_tray.rs @@ -13,7 +13,7 @@ fn main() -> wry::Result<()> { menu::{MenuItem, MenuType}, platform::system_tray::SystemTrayBuilder, window::Window, - Application + Application, }, webview::WebViewBuilder, }; diff --git a/examples/transparent.rs b/examples/transparent.rs index 4d039cc59..681a570c1 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -8,7 +8,7 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application + Application, }, webview::WebViewBuilder, }; diff --git a/src/application/mod.rs b/src/application/mod.rs index a9804a832..e5fa703af 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -40,8 +40,8 @@ use self::macos::ApplicationInner; #[cfg_attr(doc_cfg, doc(cfg(target_os = "linux")))] pub mod unix { //! Unix platform extensions for [`Application`](super::Application). - use std::{path::PathBuf}; - use webkit2gtk::{WebContext, WebContextBuilder, WebsiteDataManagerBuilder}; + use std::path::PathBuf; + use webkit2gtk::{WebContext, WebContextBuilder, WebsiteDataManagerBuilder}; pub(crate) struct ApplicationInner { context: WebContext, diff --git a/src/lib.rs b/src/lib.rs index 8f973edde..ea7737fb7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,7 +78,6 @@ //! [`with_custom_protocol`]: crate::webview::WebView::with_custom_protocol #![cfg_attr(doc_cfg, feature(doc_cfg))] - #![allow(clippy::new_without_default)] #![allow(clippy::wrong_self_convention)] #![allow(clippy::too_many_arguments)] diff --git a/src/webview/linux/mod.rs b/src/webview/linux/mod.rs index 15471cdfa..b4f50973a 100644 --- a/src/webview/linux/mod.rs +++ b/src/webview/linux/mod.rs @@ -18,7 +18,7 @@ use webkit2gtk_sys::{ }; use crate::{ - application::{unix::ApplicationExt, platform::unix::*, window::Window, Application}, + application::{platform::unix::*, unix::ApplicationExt, window::Window, Application}, webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse}, Error, Result, }; From c7491cb4bf7a912c22f5cc7884501e2e507b34ea Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 20 May 2021 16:19:51 -0700 Subject: [PATCH 13/44] remove automation flag from mac/win ApplicationInner --- src/application/mod.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/application/mod.rs b/src/application/mod.rs index e5fa703af..bdcbfba35 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -122,7 +122,6 @@ pub(crate) mod windows { pub fn new(data_directory: Option) -> Self { Self { data_directory, - automation, } } } @@ -142,16 +141,13 @@ pub(crate) mod windows { #[cfg(target_os = "macos")] #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))] pub(crate) mod macos { - use std::{env::var, path::PathBuf}; + use std::path::PathBuf; - pub struct ApplicationInner { - automation: bool, - } + pub struct ApplicationInner; impl ApplicationInner { pub fn new(_data_directory: Option) -> Self { - let automation = var("TAURI_AUTOMATION_MODE").as_deref() == Ok("TRUE"); - Self { automation } + Self } } } From cc7281dce6cd4a0d0aab3e629f08f058cbe05724 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 20 May 2021 16:25:05 -0700 Subject: [PATCH 14/44] allow dead_code in Application inner field is there a better proper fix? probably - but we will be redoing this interface soon I imagine. --- src/application/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/application/mod.rs b/src/application/mod.rs index bdcbfba35..8ea604bd0 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -16,6 +16,7 @@ pub use tao::*; /// Think of this like a browser session. Incognito mode would be a single context even though /// it has multiple tab/windows. pub struct Application { + #[allow(dead_code)] inner: ApplicationInner, } From 588e3ae96fc505ac660d1e5365d9ee2af580c438 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 20 May 2021 16:28:16 -0700 Subject: [PATCH 15/44] cargo +nightly fmt --- src/application/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/application/mod.rs b/src/application/mod.rs index 8ea604bd0..bff8cafbe 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -121,9 +121,7 @@ pub(crate) mod windows { impl ApplicationInner { pub fn new(data_directory: Option) -> Self { - Self { - data_directory, - } + Self { data_directory } } } From 90187d2150ad0e4167497315bdf7188488cfdc1a Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 20 May 2021 16:44:13 -0700 Subject: [PATCH 16/44] update all WebviewBuilder::new calls --- README.md | 4 +++- bench/tests/src/cpu_intensive.rs | 4 +++- bench/tests/src/custom_protocol.rs | 4 +++- bench/tests/src/hello_world.rs | 4 +++- src/lib.rs | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d9c801389..76c171b4e 100644 --- a/README.md +++ b/README.md @@ -32,15 +32,17 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, + Application, }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop)?; - let _webview = WebViewBuilder::new(window)? + let _webview = WebViewBuilder::new(window, &application)? .with_url("https://tauri.studio")? .build()?; diff --git a/bench/tests/src/cpu_intensive.rs b/bench/tests/src/cpu_intensive.rs index 2389e12c6..6aa722a52 100644 --- a/bench/tests/src/cpu_intensive.rs +++ b/bench/tests/src/cpu_intensive.rs @@ -10,11 +10,13 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, + Application }, webview::{RpcRequest, WebViewBuilder}, }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new().build(&event_loop).unwrap(); let handler = |_window: &Window, req: RpcRequest| { @@ -23,7 +25,7 @@ fn main() -> wry::Result<()> { } None }; - let webview = WebViewBuilder::new(window) + let webview = WebViewBuilder::new(window, &application) .unwrap() .with_custom_protocol("wry.bench".into(), move |_, requested_asset_path| { let requested_asset_path = requested_asset_path.replace("wry.bench://", ""); diff --git a/bench/tests/src/custom_protocol.rs b/bench/tests/src/custom_protocol.rs index 2a3826921..6d1403013 100644 --- a/bench/tests/src/custom_protocol.rs +++ b/bench/tests/src/custom_protocol.rs @@ -16,11 +16,13 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, + Application }, webview::{RpcRequest, WebViewBuilder}, }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new().build(&event_loop).unwrap(); let handler = |_window: &Window, req: RpcRequest| { @@ -29,7 +31,7 @@ fn main() -> wry::Result<()> { } None }; - let webview = WebViewBuilder::new(window) + let webview = WebViewBuilder::new(window, &application) .unwrap() .with_rpc_handler(handler) .with_custom_protocol("wry.bench".into(), move |_, _| { diff --git a/bench/tests/src/hello_world.rs b/bench/tests/src/hello_world.rs index 624762ea0..2b228edc9 100644 --- a/bench/tests/src/hello_world.rs +++ b/bench/tests/src/hello_world.rs @@ -16,11 +16,13 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, + Application }, webview::{RpcRequest, WebViewBuilder}, }; let event_loop = EventLoop::new(); + let application = Application::new(None); let window = WindowBuilder::new().build(&event_loop).unwrap(); let url = r#"data:text/html, @@ -37,7 +39,7 @@ fn main() -> wry::Result<()> { } None }; - let webview = WebViewBuilder::new(window) + let webview = WebViewBuilder::new(window, &application) .unwrap() .with_url(url)? .with_rpc_handler(handler) diff --git a/src/lib.rs b/src/lib.rs index ea7737fb7..f9fc40a86 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,15 +16,17 @@ //! event::{Event, StartCause, WindowEvent}, //! event_loop::{ControlFlow, EventLoop}, //! window::WindowBuilder, +//! Application //! }, //! webview::WebViewBuilder, //! }; //! //! let event_loop = EventLoop::new(); +//! let application = Application::new(None); //! let window = WindowBuilder::new() //! .with_title("Hello World") //! .build(&event_loop)?; -//! let _webview = WebViewBuilder::new(window)? +//! let _webview = WebViewBuilder::new(window, &application)? //! .with_url("https://tauri.studio")? //! .build()?; //! From 2bf9aac9a76a07a35cb8166fbcb4ff77325cc0a8 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Thu, 20 May 2021 16:49:06 -0700 Subject: [PATCH 17/44] cargo +nightly fmt --- bench/tests/src/cpu_intensive.rs | 2 +- bench/tests/src/custom_protocol.rs | 2 +- bench/tests/src/hello_world.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bench/tests/src/cpu_intensive.rs b/bench/tests/src/cpu_intensive.rs index 6aa722a52..7b3b10496 100644 --- a/bench/tests/src/cpu_intensive.rs +++ b/bench/tests/src/cpu_intensive.rs @@ -10,7 +10,7 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, - Application + Application, }, webview::{RpcRequest, WebViewBuilder}, }; diff --git a/bench/tests/src/custom_protocol.rs b/bench/tests/src/custom_protocol.rs index 6d1403013..cd6ce3b4f 100644 --- a/bench/tests/src/custom_protocol.rs +++ b/bench/tests/src/custom_protocol.rs @@ -16,7 +16,7 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, - Application + Application, }, webview::{RpcRequest, WebViewBuilder}, }; diff --git a/bench/tests/src/hello_world.rs b/bench/tests/src/hello_world.rs index 2b228edc9..be165e081 100644 --- a/bench/tests/src/hello_world.rs +++ b/bench/tests/src/hello_world.rs @@ -16,7 +16,7 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, - Application + Application, }, webview::{RpcRequest, WebViewBuilder}, }; From 201e4dc73a3b8b847795ac301f6e6863f5ea4e17 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Wed, 2 Jun 2021 06:40:51 -0700 Subject: [PATCH 18/44] super builder --- examples/detect_js_ecma.rs | 22 +-- examples/multi_window.rs | 33 ++--- src/lib.rs | 293 +++++++++++++++++++++++++++++++++++++ src/webview/mod.rs | 22 ++- 4 files changed, 323 insertions(+), 47 deletions(-) diff --git a/examples/detect_js_ecma.rs b/examples/detect_js_ecma.rs index f2d346896..2ac5bd3fa 100644 --- a/examples/detect_js_ecma.rs +++ b/examples/detect_js_ecma.rs @@ -11,19 +11,12 @@ fn main() -> wry::Result<()> { event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, }, - webview::WebViewBuilder, }; - let event_loop = EventLoop::new(); let application = Application::new(None); - let window = WindowBuilder::new() - .with_title("Detect ECMAScript") - .build(&event_loop) - .unwrap(); - let _webview = WebViewBuilder::new(window, &application) - .unwrap() - .with_initialization_script( - r#" + let _webview = wry::Builder::new() + .title("Detect ECMAScript") + .initialization_script(r#" (function () { window.addEventListener('DOMContentLoaded', (event) => { @@ -107,7 +100,7 @@ fn main() -> wry::Result<()> { for (var j = 0; j < versionDetails.features.length; j++) { var feature = versionDetails.features[j]; tableElement.innerHTML += ` ${feature.name} ${feature.supported ? '✔' : '❌'} ` - if (!feature.supported) versionSupported = false; + if (!feature.supported) versionSupported = false; } summaryListElement.innerHTML += `
  • ${versionDetails.version}: ${versionSupported ? '✔' : '❌'}` } @@ -115,8 +108,8 @@ fn main() -> wry::Result<()> { }); })(); "#) - .with_url( - r#"data:text/html, + .url( + r#"data:text/html,

    ECMAScript support list:

    @@ -130,8 +123,7 @@ fn main() -> wry::Result<()> { "#, - )? - .build()?; + )?.build(&application)?; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/multi_window.rs b/examples/multi_window.rs index 6aeb79f2e..3c6aceaf6 100644 --- a/examples/multi_window.rs +++ b/examples/multi_window.rs @@ -23,12 +23,11 @@ fn main() -> wry::Result<()> { window::{Window, WindowBuilder}, Application, }, - webview::{RpcRequest, WebViewBuilder}, + webview::RpcRequest, }; let event_loop = EventLoop::new(); let application = Application::new(None); - let window1 = WindowBuilder::new().build(&event_loop).unwrap(); let (window_tx, window_rx) = std::sync::mpsc::channel::(); let handler = move |_window: &Window, req: RpcRequest| { @@ -42,17 +41,17 @@ fn main() -> wry::Result<()> { None }; - let id = window1.id(); - let webview1 = WebViewBuilder::new(window1, &application) - .unwrap() - .with_url("https://tauri.studio")? - .with_initialization_script( + let webview1 = wry::Builder::new(&event_loop) + .url("https://tauri.studio")? + .initialization_script( r#"async function openWindow() { await window.rpc.notify("openWindow", "https://i.imgur.com/x6tXcr9.gif"); }"#, ) - .with_rpc_handler(handler) - .build()?; + .rpc_handler(handler) + .build(&application)?; + let id = webview1.window().id(); + let mut webviews = HashMap::new(); webviews.insert(id, webview1); @@ -63,18 +62,14 @@ fn main() -> wry::Result<()> { *control_flow = ControlFlow::Wait; if let Ok(url) = window_rx.try_recv() { - let window2 = WindowBuilder::new() - .with_title("RODA RORA DA") - .with_inner_size(PhysicalSize::new(426, 197)) - .build(&event_loop) - .unwrap(); - let id = window2.id(); - let webview2 = WebViewBuilder::new(window2, &application) - .unwrap() - .with_url(&url) + let webview2 = wry::Builder::new(&event_loop) + .title("RODA RORA DA") + .inner_size(PhysicalSize::new(426, 197)) + .url(&url) .unwrap() - .build() + .build(&application) .unwrap(); + let id = webview2.window().id(); webviews.insert(id, webview2); } else if trigger && instant.elapsed() >= eight_secs { webviews diff --git a/src/lib.rs b/src/lib.rs index f9fc40a86..92041be79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -152,3 +152,296 @@ pub enum Error { #[error(transparent)] WebView2Error(#[from] webview2::Error), } + +use crate::{ + application::{ + window::{Window, WindowBuilder}, + Application, + }, + webview::{Dispatcher, WebViewBuilder}, + webview::{FileDropEvent, RpcRequest, RpcResponse, WebView}, +}; + +use tao::{ + dpi::{Position, Size}, + event_loop::EventLoopWindowTarget, + menu::Menu, + window::{Fullscreen, Icon}, +}; + +macro_rules! window_builder { + ( + $(#[$meta:meta])+ + method => $method:ident, + original => $original:ident, + $( + arg => $arg:ident: $type:path, + $(generic => $generic:path)? + )? + ) => { + $(#[$meta])+ + #[doc = ""] + #[doc = "_**Note:** if the [`Builder`] was created with [`Builder::with_window`] then this method will have no effect._"] + pub fn $method $($()?)? (mut self $(, $arg: $type)? ) -> Self { + if let BuilderWindowBuilder::Builder(builder) = self.window { + self.window = BuilderWindowBuilder::Builder(builder.$original($($arg)?)); + } + + self + } + }; +} + +/// lol what do i call this +enum BuilderWindowBuilder { + Window(Window), + Builder(WindowBuilder), +} + +pub struct Builder<'event, Event: 'static> { + event_loop: &'event EventLoopWindowTarget, + window: BuilderWindowBuilder, + webview: WebViewBuilder, +} + +impl<'event, Event: 'static> Builder<'event, Event> { + pub fn new(event_loop: &'event EventLoopWindowTarget) -> Self { + Builder { + event_loop, + window: BuilderWindowBuilder::Builder(WindowBuilder::new()), + webview: WebViewBuilder::new(), + } + } + + pub fn with_window(event_loop: &'event EventLoopWindowTarget, window: Window) -> Self { + Self { + event_loop, + window: BuilderWindowBuilder::Window(window), + webview: WebViewBuilder::new(), + } + } + + window_builder! { + /// Requests the window to be of specific dimensions. + /// + /// See [`WindowBuilder::with_inner_size`] for details. + method => inner_size, + original => with_inner_size, + arg => size: T, + generic => Into + } + + window_builder! { + /// Sets a minimum dimension size for the window. + /// + /// See [`WindowBuilder::with_min_inner_size`] for details. + method => min_inner_size, + original => with_min_inner_size, + arg => min_size: T, + generic => Into + } + + window_builder! { + /// Sets a maximum dimension size for the window. + /// + /// See [`WindowBuilder::with_max_inner_size`] for details. + method => max_inner_size, + original => with_max_inner_size, + arg => max_size: T, + generic => Into + } + + window_builder! { + /// Sets a desired initial position for the window. + /// + /// See [`WindowBuilder::with_position`] for details. + method => position, + original => with_position, + arg => position: T, + generic => Into + } + + window_builder! { + /// Sets whether the window is resizable or not. + /// + /// See [`WindowBuilder::with_resizable`] for details. + method => resizable, + original => with_resizable, + arg => resizable: bool, + } + + window_builder! { + /// Requests a specific title for the window. + /// + /// See [`WindowBuilder::with_title`] for details. + method => title, + original => with_title, + arg => title: T, + generic => Into + } + + window_builder! { + /// Requests a specific menu for the window. + /// + /// See [`WindowBuilder::with_menu`] for details. + method => menu, + original => with_menu, + arg => menu: T, + generic => Into> + } + + window_builder! { + /// Sets the window fullscreen state. + /// + /// See [`WindowBuilder::with_fullscreen`] for details. + method => fullscreen, + original => with_fullscreen, + arg => fullscreen: Option, + } + + window_builder! { + /// Requests maximized mode. + /// + /// See [`WindowBuilder::with_maximized`] for details. + method => maximized, + original => with_maximized, + arg => maximized: bool, + } + + window_builder! { + /// Sets whether the window will be initially hidden or visible. + /// + /// See [`WindowBuilder::with_visible`] for details. + method => visible, + original => with_visible, + arg => visible: bool, + } + + // todo: this is the only setter that doesn't take a bool and that seems wrong on a builder + window_builder! { + /// Sets whether the window will be initially hidden or focus. + /// + /// See [`WindowBuilder::with_focus`] for details. + method => focus, + original => with_focus, + } + + window_builder! { + /// Sets whether the background of the window should be transparent. + /// + /// See [`WindowBuilder::with_transparent`] for details. + method => transparent_window, + original => with_transparent, + arg => transparent: bool, + } + + window_builder! { + /// Sets whether the window should have a border, a title bar, etc. + /// + /// See [`WindowBuilder::with_decorations`] for details. + method => decorations, + original => with_decorations, + arg => decorations: bool, + } + + window_builder! { + /// Sets whether or not the window will always be on top of other windows. + /// + /// See [`WindowBuilder::with_always_on_top`] for details. + method => always_on_top, + original => with_always_on_top, + arg => always_on_top: bool, + } + + window_builder! { + /// Sets the window icon. + /// + /// See [`WindowBuilder::with_window_icon`] for details. + method => window_icon, + original => with_window_icon, + arg => window_icon: Option, + } + + /// Whether the [`WebView`] should be transparent. + /// + /// See [`WebViewBuilder::with_transparent`] for details. + pub fn transparent_webview(mut self, transparent: bool) -> Self { + self.webview = self.webview.with_transparent(transparent); + self + } + + /// Set both the [`Window`] and [`WebView`] to be transparent. + /// + /// See [`Builder::transparent_window`] and [`Builder::transparent_webview`] for details. + pub fn transparent(self, transparent: bool) -> Self { + self + .transparent_window(transparent) + .transparent_webview(transparent) + } + + /// Initialize javascript code when loading new pages. + /// + /// See [`WebViewBuilder::with_initialization_script`] for details. + pub fn initialization_script(mut self, js: &str) -> Self { + self.webview = self.webview.with_initialization_script(js); + self + } + + /// Create a [`Dispatcher`] to send evaluation scripts to the [`WebView`]. + /// + /// See [`WebViewBuilder::dispatcher`] for details. + pub fn dispatcher(&self) -> Dispatcher { + self.webview.dispatcher() + } + + /// Register custom file loading protocol. + /// + /// See [`WebViewBuilder::with_custom_protocol`] for details. + pub fn custom_protocol(mut self, name: String, handler: F) -> Self + where + F: Fn(&Window, &str) -> Result> + 'static, + { + self.webview = self.webview.with_custom_protocol(name, handler); + self + } + + /// Set the RPC handler to Communicate between the host Rust code and Javascript on [`WebView`]. + /// + /// See [`WebViewBuilder::with_rpc_handler`] for details. + pub fn rpc_handler(mut self, handler: F) -> Self + where + F: Fn(&Window, RpcRequest) -> Option + 'static, + { + self.webview = self.webview.with_rpc_handler(handler); + self + } + + /// Set a handler closure to process incoming [`FileDropEvent`] of the [`WebView`]. + /// + /// See [`WebViewBuilder::with_file_drop_handler`] for details. + pub fn file_drop_handler(mut self, handler: F) -> Self + where + F: Fn(&Window, FileDropEvent) -> bool + 'static, + { + self.webview = self.webview.with_file_drop_handler(handler); + self + } + + /// The URL to initialize the [`WebView`] with. + /// + /// See [`WebViewBuilder::with_url`] for details. + pub fn url(mut self, url: &str) -> crate::Result { + self.webview = self.webview.with_url(url)?; + Ok(self) + } + + /// Build the resulting [`WebView`]. + pub fn build(self, application: &Application) -> crate::Result { + let window = match self.window { + BuilderWindowBuilder::Window(window) => window, + BuilderWindowBuilder::Builder(builder) => builder.build(self.event_loop)?, + }; + + self.webview.build(window, application) + } +} diff --git a/src/webview/mod.rs b/src/webview/mod.rs index eaf636ec9..6170f52bd 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -81,36 +81,32 @@ fn rpc_proxy( /// [`WebViewBuilder`] / [`WebView`] are the basic building blocks to constrcut WebView contents and /// scripts for those who prefer to control fine grained window creation and event handling. /// [`WebViewBuilder`] privides ability to setup initialization before web engine starts. -pub struct WebViewBuilder<'a> { - application: &'a Application, +pub struct WebViewBuilder { transparent: bool, tx: Sender, rx: Receiver, initialization_scripts: Vec, - window: Window, url: Option, custom_protocols: Vec<(String, Box Result>>)>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, } -impl<'a> WebViewBuilder<'a> { +impl WebViewBuilder { /// Create [`WebViewBuilder`] from provided [`Window`]. - pub fn new(window: Window, application: &'a Application) -> Result { + pub fn new() -> Self { let (tx, rx) = channel(); - Ok(Self { - application, + Self { tx, rx, initialization_scripts: vec![], - window, url: None, transparent: false, custom_protocols: vec![], rpc_handler: None, file_drop_handler: None, - }) + } } /// Whether the WebView window should be transparent. If this is true, writing colors @@ -245,10 +241,10 @@ impl<'a> WebViewBuilder<'a> { /// called in the same thread with the [`EventLoop`] you create. /// /// [`EventLoop`]: crate::application::event_loop::EventLoop - pub fn build(self) -> Result { - let window = Rc::new(self.window); + pub fn build(self, window: Window, application: &Application) -> Result { + let window = Rc::new(window); let webview = InnerWebView::new( - self.application, + application, window.clone(), self.initialization_scripts, self.url, @@ -309,7 +305,7 @@ impl WebView { /// /// [`EventLoop`]: crate::application::event_loop::EventLoop pub fn new(window: Window, application: &Application) -> Result { - WebViewBuilder::new(window, application)?.build() + WebViewBuilder::new().build(window, application) } /// Dispatch javascript code to be evaluated later. Note this will not actually run the From dc20ee4a53a06d57e4ced87f73a5c4043077f7d6 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Wed, 2 Jun 2021 08:28:53 -0700 Subject: [PATCH 19/44] update ecma example --- examples/detect_js_ecma.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/detect_js_ecma.rs b/examples/detect_js_ecma.rs index 2ac5bd3fa..67f0a9338 100644 --- a/examples/detect_js_ecma.rs +++ b/examples/detect_js_ecma.rs @@ -5,16 +5,14 @@ use wry::application::Application; fn main() -> wry::Result<()> { - use wry::{ - application::{ - event::{Event, StartCause, WindowEvent}, - event_loop::{ControlFlow, EventLoop}, - window::WindowBuilder, - }, + use wry::application::{ + event::{Event, StartCause, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, }; + let event_loop = EventLoop::new(); let application = Application::new(None); - let _webview = wry::Builder::new() + let _webview = wry::Builder::new(&event_loop) .title("Detect ECMAScript") .initialization_script(r#" (function () { From c033e769a79a2f7906286bf1a0340f3511fe57eb Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Wed, 2 Jun 2021 13:30:31 -0700 Subject: [PATCH 20/44] enable automation if specific build env is set --- src/application/mod.rs | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/application/mod.rs b/src/application/mod.rs index bff8cafbe..3771562da 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -42,7 +42,7 @@ use self::macos::ApplicationInner; pub mod unix { //! Unix platform extensions for [`Application`](super::Application). use std::path::PathBuf; - use webkit2gtk::{WebContext, WebContextBuilder, WebsiteDataManagerBuilder}; + use webkit2gtk::{WebContext, WebContextBuilder, WebContextExt, WebsiteDataManagerBuilder}; pub(crate) struct ApplicationInner { context: WebContext, @@ -71,9 +71,13 @@ pub mod unix { context_builder = context_builder.website_data_manager(&data_manager); } + let context = context_builder.build(); + let automation = automation_flag(true); + context.set_automation_allowed(automation); + Self { - context: context_builder.build(), - automation: true, + context, + automation, } } } @@ -88,8 +92,10 @@ pub mod unix { /// **Note:** `libwebkit2gtk` only allows 1 automation context at a time. fn allows_automation(&self) -> bool; - /// Set if this context allows automation (default: `true`). - fn set_automation_mode(&mut self, flag: bool); + /// Set if this context allows automation. + /// + /// **Note:** This has no effect if `ENABLE_WEBDRIVER=true` was not set during build time. + fn set_automation_allowed(&mut self, flag: bool); } impl ApplicationExt for super::Application { @@ -101,8 +107,21 @@ pub mod unix { self.inner.automation } - fn set_automation_mode(&mut self, flag: bool) { - self.inner.automation = flag; + fn set_automation_allowed(&mut self, flag: bool) { + let original = self.inner.automation; + let new = automation_flag(flag); + if new != original { + self.inner.automation = flag; + self.inner.context.set_automation_allowed(flag); + } + } + } + + /// Set the automation flag if the build time environmental variable is set. + fn automation_flag(flag: bool) -> bool { + match option_env!("ENABLE_WEBDRIVER") { + Some("true") => flag, + _ => false, } } } From a50a5ce594eda808cd19f2eedea10b53b9b99236 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Wed, 2 Jun 2021 13:50:49 -0700 Subject: [PATCH 21/44] change build env var to feature --- Cargo.toml | 1 + src/application/mod.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 28929a7c4..38206652f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ tray = [ "tao/tray" ] # See https://github.com/tauri-apps/wry/issues/247 for more information # winrt = [ "windows-webview2", "windows" ] win32 = [ "webview2", "winapi", "webview2-sys" ] +webdriver = [ ] [dependencies] libc = "0.2" diff --git a/src/application/mod.rs b/src/application/mod.rs index 3771562da..1a3fa9f9d 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -117,10 +117,10 @@ pub mod unix { } } - /// Set the automation flag if the build time environmental variable is set. + /// Set the automation flag if the the `webdriver` feature is set. fn automation_flag(flag: bool) -> bool { - match option_env!("ENABLE_WEBDRIVER") { - Some("true") => flag, + match cfg!(feature = "webdriver") { + true => flag, _ => false, } } From c55ad74d8af73da2d11e8e450ad6c41362e5f4e5 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 07:48:56 -0700 Subject: [PATCH 22/44] move the super builder to its own module --- src/builder.rs | 294 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 299 +------------------------------------------------ 2 files changed, 299 insertions(+), 294 deletions(-) create mode 100644 src/builder.rs diff --git a/src/builder.rs b/src/builder.rs new file mode 100644 index 000000000..31bcef132 --- /dev/null +++ b/src/builder.rs @@ -0,0 +1,294 @@ +//! A builder that wraps both [`WindowBuilder`] and [`WebViewBuilder`]. + +use crate::{ + application::{ + window::{Window, WindowBuilder}, + Application, + }, + webview::{Dispatcher, WebViewBuilder}, + webview::{FileDropEvent, RpcRequest, RpcResponse, WebView}, +}; + +use tao::{ + dpi::{Position, Size}, + event_loop::EventLoopWindowTarget, + menu::Menu, + window::{Fullscreen, Icon}, +}; + +macro_rules! window_builder { + ( + $(#[$meta:meta])+ + method => $method:ident, + original => $original:ident, + $( + arg => $arg:ident: $type:path, + $(generic => $generic:path)? + )? + ) => { + $(#[$meta])+ + #[doc = ""] + #[doc = "_**Note:** if the [`Builder`] was created with [`Builder::with_window`] then this method will have no effect._"] + pub fn $method $($()?)? (mut self $(, $arg: $type)? ) -> Self { + if let BuilderWindowBuilder::Builder(builder) = self.window { + self.window = BuilderWindowBuilder::Builder(builder.$original($($arg)?)); + } + + self + } + }; +} + +/// lol what do i call this +enum BuilderWindowBuilder { + Window(Window), + Builder(WindowBuilder), +} + +pub struct Builder<'event, Event: 'static> { + event_loop: &'event EventLoopWindowTarget, + window: BuilderWindowBuilder, + webview: WebViewBuilder, +} + +impl<'event, Event: 'static> Builder<'event, Event> { + pub fn new(event_loop: &'event EventLoopWindowTarget) -> Self { + Builder { + event_loop, + window: BuilderWindowBuilder::Builder(WindowBuilder::new()), + webview: WebViewBuilder::new(), + } + } + + pub fn with_window(event_loop: &'event EventLoopWindowTarget, window: Window) -> Self { + Self { + event_loop, + window: BuilderWindowBuilder::Window(window), + webview: WebViewBuilder::new(), + } + } + + window_builder! { + /// Requests the window to be of specific dimensions. + /// + /// See [`WindowBuilder::with_inner_size`] for details. + method => inner_size, + original => with_inner_size, + arg => size: T, + generic => Into + } + + window_builder! { + /// Sets a minimum dimension size for the window. + /// + /// See [`WindowBuilder::with_min_inner_size`] for details. + method => min_inner_size, + original => with_min_inner_size, + arg => min_size: T, + generic => Into + } + + window_builder! { + /// Sets a maximum dimension size for the window. + /// + /// See [`WindowBuilder::with_max_inner_size`] for details. + method => max_inner_size, + original => with_max_inner_size, + arg => max_size: T, + generic => Into + } + + window_builder! { + /// Sets a desired initial position for the window. + /// + /// See [`WindowBuilder::with_position`] for details. + method => position, + original => with_position, + arg => position: T, + generic => Into + } + + window_builder! { + /// Sets whether the window is resizable or not. + /// + /// See [`WindowBuilder::with_resizable`] for details. + method => resizable, + original => with_resizable, + arg => resizable: bool, + } + + window_builder! { + /// Requests a specific title for the window. + /// + /// See [`WindowBuilder::with_title`] for details. + method => title, + original => with_title, + arg => title: T, + generic => Into + } + + window_builder! { + /// Requests a specific menu for the window. + /// + /// See [`WindowBuilder::with_menu`] for details. + method => menu, + original => with_menu, + arg => menu: T, + generic => Into> + } + + window_builder! { + /// Sets the window fullscreen state. + /// + /// See [`WindowBuilder::with_fullscreen`] for details. + method => fullscreen, + original => with_fullscreen, + arg => fullscreen: Option, + } + + window_builder! { + /// Requests maximized mode. + /// + /// See [`WindowBuilder::with_maximized`] for details. + method => maximized, + original => with_maximized, + arg => maximized: bool, + } + + window_builder! { + /// Sets whether the window will be initially hidden or visible. + /// + /// See [`WindowBuilder::with_visible`] for details. + method => visible, + original => with_visible, + arg => visible: bool, + } + + // todo: this is the only setter that doesn't take a bool and that seems wrong on a builder + window_builder! { + /// Sets whether the window will be initially hidden or focus. + /// + /// See [`WindowBuilder::with_focus`] for details. + method => focus, + original => with_focus, + } + + window_builder! { + /// Sets whether the background of the window should be transparent. + /// + /// See [`WindowBuilder::with_transparent`] for details. + method => transparent_window, + original => with_transparent, + arg => transparent: bool, + } + + window_builder! { + /// Sets whether the window should have a border, a title bar, etc. + /// + /// See [`WindowBuilder::with_decorations`] for details. + method => decorations, + original => with_decorations, + arg => decorations: bool, + } + + window_builder! { + /// Sets whether or not the window will always be on top of other windows. + /// + /// See [`WindowBuilder::with_always_on_top`] for details. + method => always_on_top, + original => with_always_on_top, + arg => always_on_top: bool, + } + + window_builder! { + /// Sets the window icon. + /// + /// See [`WindowBuilder::with_window_icon`] for details. + method => window_icon, + original => with_window_icon, + arg => window_icon: Option, + } + + /// Whether the [`WebView`] should be transparent. + /// + /// See [`WebViewBuilder::with_transparent`] for details. + pub fn transparent_webview(mut self, transparent: bool) -> Self { + self.webview = self.webview.with_transparent(transparent); + self + } + + /// Set both the [`Window`] and [`WebView`] to be transparent. + /// + /// See [`Builder::transparent_window`] and [`Builder::transparent_webview`] for details. + pub fn transparent(self, transparent: bool) -> Self { + self + .transparent_window(transparent) + .transparent_webview(transparent) + } + + /// Initialize javascript code when loading new pages. + /// + /// See [`WebViewBuilder::with_initialization_script`] for details. + pub fn initialization_script(mut self, js: &str) -> Self { + self.webview = self.webview.with_initialization_script(js); + self + } + + /// Create a [`Dispatcher`] to send evaluation scripts to the [`WebView`]. + /// + /// See [`WebViewBuilder::dispatcher`] for details. + pub fn dispatcher(&self) -> Dispatcher { + self.webview.dispatcher() + } + + /// Register custom file loading protocol. + /// + /// See [`WebViewBuilder::with_custom_protocol`] for details. + pub fn custom_protocol(mut self, name: String, handler: F) -> Self + where + F: Fn(&Window, &str) -> crate::Result> + 'static, + { + self.webview = self.webview.with_custom_protocol(name, handler); + self + } + + /// Set the RPC handler to Communicate between the host Rust code and Javascript on [`WebView`]. + /// + /// See [`WebViewBuilder::with_rpc_handler`] for details. + pub fn rpc_handler(mut self, handler: F) -> Self + where + F: Fn(&Window, RpcRequest) -> Option + 'static, + { + self.webview = self.webview.with_rpc_handler(handler); + self + } + + /// Set a handler closure to process incoming [`FileDropEvent`] of the [`WebView`]. + /// + /// See [`WebViewBuilder::with_file_drop_handler`] for details. + pub fn file_drop_handler(mut self, handler: F) -> Self + where + F: Fn(&Window, FileDropEvent) -> bool + 'static, + { + self.webview = self.webview.with_file_drop_handler(handler); + self + } + + /// The URL to initialize the [`WebView`] with. + /// + /// See [`WebViewBuilder::with_url`] for details. + pub fn url(mut self, url: &str) -> crate::Result { + self.webview = self.webview.with_url(url)?; + Ok(self) + } + + /// Build the resulting [`WebView`]. + pub fn build(self, application: &Application) -> crate::Result { + let window = match self.window { + BuilderWindowBuilder::Window(window) => window, + BuilderWindowBuilder::Builder(builder) => builder.build(self.event_loop)?, + }; + + self.webview.build(window, application) + } +} diff --git a/src/lib.rs b/src/lib.rs index f54f8d014..ce0850294 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,6 +104,10 @@ use url::ParseError; pub mod application; pub mod webview; +mod builder; + +// expose the builder on the root namespace so it can be used as wry::Builder +pub use builder::Builder; /// Convenient type alias of Result type for wry. pub type Result = std::result::Result; @@ -151,297 +155,4 @@ pub enum Error { #[cfg(feature = "win32")] #[error(transparent)] WebView2Error(#[from] webview2::Error), -} - -use crate::{ - application::{ - window::{Window, WindowBuilder}, - Application, - }, - webview::{Dispatcher, WebViewBuilder}, - webview::{FileDropEvent, RpcRequest, RpcResponse, WebView}, -}; - -use tao::{ - dpi::{Position, Size}, - event_loop::EventLoopWindowTarget, - menu::Menu, - window::{Fullscreen, Icon}, -}; - -macro_rules! window_builder { - ( - $(#[$meta:meta])+ - method => $method:ident, - original => $original:ident, - $( - arg => $arg:ident: $type:path, - $(generic => $generic:path)? - )? - ) => { - $(#[$meta])+ - #[doc = ""] - #[doc = "_**Note:** if the [`Builder`] was created with [`Builder::with_window`] then this method will have no effect._"] - pub fn $method $($()?)? (mut self $(, $arg: $type)? ) -> Self { - if let BuilderWindowBuilder::Builder(builder) = self.window { - self.window = BuilderWindowBuilder::Builder(builder.$original($($arg)?)); - } - - self - } - }; -} - -/// lol what do i call this -enum BuilderWindowBuilder { - Window(Window), - Builder(WindowBuilder), -} - -pub struct Builder<'event, Event: 'static> { - event_loop: &'event EventLoopWindowTarget, - window: BuilderWindowBuilder, - webview: WebViewBuilder, -} - -impl<'event, Event: 'static> Builder<'event, Event> { - pub fn new(event_loop: &'event EventLoopWindowTarget) -> Self { - Builder { - event_loop, - window: BuilderWindowBuilder::Builder(WindowBuilder::new()), - webview: WebViewBuilder::new(), - } - } - - pub fn with_window(event_loop: &'event EventLoopWindowTarget, window: Window) -> Self { - Self { - event_loop, - window: BuilderWindowBuilder::Window(window), - webview: WebViewBuilder::new(), - } - } - - window_builder! { - /// Requests the window to be of specific dimensions. - /// - /// See [`WindowBuilder::with_inner_size`] for details. - method => inner_size, - original => with_inner_size, - arg => size: T, - generic => Into - } - - window_builder! { - /// Sets a minimum dimension size for the window. - /// - /// See [`WindowBuilder::with_min_inner_size`] for details. - method => min_inner_size, - original => with_min_inner_size, - arg => min_size: T, - generic => Into - } - - window_builder! { - /// Sets a maximum dimension size for the window. - /// - /// See [`WindowBuilder::with_max_inner_size`] for details. - method => max_inner_size, - original => with_max_inner_size, - arg => max_size: T, - generic => Into - } - - window_builder! { - /// Sets a desired initial position for the window. - /// - /// See [`WindowBuilder::with_position`] for details. - method => position, - original => with_position, - arg => position: T, - generic => Into - } - - window_builder! { - /// Sets whether the window is resizable or not. - /// - /// See [`WindowBuilder::with_resizable`] for details. - method => resizable, - original => with_resizable, - arg => resizable: bool, - } - - window_builder! { - /// Requests a specific title for the window. - /// - /// See [`WindowBuilder::with_title`] for details. - method => title, - original => with_title, - arg => title: T, - generic => Into - } - - window_builder! { - /// Requests a specific menu for the window. - /// - /// See [`WindowBuilder::with_menu`] for details. - method => menu, - original => with_menu, - arg => menu: T, - generic => Into> - } - - window_builder! { - /// Sets the window fullscreen state. - /// - /// See [`WindowBuilder::with_fullscreen`] for details. - method => fullscreen, - original => with_fullscreen, - arg => fullscreen: Option, - } - - window_builder! { - /// Requests maximized mode. - /// - /// See [`WindowBuilder::with_maximized`] for details. - method => maximized, - original => with_maximized, - arg => maximized: bool, - } - - window_builder! { - /// Sets whether the window will be initially hidden or visible. - /// - /// See [`WindowBuilder::with_visible`] for details. - method => visible, - original => with_visible, - arg => visible: bool, - } - - // todo: this is the only setter that doesn't take a bool and that seems wrong on a builder - window_builder! { - /// Sets whether the window will be initially hidden or focus. - /// - /// See [`WindowBuilder::with_focus`] for details. - method => focus, - original => with_focus, - } - - window_builder! { - /// Sets whether the background of the window should be transparent. - /// - /// See [`WindowBuilder::with_transparent`] for details. - method => transparent_window, - original => with_transparent, - arg => transparent: bool, - } - - window_builder! { - /// Sets whether the window should have a border, a title bar, etc. - /// - /// See [`WindowBuilder::with_decorations`] for details. - method => decorations, - original => with_decorations, - arg => decorations: bool, - } - - window_builder! { - /// Sets whether or not the window will always be on top of other windows. - /// - /// See [`WindowBuilder::with_always_on_top`] for details. - method => always_on_top, - original => with_always_on_top, - arg => always_on_top: bool, - } - - window_builder! { - /// Sets the window icon. - /// - /// See [`WindowBuilder::with_window_icon`] for details. - method => window_icon, - original => with_window_icon, - arg => window_icon: Option, - } - - /// Whether the [`WebView`] should be transparent. - /// - /// See [`WebViewBuilder::with_transparent`] for details. - pub fn transparent_webview(mut self, transparent: bool) -> Self { - self.webview = self.webview.with_transparent(transparent); - self - } - - /// Set both the [`Window`] and [`WebView`] to be transparent. - /// - /// See [`Builder::transparent_window`] and [`Builder::transparent_webview`] for details. - pub fn transparent(self, transparent: bool) -> Self { - self - .transparent_window(transparent) - .transparent_webview(transparent) - } - - /// Initialize javascript code when loading new pages. - /// - /// See [`WebViewBuilder::with_initialization_script`] for details. - pub fn initialization_script(mut self, js: &str) -> Self { - self.webview = self.webview.with_initialization_script(js); - self - } - - /// Create a [`Dispatcher`] to send evaluation scripts to the [`WebView`]. - /// - /// See [`WebViewBuilder::dispatcher`] for details. - pub fn dispatcher(&self) -> Dispatcher { - self.webview.dispatcher() - } - - /// Register custom file loading protocol. - /// - /// See [`WebViewBuilder::with_custom_protocol`] for details. - pub fn custom_protocol(mut self, name: String, handler: F) -> Self - where - F: Fn(&Window, &str) -> Result> + 'static, - { - self.webview = self.webview.with_custom_protocol(name, handler); - self - } - - /// Set the RPC handler to Communicate between the host Rust code and Javascript on [`WebView`]. - /// - /// See [`WebViewBuilder::with_rpc_handler`] for details. - pub fn rpc_handler(mut self, handler: F) -> Self - where - F: Fn(&Window, RpcRequest) -> Option + 'static, - { - self.webview = self.webview.with_rpc_handler(handler); - self - } - - /// Set a handler closure to process incoming [`FileDropEvent`] of the [`WebView`]. - /// - /// See [`WebViewBuilder::with_file_drop_handler`] for details. - pub fn file_drop_handler(mut self, handler: F) -> Self - where - F: Fn(&Window, FileDropEvent) -> bool + 'static, - { - self.webview = self.webview.with_file_drop_handler(handler); - self - } - - /// The URL to initialize the [`WebView`] with. - /// - /// See [`WebViewBuilder::with_url`] for details. - pub fn url(mut self, url: &str) -> crate::Result { - self.webview = self.webview.with_url(url)?; - Ok(self) - } - - /// Build the resulting [`WebView`]. - pub fn build(self, application: &Application) -> crate::Result { - let window = match self.window { - BuilderWindowBuilder::Window(window) => window, - BuilderWindowBuilder::Builder(builder) => builder.build(self.event_loop)?, - }; - - self.webview.build(window, application) - } -} +} \ No newline at end of file From 3f89ac1f485330cf2934535b069c016c57a91c9b Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 07:49:09 -0700 Subject: [PATCH 23/44] cargo +nightly fmt --- src/builder.rs | 231 ++++++++++++++++++++++++------------------------- src/lib.rs | 4 +- 2 files changed, 117 insertions(+), 118 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 31bcef132..f979ebc91 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,19 +1,18 @@ //! A builder that wraps both [`WindowBuilder`] and [`WebViewBuilder`]. use crate::{ - application::{ - window::{Window, WindowBuilder}, - Application, - }, - webview::{Dispatcher, WebViewBuilder}, - webview::{FileDropEvent, RpcRequest, RpcResponse, WebView}, + application::{ + window::{Window, WindowBuilder}, + Application, + }, + webview::{Dispatcher, FileDropEvent, RpcRequest, RpcResponse, WebView, WebViewBuilder}, }; use tao::{ - dpi::{Position, Size}, - event_loop::EventLoopWindowTarget, - menu::Menu, - window::{Fullscreen, Icon}, + dpi::{Position, Size}, + event_loop::EventLoopWindowTarget, + menu::Menu, + window::{Fullscreen, Icon}, }; macro_rules! window_builder { @@ -41,34 +40,34 @@ macro_rules! window_builder { /// lol what do i call this enum BuilderWindowBuilder { - Window(Window), - Builder(WindowBuilder), + Window(Window), + Builder(WindowBuilder), } pub struct Builder<'event, Event: 'static> { - event_loop: &'event EventLoopWindowTarget, - window: BuilderWindowBuilder, - webview: WebViewBuilder, + event_loop: &'event EventLoopWindowTarget, + window: BuilderWindowBuilder, + webview: WebViewBuilder, } impl<'event, Event: 'static> Builder<'event, Event> { - pub fn new(event_loop: &'event EventLoopWindowTarget) -> Self { - Builder { - event_loop, - window: BuilderWindowBuilder::Builder(WindowBuilder::new()), - webview: WebViewBuilder::new(), - } + pub fn new(event_loop: &'event EventLoopWindowTarget) -> Self { + Builder { + event_loop, + window: BuilderWindowBuilder::Builder(WindowBuilder::new()), + webview: WebViewBuilder::new(), } + } - pub fn with_window(event_loop: &'event EventLoopWindowTarget, window: Window) -> Self { - Self { - event_loop, - window: BuilderWindowBuilder::Window(window), - webview: WebViewBuilder::new(), - } + pub fn with_window(event_loop: &'event EventLoopWindowTarget, window: Window) -> Self { + Self { + event_loop, + window: BuilderWindowBuilder::Window(window), + webview: WebViewBuilder::new(), } + } - window_builder! { + window_builder! { /// Requests the window to be of specific dimensions. /// /// See [`WindowBuilder::with_inner_size`] for details. @@ -78,7 +77,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { generic => Into } - window_builder! { + window_builder! { /// Sets a minimum dimension size for the window. /// /// See [`WindowBuilder::with_min_inner_size`] for details. @@ -88,7 +87,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { generic => Into } - window_builder! { + window_builder! { /// Sets a maximum dimension size for the window. /// /// See [`WindowBuilder::with_max_inner_size`] for details. @@ -98,7 +97,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { generic => Into } - window_builder! { + window_builder! { /// Sets a desired initial position for the window. /// /// See [`WindowBuilder::with_position`] for details. @@ -108,7 +107,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { generic => Into } - window_builder! { + window_builder! { /// Sets whether the window is resizable or not. /// /// See [`WindowBuilder::with_resizable`] for details. @@ -117,7 +116,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { arg => resizable: bool, } - window_builder! { + window_builder! { /// Requests a specific title for the window. /// /// See [`WindowBuilder::with_title`] for details. @@ -127,7 +126,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { generic => Into } - window_builder! { + window_builder! { /// Requests a specific menu for the window. /// /// See [`WindowBuilder::with_menu`] for details. @@ -137,7 +136,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { generic => Into> } - window_builder! { + window_builder! { /// Sets the window fullscreen state. /// /// See [`WindowBuilder::with_fullscreen`] for details. @@ -146,7 +145,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { arg => fullscreen: Option, } - window_builder! { + window_builder! { /// Requests maximized mode. /// /// See [`WindowBuilder::with_maximized`] for details. @@ -155,7 +154,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { arg => maximized: bool, } - window_builder! { + window_builder! { /// Sets whether the window will be initially hidden or visible. /// /// See [`WindowBuilder::with_visible`] for details. @@ -164,8 +163,8 @@ impl<'event, Event: 'static> Builder<'event, Event> { arg => visible: bool, } - // todo: this is the only setter that doesn't take a bool and that seems wrong on a builder - window_builder! { + // todo: this is the only setter that doesn't take a bool and that seems wrong on a builder + window_builder! { /// Sets whether the window will be initially hidden or focus. /// /// See [`WindowBuilder::with_focus`] for details. @@ -173,7 +172,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { original => with_focus, } - window_builder! { + window_builder! { /// Sets whether the background of the window should be transparent. /// /// See [`WindowBuilder::with_transparent`] for details. @@ -182,7 +181,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { arg => transparent: bool, } - window_builder! { + window_builder! { /// Sets whether the window should have a border, a title bar, etc. /// /// See [`WindowBuilder::with_decorations`] for details. @@ -191,7 +190,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { arg => decorations: bool, } - window_builder! { + window_builder! { /// Sets whether or not the window will always be on top of other windows. /// /// See [`WindowBuilder::with_always_on_top`] for details. @@ -200,7 +199,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { arg => always_on_top: bool, } - window_builder! { + window_builder! { /// Sets the window icon. /// /// See [`WindowBuilder::with_window_icon`] for details. @@ -209,86 +208,86 @@ impl<'event, Event: 'static> Builder<'event, Event> { arg => window_icon: Option, } - /// Whether the [`WebView`] should be transparent. - /// - /// See [`WebViewBuilder::with_transparent`] for details. - pub fn transparent_webview(mut self, transparent: bool) -> Self { - self.webview = self.webview.with_transparent(transparent); - self - } + /// Whether the [`WebView`] should be transparent. + /// + /// See [`WebViewBuilder::with_transparent`] for details. + pub fn transparent_webview(mut self, transparent: bool) -> Self { + self.webview = self.webview.with_transparent(transparent); + self + } - /// Set both the [`Window`] and [`WebView`] to be transparent. - /// - /// See [`Builder::transparent_window`] and [`Builder::transparent_webview`] for details. - pub fn transparent(self, transparent: bool) -> Self { - self - .transparent_window(transparent) - .transparent_webview(transparent) - } + /// Set both the [`Window`] and [`WebView`] to be transparent. + /// + /// See [`Builder::transparent_window`] and [`Builder::transparent_webview`] for details. + pub fn transparent(self, transparent: bool) -> Self { + self + .transparent_window(transparent) + .transparent_webview(transparent) + } - /// Initialize javascript code when loading new pages. - /// - /// See [`WebViewBuilder::with_initialization_script`] for details. - pub fn initialization_script(mut self, js: &str) -> Self { - self.webview = self.webview.with_initialization_script(js); - self - } + /// Initialize javascript code when loading new pages. + /// + /// See [`WebViewBuilder::with_initialization_script`] for details. + pub fn initialization_script(mut self, js: &str) -> Self { + self.webview = self.webview.with_initialization_script(js); + self + } - /// Create a [`Dispatcher`] to send evaluation scripts to the [`WebView`]. - /// - /// See [`WebViewBuilder::dispatcher`] for details. - pub fn dispatcher(&self) -> Dispatcher { - self.webview.dispatcher() - } + /// Create a [`Dispatcher`] to send evaluation scripts to the [`WebView`]. + /// + /// See [`WebViewBuilder::dispatcher`] for details. + pub fn dispatcher(&self) -> Dispatcher { + self.webview.dispatcher() + } - /// Register custom file loading protocol. - /// - /// See [`WebViewBuilder::with_custom_protocol`] for details. - pub fn custom_protocol(mut self, name: String, handler: F) -> Self - where - F: Fn(&Window, &str) -> crate::Result> + 'static, - { - self.webview = self.webview.with_custom_protocol(name, handler); - self - } + /// Register custom file loading protocol. + /// + /// See [`WebViewBuilder::with_custom_protocol`] for details. + pub fn custom_protocol(mut self, name: String, handler: F) -> Self + where + F: Fn(&Window, &str) -> crate::Result> + 'static, + { + self.webview = self.webview.with_custom_protocol(name, handler); + self + } - /// Set the RPC handler to Communicate between the host Rust code and Javascript on [`WebView`]. - /// - /// See [`WebViewBuilder::with_rpc_handler`] for details. - pub fn rpc_handler(mut self, handler: F) -> Self - where - F: Fn(&Window, RpcRequest) -> Option + 'static, - { - self.webview = self.webview.with_rpc_handler(handler); - self - } + /// Set the RPC handler to Communicate between the host Rust code and Javascript on [`WebView`]. + /// + /// See [`WebViewBuilder::with_rpc_handler`] for details. + pub fn rpc_handler(mut self, handler: F) -> Self + where + F: Fn(&Window, RpcRequest) -> Option + 'static, + { + self.webview = self.webview.with_rpc_handler(handler); + self + } - /// Set a handler closure to process incoming [`FileDropEvent`] of the [`WebView`]. - /// - /// See [`WebViewBuilder::with_file_drop_handler`] for details. - pub fn file_drop_handler(mut self, handler: F) -> Self - where - F: Fn(&Window, FileDropEvent) -> bool + 'static, - { - self.webview = self.webview.with_file_drop_handler(handler); - self - } + /// Set a handler closure to process incoming [`FileDropEvent`] of the [`WebView`]. + /// + /// See [`WebViewBuilder::with_file_drop_handler`] for details. + pub fn file_drop_handler(mut self, handler: F) -> Self + where + F: Fn(&Window, FileDropEvent) -> bool + 'static, + { + self.webview = self.webview.with_file_drop_handler(handler); + self + } - /// The URL to initialize the [`WebView`] with. - /// - /// See [`WebViewBuilder::with_url`] for details. - pub fn url(mut self, url: &str) -> crate::Result { - self.webview = self.webview.with_url(url)?; - Ok(self) - } + /// The URL to initialize the [`WebView`] with. + /// + /// See [`WebViewBuilder::with_url`] for details. + pub fn url(mut self, url: &str) -> crate::Result { + self.webview = self.webview.with_url(url)?; + Ok(self) + } - /// Build the resulting [`WebView`]. - pub fn build(self, application: &Application) -> crate::Result { - let window = match self.window { - BuilderWindowBuilder::Window(window) => window, - BuilderWindowBuilder::Builder(builder) => builder.build(self.event_loop)?, - }; + /// Build the resulting [`WebView`]. + pub fn build(self, application: &Application) -> crate::Result { + let window = match self.window { + BuilderWindowBuilder::Window(window) => window, + BuilderWindowBuilder::Builder(builder) => builder.build(self.event_loop)?, + }; - self.webview.build(window, application) - } + self.webview.build(window, application) + } } diff --git a/src/lib.rs b/src/lib.rs index ce0850294..cf9b0c469 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -103,8 +103,8 @@ pub use serde_json::Value; use url::ParseError; pub mod application; -pub mod webview; mod builder; +pub mod webview; // expose the builder on the root namespace so it can be used as wry::Builder pub use builder::Builder; @@ -155,4 +155,4 @@ pub enum Error { #[cfg(feature = "win32")] #[error(transparent)] WebView2Error(#[from] webview2::Error), -} \ No newline at end of file +} From a497e86e418d0f5bf4d7e9dfaacf23afb7f0f30a Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 08:02:59 -0700 Subject: [PATCH 24/44] update builder docs --- src/builder.rs | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index f979ebc91..9af95f3f2 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -29,8 +29,11 @@ macro_rules! window_builder { #[doc = ""] #[doc = "_**Note:** if the [`Builder`] was created with [`Builder::with_window`] then this method will have no effect._"] pub fn $method $($()?)? (mut self $(, $arg: $type)? ) -> Self { - if let BuilderWindowBuilder::Builder(builder) = self.window { - self.window = BuilderWindowBuilder::Builder(builder.$original($($arg)?)); + if let BuilderWindowBuilder::Builder { builder, event_loop } = self.window { + self.window = BuilderWindowBuilder::Builder { + builder: builder.$original($($arg)?), + event_loop + }; } self @@ -39,29 +42,43 @@ macro_rules! window_builder { } /// lol what do i call this -enum BuilderWindowBuilder { +enum BuilderWindowBuilder<'event, Event: 'static> { Window(Window), - Builder(WindowBuilder), + Builder { + builder: WindowBuilder, + event_loop: &'event EventLoopWindowTarget, + }, } +/// A streamlined builder to create a [`WebView`](crate::webview::WebView). +/// +/// You can instead use [`WindowBuilder`] and [`WebViewBuilder`] if you wish to separate the +/// builders. pub struct Builder<'event, Event: 'static> { - event_loop: &'event EventLoopWindowTarget, - window: BuilderWindowBuilder, + window: BuilderWindowBuilder<'event, Event>, webview: WebViewBuilder, } impl<'event, Event: 'static> Builder<'event, Event> { + /// Create a new [`Builder`] attached to an existing [`EventLoop`](tao::event_loop::EventLoop). pub fn new(event_loop: &'event EventLoopWindowTarget) -> Self { Builder { - event_loop, - window: BuilderWindowBuilder::Builder(WindowBuilder::new()), + window: BuilderWindowBuilder::Builder { + builder: WindowBuilder::new(), + event_loop, + }, webview: WebViewBuilder::new(), } } - pub fn with_window(event_loop: &'event EventLoopWindowTarget, window: Window) -> Self { + /// Create a new [`Builder`] with an already built [`Window`]. + /// + /// You should still have the [`EventLoop`] you created the [`Window`] with if you want to control + /// the [`WebView`] resulting from this [`Builder`]. + /// + /// [`EventLoop`]: tao::event_loop::EventLoop + pub fn with_window(window: Window) -> Self { Self { - event_loop, window: BuilderWindowBuilder::Window(window), webview: WebViewBuilder::new(), } @@ -285,7 +302,10 @@ impl<'event, Event: 'static> Builder<'event, Event> { pub fn build(self, application: &Application) -> crate::Result { let window = match self.window { BuilderWindowBuilder::Window(window) => window, - BuilderWindowBuilder::Builder(builder) => builder.build(self.event_loop)?, + BuilderWindowBuilder::Builder { + builder, + event_loop, + } => builder.build(event_loop)?, }; self.webview.build(window, application) From c6dc1067aaca4fb5a54a5f4b4fc01acd0dd30c4e Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 08:09:48 -0700 Subject: [PATCH 25/44] explicitly allow inlining on wry::Builder --- src/builder.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/builder.rs b/src/builder.rs index 9af95f3f2..9753ade38 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -28,6 +28,7 @@ macro_rules! window_builder { $(#[$meta])+ #[doc = ""] #[doc = "_**Note:** if the [`Builder`] was created with [`Builder::with_window`] then this method will have no effect._"] + #[inline] pub fn $method $($()?)? (mut self $(, $arg: $type)? ) -> Self { if let BuilderWindowBuilder::Builder { builder, event_loop } = self.window { self.window = BuilderWindowBuilder::Builder { @@ -61,6 +62,7 @@ pub struct Builder<'event, Event: 'static> { impl<'event, Event: 'static> Builder<'event, Event> { /// Create a new [`Builder`] attached to an existing [`EventLoop`](tao::event_loop::EventLoop). + #[inline] pub fn new(event_loop: &'event EventLoopWindowTarget) -> Self { Builder { window: BuilderWindowBuilder::Builder { @@ -77,6 +79,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { /// the [`WebView`] resulting from this [`Builder`]. /// /// [`EventLoop`]: tao::event_loop::EventLoop + #[inline] pub fn with_window(window: Window) -> Self { Self { window: BuilderWindowBuilder::Window(window), @@ -228,6 +231,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { /// Whether the [`WebView`] should be transparent. /// /// See [`WebViewBuilder::with_transparent`] for details. + #[inline] pub fn transparent_webview(mut self, transparent: bool) -> Self { self.webview = self.webview.with_transparent(transparent); self @@ -236,6 +240,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { /// Set both the [`Window`] and [`WebView`] to be transparent. /// /// See [`Builder::transparent_window`] and [`Builder::transparent_webview`] for details. + #[inline] pub fn transparent(self, transparent: bool) -> Self { self .transparent_window(transparent) @@ -245,6 +250,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { /// Initialize javascript code when loading new pages. /// /// See [`WebViewBuilder::with_initialization_script`] for details. + #[inline] pub fn initialization_script(mut self, js: &str) -> Self { self.webview = self.webview.with_initialization_script(js); self @@ -253,6 +259,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { /// Create a [`Dispatcher`] to send evaluation scripts to the [`WebView`]. /// /// See [`WebViewBuilder::dispatcher`] for details. + #[inline] pub fn dispatcher(&self) -> Dispatcher { self.webview.dispatcher() } @@ -260,6 +267,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { /// Register custom file loading protocol. /// /// See [`WebViewBuilder::with_custom_protocol`] for details. + #[inline] pub fn custom_protocol(mut self, name: String, handler: F) -> Self where F: Fn(&Window, &str) -> crate::Result> + 'static, @@ -271,6 +279,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { /// Set the RPC handler to Communicate between the host Rust code and Javascript on [`WebView`]. /// /// See [`WebViewBuilder::with_rpc_handler`] for details. + #[inline] pub fn rpc_handler(mut self, handler: F) -> Self where F: Fn(&Window, RpcRequest) -> Option + 'static, @@ -282,6 +291,7 @@ impl<'event, Event: 'static> Builder<'event, Event> { /// Set a handler closure to process incoming [`FileDropEvent`] of the [`WebView`]. /// /// See [`WebViewBuilder::with_file_drop_handler`] for details. + #[inline] pub fn file_drop_handler(mut self, handler: F) -> Self where F: Fn(&Window, FileDropEvent) -> bool + 'static, @@ -293,12 +303,14 @@ impl<'event, Event: 'static> Builder<'event, Event> { /// The URL to initialize the [`WebView`] with. /// /// See [`WebViewBuilder::with_url`] for details. + #[inline] pub fn url(mut self, url: &str) -> crate::Result { self.webview = self.webview.with_url(url)?; Ok(self) } /// Build the resulting [`WebView`]. + #[inline] pub fn build(self, application: &Application) -> crate::Result { let window = match self.window { BuilderWindowBuilder::Window(window) => window, From 98b5db40f4d9e0fc545bb1d2250c8fa9239734e9 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 09:14:44 -0700 Subject: [PATCH 26/44] revert everything to dev --- Cargo.toml | 4 +- README.md | 4 +- bench/tests/src/cpu_intensive.rs | 4 +- bench/tests/src/custom_protocol.rs | 4 +- bench/tests/src/hello_world.rs | 4 +- examples/custom_data_directory.rs | 5 +- examples/custom_protocol.rs | 4 +- examples/custom_titlebar.rs | 4 +- examples/detect_js_ecma.rs | 33 +-- examples/dragndrop.rs | 4 +- examples/fullscreen.rs | 4 +- examples/hello_world.rs | 4 +- examples/html_test.rs | 4 +- examples/menu_bar.rs | 7 +- examples/multi_window.rs | 37 ++-- examples/rpc.rs | 4 +- examples/system_tray.rs | 4 +- examples/transparent.rs | 4 +- examples/validate_webview.rs | 4 +- src/application/mod.rs | 159 -------------- src/builder.rs | 325 ----------------------------- src/lib.rs | 9 +- src/webview/mod.rs | 29 ++- src/webview/webkitgtk/mod.rs | 65 +++--- src/webview/webview2/win32/mod.rs | 27 +-- src/webview/webview2/winrt/mod.rs | 8 +- src/webview/wkwebview/mod.rs | 5 +- 27 files changed, 125 insertions(+), 644 deletions(-) delete mode 100644 src/builder.rs diff --git a/Cargo.toml b/Cargo.toml index 38206652f..e0f022141 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ categories = [ "gui" ] [package.metadata.docs.rs] features = [ "dox" ] -rustdoc-args = [ "--cfg", "doc_cfg" ] default-target = "x86_64-unknown-linux-gnu" targets = [ "x86_64-pc-windows-msvc", @@ -33,7 +32,6 @@ tray = [ "tao/tray" ] # See https://github.com/tauri-apps/wry/issues/247 for more information # winrt = [ "windows-webview2", "windows" ] win32 = [ "webview2", "winapi", "webview2-sys" ] -webdriver = [ ] [dependencies] libc = "0.2" @@ -52,7 +50,7 @@ chrono = "0.4.19" tempfile = "3.2.0" [target."cfg(target_os = \"linux\")".dependencies] -webkit2gtk = { version = "0.11", features = [ "v2_18" ] } +webkit2gtk = { version = "0.11", features = [ "v2_10" ] } webkit2gtk-sys = "0.13.0" gio = "0.9" glib = "0.10" diff --git a/README.md b/README.md index 76c171b4e..d9c801389 100644 --- a/README.md +++ b/README.md @@ -32,17 +32,15 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application, }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); - let application = Application::new(None); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop)?; - let _webview = WebViewBuilder::new(window, &application)? + let _webview = WebViewBuilder::new(window)? .with_url("https://tauri.studio")? .build()?; diff --git a/bench/tests/src/cpu_intensive.rs b/bench/tests/src/cpu_intensive.rs index 7b3b10496..2389e12c6 100644 --- a/bench/tests/src/cpu_intensive.rs +++ b/bench/tests/src/cpu_intensive.rs @@ -10,13 +10,11 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, - Application, }, webview::{RpcRequest, WebViewBuilder}, }; let event_loop = EventLoop::new(); - let application = Application::new(None); let window = WindowBuilder::new().build(&event_loop).unwrap(); let handler = |_window: &Window, req: RpcRequest| { @@ -25,7 +23,7 @@ fn main() -> wry::Result<()> { } None }; - let webview = WebViewBuilder::new(window, &application) + let webview = WebViewBuilder::new(window) .unwrap() .with_custom_protocol("wry.bench".into(), move |_, requested_asset_path| { let requested_asset_path = requested_asset_path.replace("wry.bench://", ""); diff --git a/bench/tests/src/custom_protocol.rs b/bench/tests/src/custom_protocol.rs index cd6ce3b4f..2a3826921 100644 --- a/bench/tests/src/custom_protocol.rs +++ b/bench/tests/src/custom_protocol.rs @@ -16,13 +16,11 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, - Application, }, webview::{RpcRequest, WebViewBuilder}, }; let event_loop = EventLoop::new(); - let application = Application::new(None); let window = WindowBuilder::new().build(&event_loop).unwrap(); let handler = |_window: &Window, req: RpcRequest| { @@ -31,7 +29,7 @@ fn main() -> wry::Result<()> { } None }; - let webview = WebViewBuilder::new(window, &application) + let webview = WebViewBuilder::new(window) .unwrap() .with_rpc_handler(handler) .with_custom_protocol("wry.bench".into(), move |_, _| { diff --git a/bench/tests/src/hello_world.rs b/bench/tests/src/hello_world.rs index be165e081..624762ea0 100644 --- a/bench/tests/src/hello_world.rs +++ b/bench/tests/src/hello_world.rs @@ -16,13 +16,11 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, - Application, }, webview::{RpcRequest, WebViewBuilder}, }; let event_loop = EventLoop::new(); - let application = Application::new(None); let window = WindowBuilder::new().build(&event_loop).unwrap(); let url = r#"data:text/html, @@ -39,7 +37,7 @@ fn main() -> wry::Result<()> { } None }; - let webview = WebViewBuilder::new(window, &application) + let webview = WebViewBuilder::new(window) .unwrap() .with_url(url)? .with_rpc_handler(handler) diff --git a/examples/custom_data_directory.rs b/examples/custom_data_directory.rs index 334ecc35b..0bcd76a33 100644 --- a/examples/custom_data_directory.rs +++ b/examples/custom_data_directory.rs @@ -10,7 +10,6 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application, }, webview::WebViewBuilder, }; @@ -25,14 +24,14 @@ fn main() -> wry::Result<()> { println!("Webview storage path: {:#?}", &test_path); let event_loop = EventLoop::new(); - let application = Application::new(Some(test_path)); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop) .unwrap(); - let _webview = WebViewBuilder::new(window, &application) + let _webview = WebViewBuilder::new(window) .unwrap() .with_url("https://tauri.studio")? + .with_data_directory(test_path) .build()?; event_loop.run(move |event, _, control_flow| { diff --git a/examples/custom_protocol.rs b/examples/custom_protocol.rs index cbad56baf..434bb3545 100644 --- a/examples/custom_protocol.rs +++ b/examples/custom_protocol.rs @@ -8,19 +8,17 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application, }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); - let application = Application::new(None); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop) .unwrap(); - let _webview = WebViewBuilder::new(window, &application) + let _webview = WebViewBuilder::new(window) .unwrap() .with_custom_protocol("wry.dev".into(), move |_, requested_asset_path| { // remove the protocol from the path for easiest match diff --git a/examples/custom_titlebar.rs b/examples/custom_titlebar.rs index 2ab1e232f..c07323605 100644 --- a/examples/custom_titlebar.rs +++ b/examples/custom_titlebar.rs @@ -8,13 +8,11 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, - Application, }, webview::{RpcRequest, WebViewBuilder}, }; let event_loop = EventLoop::new(); - let application = Application::new(None); let mut webviews = std::collections::HashMap::new(); let window = WindowBuilder::new() .with_decorations(false) @@ -116,7 +114,7 @@ fn main() -> wry::Result<()> { None }; - let webview = WebViewBuilder::new(window, &application) + let webview = WebViewBuilder::new(window) .unwrap() .with_url(url)? .with_initialization_script(script) diff --git a/examples/detect_js_ecma.rs b/examples/detect_js_ecma.rs index 67f0a9338..a0c6517c0 100644 --- a/examples/detect_js_ecma.rs +++ b/examples/detect_js_ecma.rs @@ -2,19 +2,25 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use wry::application::Application; - fn main() -> wry::Result<()> { - use wry::application::{ - event::{Event, StartCause, WindowEvent}, - event_loop::{ControlFlow, EventLoop}, + use wry::{ + application::{ + event::{Event, StartCause, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, + }, + webview::WebViewBuilder, }; let event_loop = EventLoop::new(); - let application = Application::new(None); - let _webview = wry::Builder::new(&event_loop) - .title("Detect ECMAScript") - .initialization_script(r#" + let window = WindowBuilder::new() + .with_title("Detect ECMAScript") + .build(&event_loop) + .unwrap(); + let _webview = WebViewBuilder::new(window) + .unwrap() + .with_initialization_script( + r#" (function () { window.addEventListener('DOMContentLoaded', (event) => { @@ -98,7 +104,7 @@ fn main() -> wry::Result<()> { for (var j = 0; j < versionDetails.features.length; j++) { var feature = versionDetails.features[j]; tableElement.innerHTML += ` ${feature.name} ${feature.supported ? '✔' : '❌'} ` - if (!feature.supported) versionSupported = false; + if (!feature.supported) versionSupported = false; } summaryListElement.innerHTML += `
  • ${versionDetails.version}: ${versionSupported ? '✔' : '❌'}` } @@ -106,8 +112,8 @@ fn main() -> wry::Result<()> { }); })(); "#) - .url( - r#"data:text/html, + .with_url( + r#"data:text/html,

    ECMAScript support list:

    @@ -121,7 +127,8 @@ fn main() -> wry::Result<()> { "#, - )?.build(&application)?; + )? + .build()?; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/dragndrop.rs b/examples/dragndrop.rs index d60e33e62..5ff3231fc 100644 --- a/examples/dragndrop.rs +++ b/examples/dragndrop.rs @@ -14,15 +14,13 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application, }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); - let application = Application::new(None); let window = WindowBuilder::new().build(&event_loop).unwrap(); - let webview = WebViewBuilder::new(window, &application) + let webview = WebViewBuilder::new(window) .unwrap() .with_url(HTML)? .with_file_drop_handler(|_, data| { diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index 3ae0f80b6..f3b6c3900 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -8,19 +8,17 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Fullscreen, WindowBuilder}, - Application, }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); - let application = Application::new(None); let window = WindowBuilder::new() .with_title("3D Render Test") .with_fullscreen(Some(Fullscreen::Borderless(None))) .build(&event_loop) .unwrap(); - let webview = WebViewBuilder::new(window, &application) + let webview = WebViewBuilder::new(window) .unwrap() .with_url("https://www.wirple.com/")? .build()?; diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 0470f42b3..5187154ee 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -8,17 +8,15 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application, }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); - let application = Application::new(None); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop)?; - let _webview = WebViewBuilder::new(window, &application)? + let _webview = WebViewBuilder::new(window)? .with_url("https://tauri.studio")? .build()?; diff --git a/examples/html_test.rs b/examples/html_test.rs index 083de4785..195f5376b 100644 --- a/examples/html_test.rs +++ b/examples/html_test.rs @@ -8,17 +8,15 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application, }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); - let application = Application::new(None); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop)?; - let _webview = WebViewBuilder::new(window, &application)? + let _webview = WebViewBuilder::new(window)? .with_url("https://html5test.com")? .build()?; diff --git a/examples/menu_bar.rs b/examples/menu_bar.rs index 97255b4d3..a263335f5 100644 --- a/examples/menu_bar.rs +++ b/examples/menu_bar.rs @@ -10,7 +10,6 @@ fn main() -> wry::Result<()> { event_loop::{ControlFlow, EventLoop}, menu::{Menu, MenuItem, MenuType}, window::WindowBuilder, - Application, }, webview::WebViewBuilder, }; @@ -86,17 +85,13 @@ fn main() -> wry::Result<()> { // Build our event loop let event_loop = EventLoop::new(); - - // Build our application context - let application = Application::new(None); - // Build the window let window = WindowBuilder::new() .with_title("Hello World") .with_menu(menu) .build(&event_loop)?; // Build the webview - let webview = WebViewBuilder::new(window, &application)? + let webview = WebViewBuilder::new(window)? .with_url("https://tauri.studio")? .build()?; // launch WRY process diff --git a/examples/multi_window.rs b/examples/multi_window.rs index aa94bd4bc..eb7c4b60b 100644 --- a/examples/multi_window.rs +++ b/examples/multi_window.rs @@ -20,14 +20,13 @@ fn main() -> wry::Result<()> { dpi::PhysicalSize, event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, - window::Window, - Application, + window::{Window, WindowBuilder}, }, - webview::RpcRequest, + webview::{RpcRequest, WebViewBuilder}, }; let event_loop = EventLoop::new(); - let application = Application::new(None); + let window1 = WindowBuilder::new().build(&event_loop).unwrap(); let (window_tx, window_rx) = std::sync::mpsc::channel::(); let handler = move |_window: &Window, req: RpcRequest| { @@ -41,17 +40,17 @@ fn main() -> wry::Result<()> { None }; - let webview1 = wry::Builder::new(&event_loop) - .url("https://tauri.studio")? - .initialization_script( + let id = window1.id(); + let webview1 = WebViewBuilder::new(window1) + .unwrap() + .with_url("https://tauri.studio")? + .with_initialization_script( r#"async function openWindow() { await window.rpc.notify("openWindow", "https://i.imgur.com/x6tXcr9.gif"); }"#, ) - .rpc_handler(handler) - .build(&application)?; - let id = webview1.window().id(); - + .with_rpc_handler(handler) + .build()?; let mut webviews = HashMap::new(); webviews.insert(id, webview1); @@ -62,14 +61,18 @@ fn main() -> wry::Result<()> { *control_flow = ControlFlow::Wait; if let Ok(url) = window_rx.try_recv() { - let webview2 = wry::Builder::new(&event_loop) - .title("RODA RORA DA") - .inner_size(PhysicalSize::new(426, 197)) - .url(&url) + let window2 = WindowBuilder::new() + .with_title("RODA RORA DA") + .with_inner_size(PhysicalSize::new(426, 197)) + .build(&event_loop) + .unwrap(); + let id = window2.id(); + let webview2 = WebViewBuilder::new(window2) + .unwrap() + .with_url(&url) .unwrap() - .build(&application) + .build() .unwrap(); - let id = webview2.window().id(); webviews.insert(id, webview2); } else if trigger && instant.elapsed() >= eight_secs { webviews diff --git a/examples/rpc.rs b/examples/rpc.rs index d26d2b8a2..e8d884ad8 100644 --- a/examples/rpc.rs +++ b/examples/rpc.rs @@ -16,13 +16,11 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Fullscreen, Window, WindowBuilder}, - Application, }, webview::{RpcRequest, RpcResponse, WebViewBuilder}, }; let event_loop = EventLoop::new(); - let application = Application::new(None); let window = WindowBuilder::new().build(&event_loop).unwrap(); let url = r#"data:text/html, @@ -78,7 +76,7 @@ async function getAsyncRpcResult() { response }; - let webview = WebViewBuilder::new(window, &application) + let webview = WebViewBuilder::new(window) .unwrap() .with_url(url)? .with_rpc_handler(handler) diff --git a/examples/system_tray.rs b/examples/system_tray.rs index 19a8e6c38..d48de2487 100644 --- a/examples/system_tray.rs +++ b/examples/system_tray.rs @@ -14,14 +14,12 @@ fn main() -> wry::Result<()> { menu::{MenuItem, MenuType}, platform::system_tray::SystemTrayBuilder, window::Window, - Application, }, webview::WebViewBuilder, }; // Build our event loop let event_loop = EventLoop::new(); - let application = Application::new(None); let mut webviews = HashMap::new(); // Create sample menu item @@ -64,7 +62,7 @@ fn main() -> wry::Result<()> { if menu_id == open_new_window_id { let window = Window::new(&event_loop).unwrap(); let id = window.id(); - let webview = WebViewBuilder::new(window, &application) + let webview = WebViewBuilder::new(window) .unwrap() .with_url("https://tauri.studio") .unwrap() diff --git a/examples/transparent.rs b/examples/transparent.rs index 681a570c1..8d62b8196 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -8,13 +8,11 @@ fn main() -> wry::Result<()> { event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application, }, webview::WebViewBuilder, }; let event_loop = EventLoop::new(); - let application = Application::new(None); let window = WindowBuilder::new() .with_decorations(false) // There are actually three layer of background color when creating webview window. @@ -23,7 +21,7 @@ fn main() -> wry::Result<()> { .build(&event_loop) .unwrap(); - let webview = WebViewBuilder::new(window, &application)? + let webview = WebViewBuilder::new(window)? // The second is on webview... .with_transparent(true) // And the last is in html. diff --git a/examples/validate_webview.rs b/examples/validate_webview.rs index 50f333af5..fd98644b6 100644 --- a/examples/validate_webview.rs +++ b/examples/validate_webview.rs @@ -8,7 +8,6 @@ fn main() -> wry::Result<()> { event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, - Application, }, webview::{webview_version, WebViewBuilder}, }; @@ -22,11 +21,10 @@ fn main() -> wry::Result<()> { ); let event_loop = EventLoop::new(); - let application = Application::new(None); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop)?; - let _webview = WebViewBuilder::new(window, &application)? + let _webview = WebViewBuilder::new(window)? .with_url("https://tauri.studio")? .build()?; diff --git a/src/application/mod.rs b/src/application/mod.rs index 1a3fa9f9d..80751a03c 100644 --- a/src/application/mod.rs +++ b/src/application/mod.rs @@ -10,162 +10,3 @@ //! [tao]: https://crates.io/crates/tao pub use tao::*; - -/// A single browser context. -/// -/// Think of this like a browser session. Incognito mode would be a single context even though -/// it has multiple tab/windows. -pub struct Application { - #[allow(dead_code)] - inner: ApplicationInner, -} - -impl Application { - pub fn new(data_directory: Option) -> Self { - Self { - inner: ApplicationInner::new(data_directory), - } - } -} - -#[cfg(target_os = "linux")] -use self::unix::ApplicationInner; - -#[cfg(target_os = "windows")] -use self::windows::ApplicationInner; - -#[cfg(target_os = "macos")] -use self::macos::ApplicationInner; - -#[cfg(target_os = "linux")] -#[cfg_attr(doc_cfg, doc(cfg(target_os = "linux")))] -pub mod unix { - //! Unix platform extensions for [`Application`](super::Application). - use std::path::PathBuf; - use webkit2gtk::{WebContext, WebContextBuilder, WebContextExt, WebsiteDataManagerBuilder}; - - pub(crate) struct ApplicationInner { - context: WebContext, - automation: bool, - } - - impl ApplicationInner { - pub fn new(data_directory: Option) -> Self { - let mut context_builder = WebContextBuilder::new(); - if let Some(data_directory) = data_directory { - let data_manager = WebsiteDataManagerBuilder::new() - .local_storage_directory( - &data_directory - .join("localstorage") - .to_string_lossy() - .into_owned(), - ) - .indexeddb_directory( - &data_directory - .join("databases") - .join("indexeddb") - .to_string_lossy() - .into_owned(), - ) - .build(); - context_builder = context_builder.website_data_manager(&data_manager); - } - - let context = context_builder.build(); - let automation = automation_flag(true); - context.set_automation_allowed(automation); - - Self { - context, - automation, - } - } - } - - /// [`Application`](super::Application) items that only matter on unix. - pub trait ApplicationExt { - /// The context of all webviews opened. - fn context(&self) -> &WebContext; - - /// If the context allows automation. - /// - /// **Note:** `libwebkit2gtk` only allows 1 automation context at a time. - fn allows_automation(&self) -> bool; - - /// Set if this context allows automation. - /// - /// **Note:** This has no effect if `ENABLE_WEBDRIVER=true` was not set during build time. - fn set_automation_allowed(&mut self, flag: bool); - } - - impl ApplicationExt for super::Application { - fn context(&self) -> &WebContext { - &self.inner.context - } - - fn allows_automation(&self) -> bool { - self.inner.automation - } - - fn set_automation_allowed(&mut self, flag: bool) { - let original = self.inner.automation; - let new = automation_flag(flag); - if new != original { - self.inner.automation = flag; - self.inner.context.set_automation_allowed(flag); - } - } - } - - /// Set the automation flag if the the `webdriver` feature is set. - fn automation_flag(flag: bool) -> bool { - match cfg!(feature = "webdriver") { - true => flag, - _ => false, - } - } -} - -#[cfg(target_os = "windows")] -#[cfg_attr(doc_cfg, doc(cfg(target_os = "windows")))] -pub(crate) mod windows { - use std::{ - env::var, - path::{Path, PathBuf}, - }; - - pub struct ApplicationInner { - data_directory: Option, - } - - impl ApplicationInner { - pub fn new(data_directory: Option) -> Self { - Self { data_directory } - } - } - - /// [`Application`](super::Application) items that only matter on windows. - pub trait ApplicationExt { - fn data_directory(&self) -> Option<&Path>; - } - - impl ApplicationExt for super::Application { - fn data_directory(&self) -> Option<&Path> { - self.inner.data_directory.as_deref() - } - } -} - -#[cfg(target_os = "macos")] -#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))] -pub(crate) mod macos { - use std::path::PathBuf; - - pub struct ApplicationInner; - - impl ApplicationInner { - pub fn new(_data_directory: Option) -> Self { - Self - } - } -} diff --git a/src/builder.rs b/src/builder.rs deleted file mode 100644 index 9753ade38..000000000 --- a/src/builder.rs +++ /dev/null @@ -1,325 +0,0 @@ -//! A builder that wraps both [`WindowBuilder`] and [`WebViewBuilder`]. - -use crate::{ - application::{ - window::{Window, WindowBuilder}, - Application, - }, - webview::{Dispatcher, FileDropEvent, RpcRequest, RpcResponse, WebView, WebViewBuilder}, -}; - -use tao::{ - dpi::{Position, Size}, - event_loop::EventLoopWindowTarget, - menu::Menu, - window::{Fullscreen, Icon}, -}; - -macro_rules! window_builder { - ( - $(#[$meta:meta])+ - method => $method:ident, - original => $original:ident, - $( - arg => $arg:ident: $type:path, - $(generic => $generic:path)? - )? - ) => { - $(#[$meta])+ - #[doc = ""] - #[doc = "_**Note:** if the [`Builder`] was created with [`Builder::with_window`] then this method will have no effect._"] - #[inline] - pub fn $method $($()?)? (mut self $(, $arg: $type)? ) -> Self { - if let BuilderWindowBuilder::Builder { builder, event_loop } = self.window { - self.window = BuilderWindowBuilder::Builder { - builder: builder.$original($($arg)?), - event_loop - }; - } - - self - } - }; -} - -/// lol what do i call this -enum BuilderWindowBuilder<'event, Event: 'static> { - Window(Window), - Builder { - builder: WindowBuilder, - event_loop: &'event EventLoopWindowTarget, - }, -} - -/// A streamlined builder to create a [`WebView`](crate::webview::WebView). -/// -/// You can instead use [`WindowBuilder`] and [`WebViewBuilder`] if you wish to separate the -/// builders. -pub struct Builder<'event, Event: 'static> { - window: BuilderWindowBuilder<'event, Event>, - webview: WebViewBuilder, -} - -impl<'event, Event: 'static> Builder<'event, Event> { - /// Create a new [`Builder`] attached to an existing [`EventLoop`](tao::event_loop::EventLoop). - #[inline] - pub fn new(event_loop: &'event EventLoopWindowTarget) -> Self { - Builder { - window: BuilderWindowBuilder::Builder { - builder: WindowBuilder::new(), - event_loop, - }, - webview: WebViewBuilder::new(), - } - } - - /// Create a new [`Builder`] with an already built [`Window`]. - /// - /// You should still have the [`EventLoop`] you created the [`Window`] with if you want to control - /// the [`WebView`] resulting from this [`Builder`]. - /// - /// [`EventLoop`]: tao::event_loop::EventLoop - #[inline] - pub fn with_window(window: Window) -> Self { - Self { - window: BuilderWindowBuilder::Window(window), - webview: WebViewBuilder::new(), - } - } - - window_builder! { - /// Requests the window to be of specific dimensions. - /// - /// See [`WindowBuilder::with_inner_size`] for details. - method => inner_size, - original => with_inner_size, - arg => size: T, - generic => Into - } - - window_builder! { - /// Sets a minimum dimension size for the window. - /// - /// See [`WindowBuilder::with_min_inner_size`] for details. - method => min_inner_size, - original => with_min_inner_size, - arg => min_size: T, - generic => Into - } - - window_builder! { - /// Sets a maximum dimension size for the window. - /// - /// See [`WindowBuilder::with_max_inner_size`] for details. - method => max_inner_size, - original => with_max_inner_size, - arg => max_size: T, - generic => Into - } - - window_builder! { - /// Sets a desired initial position for the window. - /// - /// See [`WindowBuilder::with_position`] for details. - method => position, - original => with_position, - arg => position: T, - generic => Into - } - - window_builder! { - /// Sets whether the window is resizable or not. - /// - /// See [`WindowBuilder::with_resizable`] for details. - method => resizable, - original => with_resizable, - arg => resizable: bool, - } - - window_builder! { - /// Requests a specific title for the window. - /// - /// See [`WindowBuilder::with_title`] for details. - method => title, - original => with_title, - arg => title: T, - generic => Into - } - - window_builder! { - /// Requests a specific menu for the window. - /// - /// See [`WindowBuilder::with_menu`] for details. - method => menu, - original => with_menu, - arg => menu: T, - generic => Into> - } - - window_builder! { - /// Sets the window fullscreen state. - /// - /// See [`WindowBuilder::with_fullscreen`] for details. - method => fullscreen, - original => with_fullscreen, - arg => fullscreen: Option, - } - - window_builder! { - /// Requests maximized mode. - /// - /// See [`WindowBuilder::with_maximized`] for details. - method => maximized, - original => with_maximized, - arg => maximized: bool, - } - - window_builder! { - /// Sets whether the window will be initially hidden or visible. - /// - /// See [`WindowBuilder::with_visible`] for details. - method => visible, - original => with_visible, - arg => visible: bool, - } - - // todo: this is the only setter that doesn't take a bool and that seems wrong on a builder - window_builder! { - /// Sets whether the window will be initially hidden or focus. - /// - /// See [`WindowBuilder::with_focus`] for details. - method => focus, - original => with_focus, - } - - window_builder! { - /// Sets whether the background of the window should be transparent. - /// - /// See [`WindowBuilder::with_transparent`] for details. - method => transparent_window, - original => with_transparent, - arg => transparent: bool, - } - - window_builder! { - /// Sets whether the window should have a border, a title bar, etc. - /// - /// See [`WindowBuilder::with_decorations`] for details. - method => decorations, - original => with_decorations, - arg => decorations: bool, - } - - window_builder! { - /// Sets whether or not the window will always be on top of other windows. - /// - /// See [`WindowBuilder::with_always_on_top`] for details. - method => always_on_top, - original => with_always_on_top, - arg => always_on_top: bool, - } - - window_builder! { - /// Sets the window icon. - /// - /// See [`WindowBuilder::with_window_icon`] for details. - method => window_icon, - original => with_window_icon, - arg => window_icon: Option, - } - - /// Whether the [`WebView`] should be transparent. - /// - /// See [`WebViewBuilder::with_transparent`] for details. - #[inline] - pub fn transparent_webview(mut self, transparent: bool) -> Self { - self.webview = self.webview.with_transparent(transparent); - self - } - - /// Set both the [`Window`] and [`WebView`] to be transparent. - /// - /// See [`Builder::transparent_window`] and [`Builder::transparent_webview`] for details. - #[inline] - pub fn transparent(self, transparent: bool) -> Self { - self - .transparent_window(transparent) - .transparent_webview(transparent) - } - - /// Initialize javascript code when loading new pages. - /// - /// See [`WebViewBuilder::with_initialization_script`] for details. - #[inline] - pub fn initialization_script(mut self, js: &str) -> Self { - self.webview = self.webview.with_initialization_script(js); - self - } - - /// Create a [`Dispatcher`] to send evaluation scripts to the [`WebView`]. - /// - /// See [`WebViewBuilder::dispatcher`] for details. - #[inline] - pub fn dispatcher(&self) -> Dispatcher { - self.webview.dispatcher() - } - - /// Register custom file loading protocol. - /// - /// See [`WebViewBuilder::with_custom_protocol`] for details. - #[inline] - pub fn custom_protocol(mut self, name: String, handler: F) -> Self - where - F: Fn(&Window, &str) -> crate::Result> + 'static, - { - self.webview = self.webview.with_custom_protocol(name, handler); - self - } - - /// Set the RPC handler to Communicate between the host Rust code and Javascript on [`WebView`]. - /// - /// See [`WebViewBuilder::with_rpc_handler`] for details. - #[inline] - pub fn rpc_handler(mut self, handler: F) -> Self - where - F: Fn(&Window, RpcRequest) -> Option + 'static, - { - self.webview = self.webview.with_rpc_handler(handler); - self - } - - /// Set a handler closure to process incoming [`FileDropEvent`] of the [`WebView`]. - /// - /// See [`WebViewBuilder::with_file_drop_handler`] for details. - #[inline] - pub fn file_drop_handler(mut self, handler: F) -> Self - where - F: Fn(&Window, FileDropEvent) -> bool + 'static, - { - self.webview = self.webview.with_file_drop_handler(handler); - self - } - - /// The URL to initialize the [`WebView`] with. - /// - /// See [`WebViewBuilder::with_url`] for details. - #[inline] - pub fn url(mut self, url: &str) -> crate::Result { - self.webview = self.webview.with_url(url)?; - Ok(self) - } - - /// Build the resulting [`WebView`]. - #[inline] - pub fn build(self, application: &Application) -> crate::Result { - let window = match self.window { - BuilderWindowBuilder::Window(window) => window, - BuilderWindowBuilder::Builder { - builder, - event_loop, - } => builder.build(event_loop)?, - }; - - self.webview.build(window, application) - } -} diff --git a/src/lib.rs b/src/lib.rs index cf9b0c469..a4028a841 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,17 +16,15 @@ //! event::{Event, StartCause, WindowEvent}, //! event_loop::{ControlFlow, EventLoop}, //! window::WindowBuilder, -//! Application //! }, //! webview::WebViewBuilder, //! }; //! //! let event_loop = EventLoop::new(); -//! let application = Application::new(None); //! let window = WindowBuilder::new() //! .with_title("Hello World") //! .build(&event_loop)?; -//! let _webview = WebViewBuilder::new(window, &application)? +//! let _webview = WebViewBuilder::new(window)? //! .with_url("https://tauri.studio")? //! .build()?; //! @@ -79,7 +77,6 @@ //! [`with_file_drop_handler`]: crate::webview::WebView::with_file_drop_handler //! [`with_custom_protocol`]: crate::webview::WebView::with_custom_protocol -#![cfg_attr(doc_cfg, feature(doc_cfg))] #![allow(clippy::new_without_default)] #![allow(clippy::wrong_self_convention)] #![allow(clippy::too_many_arguments)] @@ -103,12 +100,8 @@ pub use serde_json::Value; use url::ParseError; pub mod application; -mod builder; pub mod webview; -// expose the builder on the root namespace so it can be used as wry::Builder -pub use builder::Builder; - /// Convenient type alias of Result type for wry. pub type Result = std::result::Result; diff --git a/src/webview/mod.rs b/src/webview/mod.rs index bcff64dab..43647ea0b 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -32,7 +32,7 @@ use url::Url; #[cfg(target_os = "windows")] use crate::application::platform::windows::WindowExtWindows; -use crate::application::{window::Window, Application}; +use crate::application::window::Window; #[cfg(target_os = "windows")] #[cfg(feature = "winrt")] use windows_webview2::Windows::Win32::WindowsAndMessaging::HWND; @@ -78,27 +78,31 @@ pub struct WebViewBuilder { tx: Sender, rx: Receiver, initialization_scripts: Vec, + window: Window, url: Option, custom_protocols: Vec<(String, Box Result>>)>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, + data_directory: Option, } impl WebViewBuilder { /// Create [`WebViewBuilder`] from provided [`Window`]. - pub fn new() -> Self { + pub fn new(window: Window) -> Result { let (tx, rx) = channel(); - Self { + Ok(Self { tx, rx, initialization_scripts: vec![], + window, url: None, transparent: false, custom_protocols: vec![], rpc_handler: None, file_drop_handler: None, - } + data_directory: None, + }) } /// Whether the WebView window should be transparent. If this is true, writing colors @@ -116,6 +120,13 @@ impl WebViewBuilder { self } + /// Whether the WebView window should have a custom user data path. This is usefull in Windows + /// when a bundled application can't have the webview data inside `Program Files`. + pub fn with_data_directory(mut self, data_directory: PathBuf) -> Self { + self.data_directory.replace(data_directory); + self + } + /// Create a [`Dispatcher`] to send evaluation scripts to the WebView. [`WebView`] is not thread /// safe because it must be run on the main thread who creates it. [`Dispatcher`] can let you /// send the scripts from other threads. @@ -233,10 +244,9 @@ impl WebViewBuilder { /// called in the same thread with the [`EventLoop`] you create. /// /// [`EventLoop`]: crate::application::event_loop::EventLoop - pub fn build(self, window: Window, application: &Application) -> Result { - let window = Rc::new(window); + pub fn build(self) -> Result { + let window = Rc::new(self.window); let webview = InnerWebView::new( - application, window.clone(), self.initialization_scripts, self.url, @@ -244,6 +254,7 @@ impl WebViewBuilder { self.custom_protocols, self.rpc_handler, self.file_drop_handler, + self.data_directory, )?; Ok(WebView { window, @@ -296,8 +307,8 @@ impl WebView { /// called in the same thread with the [`EventLoop`] you create. /// /// [`EventLoop`]: crate::application::event_loop::EventLoop - pub fn new(window: Window, application: &Application) -> Result { - WebViewBuilder::new().build(window, application) + pub fn new(window: Window) -> Result { + WebViewBuilder::new(window)?.build() } /// Dispatch javascript code to be evaluated later. Note this will not actually run the diff --git a/src/webview/webkitgtk/mod.rs b/src/webview/webkitgtk/mod.rs index b4f50973a..142f3ab17 100644 --- a/src/webview/webkitgtk/mod.rs +++ b/src/webview/webkitgtk/mod.rs @@ -2,23 +2,25 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +use std::{path::PathBuf, rc::Rc}; + use gdk::{WindowEdge, WindowExt, RGBA}; use gio::Cancellable; use glib::{signal::Inhibit, Bytes, Cast, FileError}; -use gtk::{BoxExt, ContainerExt, GtkWindowExt, WidgetExt}; -use std::rc::Rc; +use gtk::{BoxExt, ContainerExt, WidgetExt}; use url::Url; use webkit2gtk::{ - ApplicationInfo, AutomationSessionExt, SecurityManagerExt, SettingsExt, URISchemeRequestExt, - UserContentInjectedFrames, UserContentManager, UserContentManagerExt, UserScript, - UserScriptInjectionTime, WebContextExt, WebView, WebViewBuilder, WebViewExt, + SecurityManagerExt, SettingsExt, URISchemeRequestExt, UserContentInjectedFrames, + UserContentManager, UserContentManagerExt, UserScript, UserScriptInjectionTime, + WebContextBuilder, WebContextExt, WebView, WebViewExt, WebViewExtManual, + WebsiteDataManagerBuilder, }; use webkit2gtk_sys::{ webkit_get_major_version, webkit_get_micro_version, webkit_get_minor_version, }; use crate::{ - application::{platform::unix::*, unix::ApplicationExt, window::Window, Application}, + application::{platform::unix::*, window::Window}, webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse}, Error, Result, }; @@ -31,7 +33,6 @@ pub struct InnerWebView { impl InnerWebView { pub fn new( - application: &Application, window: Rc, scripts: Vec, url: Option, @@ -42,32 +43,38 @@ impl InnerWebView { )>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, + data_directory: Option, ) -> Result { let window_rc = Rc::clone(&window); let window = &window.gtk_window(); - // Webview widget let manager = UserContentManager::new(); - let context = application.context(); - - let mut webview = WebViewBuilder::new(); - webview = webview.web_context(context); - webview = webview.user_content_manager(&manager); - webview = webview.is_controlled_by_automation(application.allows_automation()); - let webview = webview.build(); - - let auto_webview = webview.clone(); - context.connect_automation_started(move |_, auto| { - let webview = auto_webview.clone(); - let app_into = ApplicationInfo::new(); - app_into.set_name("wry"); - app_into.set_version(0, 9, 0); - auto.set_application_info(&app_into); - auto.connect_create_web_view(move |_| webview.clone()); - }); + let mut context_builder = WebContextBuilder::new(); + if let Some(data_directory) = data_directory { + let data_manager = WebsiteDataManagerBuilder::new() + .local_storage_directory( + &data_directory + .join("localstorage") + .to_string_lossy() + .into_owned(), + ) + .indexeddb_directory( + &data_directory + .join("databases") + .join("indexeddb") + .to_string_lossy() + .into_owned(), + ) + .build(); + context_builder = context_builder.website_data_manager(&data_manager); + } + let context = context_builder.build(); + + let webview = Rc::new(WebView::new_with_context_and_user_content_manager( + &context, &manager, + )); // Message handler - let webview = Rc::new(webview); let wv = Rc::clone(&webview); let w = window_rc.clone(); manager.register_script_message_handler("external"); @@ -91,12 +98,6 @@ impl InnerWebView { } }); - // todo: is this leaking memory when having programs longer than window close? - let close_window = window_rc.clone(); - webview.connect_close(move |_| { - close_window.gtk_window().close(); - }); - webview.connect_button_press_event(|webview, event| { if event.get_button() == 1 { let (cx, cy) = event.get_root(); diff --git a/src/webview/webview2/win32/mod.rs b/src/webview/webview2/win32/mod.rs index 49c0cfe80..71c38c357 100644 --- a/src/webview/webview2/win32/mod.rs +++ b/src/webview/webview2/win32/mod.rs @@ -11,22 +11,17 @@ use crate::{ use file_drop::FileDropController; -use std::{collections::HashSet, os::raw::c_void, rc::Rc}; +use std::{collections::HashSet, os::raw::c_void, path::PathBuf, rc::Rc}; use once_cell::unsync::OnceCell; use url::Url; use webview2::{Controller, PermissionKind, PermissionState, WebView}; -use winapi::{ - shared::{windef::HWND, winerror::E_FAIL}, - um::winuser::{DestroyWindow, GetClientRect}, -}; +use winapi::{shared::windef::HWND, um::winuser::GetClientRect}; use crate::application::{ event_loop::{ControlFlow, EventLoop}, platform::{run_return::EventLoopExtRunReturn, windows::WindowExtWindows}, window::Window, - windows::ApplicationExt, - Application, }; pub struct InnerWebView { @@ -40,7 +35,6 @@ pub struct InnerWebView { impl InnerWebView { pub fn new( - application: &Application, window: Rc, scripts: Vec, url: Option, @@ -51,6 +45,7 @@ impl InnerWebView { )>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, + data_directory: Option, ) -> Result { let hwnd = window.hwnd() as HWND; @@ -61,9 +56,12 @@ impl InnerWebView { let file_drop_controller_clone = file_drop_controller.clone(); let webview_builder: webview2::EnvironmentBuilder; + let data_directory_provided: PathBuf; - if let Some(data_directory) = application.data_directory() { - webview_builder = webview2::EnvironmentBuilder::new().with_user_data_folder(&data_directory); + if let Some(data_directory) = data_directory { + data_directory_provided = data_directory; + webview_builder = + webview2::EnvironmentBuilder::new().with_user_data_folder(&data_directory_provided); } else { webview_builder = webview2::EnvironmentBuilder::new(); } @@ -76,15 +74,6 @@ impl InnerWebView { let controller = controller?; let w = controller.get_webview()?; - // todo: is this leaking memory when having programs longer than window close? - w.add_window_close_requested(move |_| { - if unsafe { DestroyWindow(hwnd as HWND) } != 0 { - Ok(()) - } else { - Err(webview2::Error::new(E_FAIL)) - } - })?; - // Transparent if transparent { if let Ok(c2) = controller.get_controller2() { diff --git a/src/webview/webview2/winrt/mod.rs b/src/webview/webview2/winrt/mod.rs index f47499d90..fcf75e875 100644 --- a/src/webview/webview2/winrt/mod.rs +++ b/src/webview/webview2/winrt/mod.rs @@ -37,8 +37,6 @@ use crate::application::{ event_loop::{ControlFlow, EventLoop}, platform::{run_return::EventLoopExtRunReturn, windows::WindowExtWindows}, window::Window, - windows::ApplicationWinExt, - Application, }; pub struct InnerWebView { @@ -53,7 +51,6 @@ pub struct InnerWebView { impl InnerWebView { pub fn new( - application: &Application, window: Rc, scripts: Vec, url: Option, @@ -66,6 +63,7 @@ impl InnerWebView { )>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, + data_directory: Option, ) -> Result { let hwnd = HWND(window.hwnd() as _); @@ -73,7 +71,7 @@ impl InnerWebView { let webview_rc: Rc> = Rc::new(OnceCell::new()); let file_drop_controller_rc: Rc> = Rc::new(OnceCell::new()); - let env = wait_for_async_operation(match application.data_directory() { + let env = wait_for_async_operation(match data_directory { Some(data_directory_provided) => webview2::CoreWebView2Environment::CreateWithOptionsAsync( "", data_directory_provided.to_str().unwrap_or(""), @@ -108,8 +106,6 @@ impl InnerWebView { })?; } - // TODO: close window upon request like win32 add_window_close_requested - // Initialize scripts wait_for_async_operation(w.AddScriptToExecuteOnDocumentCreatedAsync( "window.external={invoke:s=>window.chrome.webview.postMessage(s)}", diff --git a/src/webview/wkwebview/mod.rs b/src/webview/wkwebview/mod.rs index fd13c1365..1d21db456 100644 --- a/src/webview/wkwebview/mod.rs +++ b/src/webview/wkwebview/mod.rs @@ -5,6 +5,7 @@ use std::{ ffi::{c_void, CStr}, os::raw::c_char, + path::PathBuf, ptr::{null, null_mut}, rc::Rc, slice, str, @@ -34,7 +35,7 @@ use file_drop::{add_file_drop_methods, set_file_drop_handler}; use crate::application::platform::ios::WindowExtIOS; use crate::{ - application::{window::Window, Application}, + application::window::Window, webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse}, Result, }; @@ -58,7 +59,6 @@ pub struct InnerWebView { impl InnerWebView { pub fn new( - _application: &Application, window: Rc, scripts: Vec, url: Option, @@ -69,6 +69,7 @@ impl InnerWebView { )>, rpc_handler: Option Option>>, _file_drop_handler: Option bool>>, + _data_directory: Option, ) -> Result { // Function for rpc handler extern "C" fn did_receive(this: &Object, _: Sel, _: id, msg: id) { From d82d857cfc61cc23d3342cf9cb9b62fc94aeb3df Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 09:23:14 -0700 Subject: [PATCH 27/44] update webkit2gtk to v2_18 to allow for automation --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e0f022141..0c761566c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ chrono = "0.4.19" tempfile = "3.2.0" [target."cfg(target_os = \"linux\")".dependencies] -webkit2gtk = { version = "0.11", features = [ "v2_10" ] } +webkit2gtk = { version = "0.11", features = [ "v2_18" ] } webkit2gtk-sys = "0.13.0" gio = "0.9" glib = "0.10" From 238b67d74d4a2fa29d4c8c2471aa13db412f386c Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 09:23:32 -0700 Subject: [PATCH 28/44] set custom cfg on rustdocs to allow for nightly doc features --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 0c761566c..28929a7c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ categories = [ "gui" ] [package.metadata.docs.rs] features = [ "dox" ] +rustdoc-args = [ "--cfg", "doc_cfg" ] default-target = "x86_64-unknown-linux-gnu" targets = [ "x86_64-pc-windows-msvc", From 48823c5dbedc1f6b627452e8575019cd0491e308 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 09:25:13 -0700 Subject: [PATCH 29/44] simplify application module --- src/{application/mod.rs => application.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{application/mod.rs => application.rs} (100%) diff --git a/src/application/mod.rs b/src/application.rs similarity index 100% rename from src/application/mod.rs rename to src/application.rs From edc6a38877496cacb458221a31cda9f1198c94f5 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 10:08:53 -0700 Subject: [PATCH 30/44] enable nightly doc features when cfg is set --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index a4028a841..8a69a2675 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,6 +77,7 @@ //! [`with_file_drop_handler`]: crate::webview::WebView::with_file_drop_handler //! [`with_custom_protocol`]: crate::webview::WebView::with_custom_protocol +#![cfg_attr(doc_cfg, feature(doc_cfg))] #![allow(clippy::new_without_default)] #![allow(clippy::wrong_self_convention)] #![allow(clippy::too_many_arguments)] From 4f993821756e504f18ea8ff56f41283276d51e90 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 10:32:48 -0700 Subject: [PATCH 31/44] add WebContext as a required item to `WebViewBuilder` --- src/webview/mod.rs | 26 ++--- src/webview/web_context.rs | 170 ++++++++++++++++++++++++++++++ src/webview/webkitgtk/mod.rs | 63 +++++------ src/webview/webview2/win32/mod.rs | 28 +++-- src/webview/wkwebview/mod.rs | 4 +- 5 files changed, 232 insertions(+), 59 deletions(-) create mode 100644 src/webview/web_context.rs diff --git a/src/webview/mod.rs b/src/webview/mod.rs index 43647ea0b..7924f759b 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -5,6 +5,9 @@ //! [`WebView`] struct and associated types. mod mimetype; +mod web_context; + +pub use web_context::WebContext; #[cfg(target_os = "linux")] mod webkitgtk; @@ -73,7 +76,7 @@ fn rpc_proxy( /// [`WebViewBuilder`] / [`WebView`] are the basic building blocks to constrcut WebView contents and /// scripts for those who prefer to control fine grained window creation and event handling. /// [`WebViewBuilder`] privides ability to setup initialization before web engine starts. -pub struct WebViewBuilder { +pub struct WebViewBuilder<'ctx> { transparent: bool, tx: Sender, rx: Receiver, @@ -83,12 +86,12 @@ pub struct WebViewBuilder { custom_protocols: Vec<(String, Box Result>>)>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, - data_directory: Option, + web_context: &'ctx WebContext, } -impl WebViewBuilder { +impl<'ctx> WebViewBuilder<'ctx> { /// Create [`WebViewBuilder`] from provided [`Window`]. - pub fn new(window: Window) -> Result { + pub fn new(window: Window, web_context: &'ctx WebContext) -> Result { let (tx, rx) = channel(); Ok(Self { @@ -101,7 +104,7 @@ impl WebViewBuilder { custom_protocols: vec![], rpc_handler: None, file_drop_handler: None, - data_directory: None, + web_context, }) } @@ -120,13 +123,6 @@ impl WebViewBuilder { self } - /// Whether the WebView window should have a custom user data path. This is usefull in Windows - /// when a bundled application can't have the webview data inside `Program Files`. - pub fn with_data_directory(mut self, data_directory: PathBuf) -> Self { - self.data_directory.replace(data_directory); - self - } - /// Create a [`Dispatcher`] to send evaluation scripts to the WebView. [`WebView`] is not thread /// safe because it must be run on the main thread who creates it. [`Dispatcher`] can let you /// send the scripts from other threads. @@ -254,7 +250,7 @@ impl WebViewBuilder { self.custom_protocols, self.rpc_handler, self.file_drop_handler, - self.data_directory, + self.web_context, )?; Ok(WebView { window, @@ -307,8 +303,8 @@ impl WebView { /// called in the same thread with the [`EventLoop`] you create. /// /// [`EventLoop`]: crate::application::event_loop::EventLoop - pub fn new(window: Window) -> Result { - WebViewBuilder::new(window)?.build() + pub fn new(window: Window, web_context: &WebContext) -> Result { + WebViewBuilder::new(window, web_context)?.build() } /// Dispatch javascript code to be evaluated later. Note this will not actually run the diff --git a/src/webview/web_context.rs b/src/webview/web_context.rs new file mode 100644 index 000000000..7d970b985 --- /dev/null +++ b/src/webview/web_context.rs @@ -0,0 +1,170 @@ +use std::path::{Path, PathBuf}; + +/// A context that is shared between multiple [`WebView`]s. +/// +/// A browser would have a context for all the normal tabs and a different context for all the +/// private/incognito tabs. +pub struct WebContext { + data: WebContextData, + os: WebContextImpl, +} + +impl WebContext { + /// Create a new [`WebContext`]. + /// + /// `data_directory`: + /// * Whether the WebView window should have a custom user data path. This is useful in Windows + /// when a bundled application can't have the webview data inside `Program Files`. + pub fn new(data_directory: Option) -> Self { + let data = WebContextData { data_directory }; + let os = WebContextImpl::new(&data); + Self { data, os } + } + + /// A reference to the data directory the context was created with. + pub fn data_directory(&self) -> Option<&Path> { + self.data.data_directory() + } +} + +impl Default for WebContext { + fn default() -> Self { + let data = WebContextData::default(); + let os = WebContextImpl::new(&data); + Self { data, os } + } +} + +/// Data that all [`WebContext`] share regardless of platform. +#[derive(Default)] +struct WebContextData { + data_directory: Option, +} + +impl WebContextData { + /// A reference to the data directory the context was created with. + pub fn data_directory(&self) -> Option<&Path> { + self.data_directory.as_deref() + } +} + +#[cfg(not(target_os = "linux"))] +#[cfg_attr(doc_cfg, doc(cfg(not(target_os = "linux"))))] +pub struct WebContextImpl; + +#[cfg(not(target_os = "linux"))] +#[cfg_attr(doc_cfg, doc(cfg(not(target_os = "linux"))))] +impl WebContextImpl { + pub fn new(_data: &super::WebContextData) -> Self { + Self + } +} + +#[cfg(target_os = "linux")] +use self::unix::WebContextImpl; + +#[cfg(target_os = "linux")] +#[cfg_attr(doc_cfg, doc(cfg(target_os = "linux")))] +pub mod unix { + //! Unix platform extensions for [`WebContext`](super::WebContext). + + use webkit2gtk::{ + ApplicationInfo, WebContext, WebContextBuilder, WebContextExt as WebkitWebContextExt, + WebsiteDataManagerBuilder, + }; + + pub(super) struct WebContextImpl { + app_info: ApplicationInfo, + context: WebContext, + automation: bool, + } + + impl WebContextImpl { + pub fn new(data: &super::WebContextData) -> Self { + let mut context_builder = WebContextBuilder::new(); + if let Some(data_directory) = data.data_directory() { + let data_manager = WebsiteDataManagerBuilder::new() + .local_storage_directory( + &data_directory + .join("localstorage") + .to_string_lossy() + .into_owned(), + ) + .indexeddb_directory( + &data_directory + .join("databases") + .join("indexeddb") + .to_string_lossy() + .into_owned(), + ) + .build(); + context_builder = context_builder.website_data_manager(&data_manager); + } + + let context = context_builder.build(); + + // default to true since other platforms don't have a way to disable it (yet) + let automation = true; + context.set_automation_allowed(automation); + + // e.g. wry 0.9.4 + let app_info = ApplicationInfo::new(); + app_info.set_name(env!("CARGO_PKG_NAME")); + app_info.set_version( + env!("CARGO_PKG_VERSION_MAJOR") + .parse() + .expect("invalid wry version major"), + env!("CARGO_PKG_VERSION_MINOR") + .parse() + .expect("invalid wry version minor"), + env!("CARGO_PKG_VERSION_PATCH") + .parse() + .expect("invalid wry version patch"), + ); + + Self { + app_info, + context, + automation, + } + } + } + + /// [`WebContext`](super::WebContext) items that only matter on unix. + pub trait WebContextExt { + /// The application info shared between webviews. + fn app_info(&self) -> &ApplicationInfo; + + /// The context of all webviews opened. + fn context(&self) -> &WebContext; + + /// If the context allows automation. + /// + /// **Note:** `libwebkit2gtk` only allows 1 automation context at a time. + fn allows_automation(&self) -> bool; + + /// Set if this context allows automation. + /// + /// **Note:** `libwebkit2gtk` only allows 1 automation context at a time. + fn set_allows_automation(&mut self, flag: bool); + } + + impl WebContextExt for super::WebContext { + fn app_info(&self) -> &ApplicationInfo { + &self.os.app_info + } + + fn context(&self) -> &WebContext { + &self.os.context + } + + fn allows_automation(&self) -> bool { + self.os.automation + } + + fn set_allows_automation(&mut self, flag: bool) { + self.os.automation = flag; + self.os.context.set_automation_allowed(flag); + } + } +} diff --git a/src/webview/webkitgtk/mod.rs b/src/webview/webkitgtk/mod.rs index 142f3ab17..0603966e8 100644 --- a/src/webview/webkitgtk/mod.rs +++ b/src/webview/webkitgtk/mod.rs @@ -2,18 +2,18 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use std::{path::PathBuf, rc::Rc}; +use std::rc::Rc; use gdk::{WindowEdge, WindowExt, RGBA}; use gio::Cancellable; use glib::{signal::Inhibit, Bytes, Cast, FileError}; -use gtk::{BoxExt, ContainerExt, WidgetExt}; +use gtk::{BoxExt, ContainerExt, GtkWindowExt, WidgetExt}; use url::Url; use webkit2gtk::{ - SecurityManagerExt, SettingsExt, URISchemeRequestExt, UserContentInjectedFrames, - UserContentManager, UserContentManagerExt, UserScript, UserScriptInjectionTime, - WebContextBuilder, WebContextExt, WebView, WebViewExt, WebViewExtManual, - WebsiteDataManagerBuilder, + AutomationSessionExt, SecurityManagerExt, SettingsExt, URISchemeRequestExt, + UserContentInjectedFrames, UserContentManager, UserContentManagerExt, UserScript, + UserScriptInjectionTime, WebContextExt as WebKitWebContextExt, WebView, WebViewBuilder, + WebViewExt, }; use webkit2gtk_sys::{ webkit_get_major_version, webkit_get_micro_version, webkit_get_minor_version, @@ -21,7 +21,11 @@ use webkit2gtk_sys::{ use crate::{ application::{platform::unix::*, window::Window}, - webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse}, + webview::{ + mimetype::MimeType, + web_context::{unix::WebContextExt, WebContext}, + FileDropEvent, RpcRequest, RpcResponse, + }, Error, Result, }; @@ -43,38 +47,30 @@ impl InnerWebView { )>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, - data_directory: Option, + web_context: &WebContext, ) -> Result { let window_rc = Rc::clone(&window); let window = &window.gtk_window(); // Webview widget let manager = UserContentManager::new(); - let mut context_builder = WebContextBuilder::new(); - if let Some(data_directory) = data_directory { - let data_manager = WebsiteDataManagerBuilder::new() - .local_storage_directory( - &data_directory - .join("localstorage") - .to_string_lossy() - .into_owned(), - ) - .indexeddb_directory( - &data_directory - .join("databases") - .join("indexeddb") - .to_string_lossy() - .into_owned(), - ) - .build(); - context_builder = context_builder.website_data_manager(&data_manager); - } - let context = context_builder.build(); - let webview = Rc::new(WebView::new_with_context_and_user_content_manager( - &context, &manager, - )); + let context = web_context.context(); + let mut webview = WebViewBuilder::new(); + webview = webview.web_context(context); + webview = webview.user_content_manager(&manager); + webview = webview.is_controlled_by_automation(web_context.allows_automation()); + let webview = webview.build(); + + let automation_webview = webview.clone(); + let app_info = web_context.app_info().clone(); + context.connect_automation_started(move |_, auto| { + let webview = automation_webview.clone(); + auto.set_application_info(&app_info); + auto.connect_create_web_view(move |_| webview.clone()); + }); // Message handler + let webview = Rc::new(webview); let wv = Rc::clone(&webview); let w = window_rc.clone(); manager.register_script_message_handler("external"); @@ -98,6 +94,11 @@ impl InnerWebView { } }); + let close_window = window_rc.clone(); + webview.connect_close(move |_| { + close_window.gtk_window().close(); + }); + webview.connect_button_press_event(|webview, event| { if event.get_button() == 1 { let (cx, cy) = event.get_root(); diff --git a/src/webview/webview2/win32/mod.rs b/src/webview/webview2/win32/mod.rs index 71c38c357..61000d5b3 100644 --- a/src/webview/webview2/win32/mod.rs +++ b/src/webview/webview2/win32/mod.rs @@ -5,7 +5,7 @@ mod file_drop; use crate::{ - webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse}, + webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse, WebContext}, Result, }; @@ -16,7 +16,10 @@ use std::{collections::HashSet, os::raw::c_void, path::PathBuf, rc::Rc}; use once_cell::unsync::OnceCell; use url::Url; use webview2::{Controller, PermissionKind, PermissionState, WebView}; -use winapi::{shared::windef::HWND, um::winuser::GetClientRect}; +use winapi::{ + shared::{windef::HWND, winerror::E_FAIL}, + um::winuser::{DestroyWindow, GetClientRect}, +}; use crate::application::{ event_loop::{ControlFlow, EventLoop}, @@ -45,7 +48,7 @@ impl InnerWebView { )>, rpc_handler: Option Option>>, file_drop_handler: Option bool>>, - data_directory: Option, + web_context: &WebContext, ) -> Result { let hwnd = window.hwnd() as HWND; @@ -55,15 +58,10 @@ impl InnerWebView { let file_drop_controller: Rc> = Rc::new(OnceCell::new()); let file_drop_controller_clone = file_drop_controller.clone(); - let webview_builder: webview2::EnvironmentBuilder; - let data_directory_provided: PathBuf; + let mut webview_builder: webview2::EnvironmentBuilder::new(); - if let Some(data_directory) = data_directory { - data_directory_provided = data_directory; - webview_builder = - webview2::EnvironmentBuilder::new().with_user_data_folder(&data_directory_provided); - } else { - webview_builder = webview2::EnvironmentBuilder::new(); + if let Some(data_directory) = web_context.data_directory() { + webview_builder = webview_builder.with_user_data_folder(&data_directory); } // Webview controller @@ -74,6 +72,14 @@ impl InnerWebView { let controller = controller?; let w = controller.get_webview()?; + w.add_window_close_requested(move |_| { + if unsafe { DestroyWindow(hwnd as HWND) } != 0 { + Ok(()) + } else { + Err(webview2::Error::new(E_FAIL)) + } + })?; + // Transparent if transparent { if let Ok(c2) = controller.get_controller2() { diff --git a/src/webview/wkwebview/mod.rs b/src/webview/wkwebview/mod.rs index 1d21db456..131b9d03d 100644 --- a/src/webview/wkwebview/mod.rs +++ b/src/webview/wkwebview/mod.rs @@ -36,7 +36,7 @@ use crate::application::platform::ios::WindowExtIOS; use crate::{ application::window::Window, - webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse}, + webview::{mimetype::MimeType, FileDropEvent, RpcRequest, RpcResponse, WebContext}, Result, }; @@ -69,7 +69,7 @@ impl InnerWebView { )>, rpc_handler: Option Option>>, _file_drop_handler: Option bool>>, - _data_directory: Option, + _web_context: &WebContext, ) -> Result { // Function for rpc handler extern "C" fn did_receive(this: &Object, _: Sel, _: id, msg: id) { From d77b698bf3eeb3a05293dc2cd29ce7b8a5ee8653 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 10:51:08 -0700 Subject: [PATCH 32/44] add changes file --- .changes/web_context.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changes/web_context.md diff --git a/.changes/web_context.md b/.changes/web_context.md new file mode 100644 index 000000000..ecd1af558 --- /dev/null +++ b/.changes/web_context.md @@ -0,0 +1,5 @@ +--- +"wry": patch +--- + +Add `wry::webview::WebContext`. It's now a required argument on `WebViewBuilder::build`. From 93bb3026a7efab8fa1a76fa059cec91755207d6a Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 10:53:49 -0700 Subject: [PATCH 33/44] move web_context to build from new --- src/webview/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webview/mod.rs b/src/webview/mod.rs index 8b64d184c..2019dcdb1 100644 --- a/src/webview/mod.rs +++ b/src/webview/mod.rs @@ -318,7 +318,7 @@ impl WebView { /// /// [`EventLoop`]: crate::application::event_loop::EventLoop pub fn new(window: Window, web_context: &WebContext) -> Result { - WebViewBuilder::new(window, web_context)?.build() + WebViewBuilder::new(window)?.build(web_context) } /// Dispatch javascript code to be evaluated later. Note this will not actually run the From 2a271b92256b6266ca979cdfb6aa449f3faed814 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 10:59:43 -0700 Subject: [PATCH 34/44] update WebContextData path for windows,macos --- src/webview/web_context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webview/web_context.rs b/src/webview/web_context.rs index 7d970b985..0b5c0a7e9 100644 --- a/src/webview/web_context.rs +++ b/src/webview/web_context.rs @@ -55,7 +55,7 @@ pub struct WebContextImpl; #[cfg(not(target_os = "linux"))] #[cfg_attr(doc_cfg, doc(cfg(not(target_os = "linux"))))] impl WebContextImpl { - pub fn new(_data: &super::WebContextData) -> Self { + pub fn new(_data: &WebContextData) -> Self { Self } } From 247f69c628ff18a42fab02f607973244f834efbb Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 11:07:48 -0700 Subject: [PATCH 35/44] mark WebContextData as private --- src/webview/web_context.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webview/web_context.rs b/src/webview/web_context.rs index 0b5c0a7e9..c6f97ee73 100644 --- a/src/webview/web_context.rs +++ b/src/webview/web_context.rs @@ -50,12 +50,12 @@ impl WebContextData { #[cfg(not(target_os = "linux"))] #[cfg_attr(doc_cfg, doc(cfg(not(target_os = "linux"))))] -pub struct WebContextImpl; +struct WebContextImpl; #[cfg(not(target_os = "linux"))] #[cfg_attr(doc_cfg, doc(cfg(not(target_os = "linux"))))] impl WebContextImpl { - pub fn new(_data: &WebContextData) -> Self { + fn new(_data: &WebContextData) -> Self { Self } } From 440b9ae5d49f044a71422756b05eea8562a2de46 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 11:26:14 -0700 Subject: [PATCH 36/44] update examples and doc tests --- examples/custom_data_directory.rs | 6 +++--- examples/custom_protocol.rs | 2 +- examples/custom_titlebar.rs | 2 +- examples/detect_js_ecma.rs | 2 +- examples/dragndrop.rs | 2 +- examples/fullscreen.rs | 2 +- examples/hello_world.rs | 2 +- examples/html_test.rs | 2 +- examples/menu_bar.rs | 2 +- examples/multi_window.rs | 7 ++++--- examples/rpc.rs | 2 +- examples/system_tray.rs | 2 +- examples/transparent.rs | 2 +- examples/validate_webview.rs | 2 +- src/lib.rs | 2 +- 15 files changed, 20 insertions(+), 19 deletions(-) diff --git a/examples/custom_data_directory.rs b/examples/custom_data_directory.rs index 0bcd76a33..a44517d07 100644 --- a/examples/custom_data_directory.rs +++ b/examples/custom_data_directory.rs @@ -11,7 +11,7 @@ fn main() -> wry::Result<()> { event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, }, - webview::WebViewBuilder, + webview::{WebContext, WebViewBuilder}, }; // Use a sample directory at the root of the project @@ -24,6 +24,7 @@ fn main() -> wry::Result<()> { println!("Webview storage path: {:#?}", &test_path); let event_loop = EventLoop::new(); + let web_context = WebContext::new(Some(test_path)); let window = WindowBuilder::new() .with_title("Hello World") .build(&event_loop) @@ -31,8 +32,7 @@ fn main() -> wry::Result<()> { let _webview = WebViewBuilder::new(window) .unwrap() .with_url("https://tauri.studio")? - .with_data_directory(test_path) - .build()?; + .build(&web_context)?; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/custom_protocol.rs b/examples/custom_protocol.rs index 434bb3545..8c3440003 100644 --- a/examples/custom_protocol.rs +++ b/examples/custom_protocol.rs @@ -74,7 +74,7 @@ fn main() -> wry::Result<()> { }) // tell the webview to load the custom protocol .with_url("wry.dev://")? - .build()?; + .build(&Default::default())?; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/custom_titlebar.rs b/examples/custom_titlebar.rs index c07323605..fb64c8769 100644 --- a/examples/custom_titlebar.rs +++ b/examples/custom_titlebar.rs @@ -119,7 +119,7 @@ fn main() -> wry::Result<()> { .with_url(url)? .with_initialization_script(script) .with_rpc_handler(handler) - .build()?; + .build(&Default::default())?; webviews.insert(webview.window().id(), webview); event_loop.run(move |event, _, control_flow| { diff --git a/examples/detect_js_ecma.rs b/examples/detect_js_ecma.rs index a0c6517c0..f45644793 100644 --- a/examples/detect_js_ecma.rs +++ b/examples/detect_js_ecma.rs @@ -128,7 +128,7 @@ fn main() -> wry::Result<()> { "#, )? - .build()?; + .build(&Default::default())?; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/dragndrop.rs b/examples/dragndrop.rs index 5ff3231fc..07e6a1781 100644 --- a/examples/dragndrop.rs +++ b/examples/dragndrop.rs @@ -27,7 +27,7 @@ fn main() -> wry::Result<()> { println!("Window 1: {:?}", data); false // Returning true will block the OS default behaviour. }) - .build()?; + .build(&Default::default())?; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index f3b6c3900..3856302f2 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -21,7 +21,7 @@ fn main() -> wry::Result<()> { let webview = WebViewBuilder::new(window) .unwrap() .with_url("https://www.wirple.com/")? - .build()?; + .build(&Default::default())?; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 5187154ee..5bcaefbbe 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -18,7 +18,7 @@ fn main() -> wry::Result<()> { .build(&event_loop)?; let _webview = WebViewBuilder::new(window)? .with_url("https://tauri.studio")? - .build()?; + .build(&Default::default())?; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/html_test.rs b/examples/html_test.rs index 195f5376b..4f44df2a7 100644 --- a/examples/html_test.rs +++ b/examples/html_test.rs @@ -18,7 +18,7 @@ fn main() -> wry::Result<()> { .build(&event_loop)?; let _webview = WebViewBuilder::new(window)? .with_url("https://html5test.com")? - .build()?; + .build(&Default::default())?; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/menu_bar.rs b/examples/menu_bar.rs index a263335f5..642eaf856 100644 --- a/examples/menu_bar.rs +++ b/examples/menu_bar.rs @@ -93,7 +93,7 @@ fn main() -> wry::Result<()> { // Build the webview let webview = WebViewBuilder::new(window)? .with_url("https://tauri.studio")? - .build()?; + .build(&Default::default())?; // launch WRY process event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/multi_window.rs b/examples/multi_window.rs index eb7c4b60b..b64373dbf 100644 --- a/examples/multi_window.rs +++ b/examples/multi_window.rs @@ -22,10 +22,11 @@ fn main() -> wry::Result<()> { event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}, }, - webview::{RpcRequest, WebViewBuilder}, + webview::{RpcRequest, WebContext, WebViewBuilder}, }; let event_loop = EventLoop::new(); + let web_context = WebContext::default(); let window1 = WindowBuilder::new().build(&event_loop).unwrap(); let (window_tx, window_rx) = std::sync::mpsc::channel::(); @@ -50,7 +51,7 @@ fn main() -> wry::Result<()> { }"#, ) .with_rpc_handler(handler) - .build()?; + .build(&web_context)?; let mut webviews = HashMap::new(); webviews.insert(id, webview1); @@ -71,7 +72,7 @@ fn main() -> wry::Result<()> { .unwrap() .with_url(&url) .unwrap() - .build() + .build(&web_context) .unwrap(); webviews.insert(id, webview2); } else if trigger && instant.elapsed() >= eight_secs { diff --git a/examples/rpc.rs b/examples/rpc.rs index e8d884ad8..3f5a713ee 100644 --- a/examples/rpc.rs +++ b/examples/rpc.rs @@ -80,7 +80,7 @@ async function getAsyncRpcResult() { .unwrap() .with_url(url)? .with_rpc_handler(handler) - .build()?; + .build(&Default::default())?; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/system_tray.rs b/examples/system_tray.rs index d48de2487..590173317 100644 --- a/examples/system_tray.rs +++ b/examples/system_tray.rs @@ -66,7 +66,7 @@ fn main() -> wry::Result<()> { .unwrap() .with_url("https://tauri.studio") .unwrap() - .build() + .build(&Default::default()) .unwrap(); webviews.insert(id, webview); } diff --git a/examples/transparent.rs b/examples/transparent.rs index 8d62b8196..da139aaa2 100644 --- a/examples/transparent.rs +++ b/examples/transparent.rs @@ -37,7 +37,7 @@ fn main() -> wry::Result<()> { "#, )? - .build()?; + .build(&Default::default())?; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/examples/validate_webview.rs b/examples/validate_webview.rs index fd98644b6..b717aca48 100644 --- a/examples/validate_webview.rs +++ b/examples/validate_webview.rs @@ -26,7 +26,7 @@ fn main() -> wry::Result<()> { .build(&event_loop)?; let _webview = WebViewBuilder::new(window)? .with_url("https://tauri.studio")? - .build()?; + .build(&Default::default())?; event_loop.run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/src/lib.rs b/src/lib.rs index 568e2367a..e633fc36d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ //! .build(&event_loop)?; //! let _webview = WebViewBuilder::new(window)? //! .with_url("https://tauri.studio")? -//! .build()?; +//! .build(&Default::default())?; //! //! event_loop.run(move |event, _, control_flow| { //! *control_flow = ControlFlow::Wait; From d114e3811a0ca17625e1395fb4c679dccea922a7 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 11:51:00 -0700 Subject: [PATCH 37/44] allow os impl WebContextImpl to be dead_code --- src/webview/web_context.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/webview/web_context.rs b/src/webview/web_context.rs index c6f97ee73..f9eccec0f 100644 --- a/src/webview/web_context.rs +++ b/src/webview/web_context.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; /// private/incognito tabs. pub struct WebContext { data: WebContextData, + #[allow(dead_code)] os: WebContextImpl, } From 8c8cca4160a2758a96d78753361d2997de80be63 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 11:51:24 -0700 Subject: [PATCH 38/44] fix windows webview builder initialization --- src/webview/webview2/win32/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webview/webview2/win32/mod.rs b/src/webview/webview2/win32/mod.rs index 9cce4be67..ec8c1279f 100644 --- a/src/webview/webview2/win32/mod.rs +++ b/src/webview/webview2/win32/mod.rs @@ -11,7 +11,7 @@ use crate::{ use file_drop::FileDropController; -use std::{collections::HashSet, os::raw::c_void, path::PathBuf, rc::Rc}; +use std::{collections::HashSet, os::raw::c_void, rc::Rc}; use once_cell::unsync::OnceCell; use webview2::{Controller, PermissionKind, PermissionState, WebView}; @@ -49,7 +49,7 @@ impl InnerWebView { let file_drop_controller: Rc> = Rc::new(OnceCell::new()); let file_drop_controller_clone = file_drop_controller.clone(); - let mut webview_builder: webview2::EnvironmentBuilder::new(); + let mut webview_builder = webview2::EnvironmentBuilder::new(); if let Some(data_directory) = web_context.data_directory() { webview_builder = webview_builder.with_user_data_folder(&data_directory); From 662037b3ba400ae6736f346b53ac7c551fd37bfc Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Fri, 4 Jun 2021 11:51:36 -0700 Subject: [PATCH 39/44] add winrt note to add window close event handler --- src/webview/webview2/winrt/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/webview/webview2/winrt/mod.rs b/src/webview/webview2/winrt/mod.rs index fcf75e875..08c339346 100644 --- a/src/webview/webview2/winrt/mod.rs +++ b/src/webview/webview2/winrt/mod.rs @@ -93,6 +93,8 @@ impl InnerWebView { settings.SetAreDevToolsEnabled(false)?; debug_assert_eq!(settings.SetAreDevToolsEnabled(true)?, ()); + // todo: add close window event handler like win32's add_window_close_requested + // Safety: System calls are unsafe unsafe { let mut rect = RECT::default(); From 0d51d78e87a2cb423e26ffa3a44311ab7785348c Mon Sep 17 00:00:00 2001 From: chip Date: Tue, 8 Jun 2021 10:17:56 -0700 Subject: [PATCH 40/44] add smart link to WebContext docs Co-authored-by: Ngo Iok Ui (Wu Yu Wei) --- src/webview/web_context.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/webview/web_context.rs b/src/webview/web_context.rs index f9eccec0f..955d86e57 100644 --- a/src/webview/web_context.rs +++ b/src/webview/web_context.rs @@ -1,6 +1,7 @@ use std::path::{Path, PathBuf}; /// A context that is shared between multiple [`WebView`]s. +/// [`WebView`]: crate::webview::WebView /// /// A browser would have a context for all the normal tabs and a different context for all the /// private/incognito tabs. From 0ca465d2790adf9285672ca984fc44ddbb798eb6 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Tue, 8 Jun 2021 10:27:18 -0700 Subject: [PATCH 41/44] update WebContext doc smartlink --- src/webview/web_context.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/webview/web_context.rs b/src/webview/web_context.rs index 955d86e57..2bc778544 100644 --- a/src/webview/web_context.rs +++ b/src/webview/web_context.rs @@ -1,10 +1,11 @@ use std::path::{Path, PathBuf}; /// A context that is shared between multiple [`WebView`]s. -/// [`WebView`]: crate::webview::WebView /// /// A browser would have a context for all the normal tabs and a different context for all the /// private/incognito tabs. +/// +/// [`WebView`]: crate::webview::WebView pub struct WebContext { data: WebContextData, #[allow(dead_code)] From 56188195685d1d63458780b27f016c6cc1fa6317 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Tue, 8 Jun 2021 10:30:16 -0700 Subject: [PATCH 42/44] remove doc_cfg from empty non-linux WebContextImpls --- src/webview/web_context.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/webview/web_context.rs b/src/webview/web_context.rs index 2bc778544..4e0b8f149 100644 --- a/src/webview/web_context.rs +++ b/src/webview/web_context.rs @@ -52,11 +52,9 @@ impl WebContextData { } #[cfg(not(target_os = "linux"))] -#[cfg_attr(doc_cfg, doc(cfg(not(target_os = "linux"))))] struct WebContextImpl; #[cfg(not(target_os = "linux"))] -#[cfg_attr(doc_cfg, doc(cfg(not(target_os = "linux"))))] impl WebContextImpl { fn new(_data: &WebContextData) -> Self { Self From f384c20769a2e7c1deb6eb7d71146576a2e35364 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Tue, 8 Jun 2021 10:35:33 -0700 Subject: [PATCH 43/44] fix clippy error in unrelated code --- src/webview/mimetype.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webview/mimetype.rs b/src/webview/mimetype.rs index 2d19a5403..8c7a45232 100644 --- a/src/webview/mimetype.rs +++ b/src/webview/mimetype.rs @@ -63,7 +63,7 @@ impl MimeType { /// infer mimetype from content (or) URI if needed. pub fn parse(content: &[u8], uri: &str) -> String { - let mime = match infer::get(&content) { + let mime = match infer::get(content) { Some(info) => info.mime_type(), None => MIMETYPE_PLAIN, }; From 08c646c1f4bae97d729dbb37fa9eed24afd59d20 Mon Sep 17 00:00:00 2001 From: Chip Reed Date: Tue, 8 Jun 2021 10:45:58 -0700 Subject: [PATCH 44/44] make clippy happy (new nightly lints) --- examples/multi_window.rs | 2 +- examples/system_tray.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/multi_window.rs b/examples/multi_window.rs index b64373dbf..ce9088666 100644 --- a/examples/multi_window.rs +++ b/examples/multi_window.rs @@ -65,7 +65,7 @@ fn main() -> wry::Result<()> { let window2 = WindowBuilder::new() .with_title("RODA RORA DA") .with_inner_size(PhysicalSize::new(426, 197)) - .build(&event_loop) + .build(event_loop) .unwrap(); let id = window2.id(); let webview2 = WebViewBuilder::new(window2) diff --git a/examples/system_tray.rs b/examples/system_tray.rs index 590173317..2eb589c64 100644 --- a/examples/system_tray.rs +++ b/examples/system_tray.rs @@ -60,7 +60,7 @@ fn main() -> wry::Result<()> { origin: MenuType::SystemTray, } => { if menu_id == open_new_window_id { - let window = Window::new(&event_loop).unwrap(); + let window = Window::new(event_loop).unwrap(); let id = window.id(); let webview = WebViewBuilder::new(window) .unwrap()