diff --git a/crates/tauri-cli/src/cef/exporter.rs b/crates/tauri-cli/src/cef/exporter.rs index 151f5d8ac..0a2e56a61 100644 --- a/crates/tauri-cli/src/cef/exporter.rs +++ b/crates/tauri-cli/src/cef/exporter.rs @@ -24,7 +24,7 @@ fn default_version() -> &'static str { fn default_download_url() -> &'static str { static DEFAULT_DOWNLOAD_URL: OnceLock = OnceLock::new(); DEFAULT_DOWNLOAD_URL - .get_or_init(|| download_cef::default_download_url()) + .get_or_init(download_cef::default_download_url) .as_str() } diff --git a/crates/tauri-cli/src/cef/macos_dev.rs b/crates/tauri-cli/src/cef/macos_dev.rs index 5305dce79..7bde5d92f 100644 --- a/crates/tauri-cli/src/cef/macos_dev.rs +++ b/crates/tauri-cli/src/cef/macos_dev.rs @@ -71,7 +71,7 @@ fn write_info_plist( let mut ls_env = HashMap::new(); ls_env.insert("MallocNanoZone".into(), "0".into()); let product_compact = product_name.replace(' ', ""); - let identifier = format!("dev.tauri.{}", product_compact); + let identifier = format!("dev.tauri.{product_compact}"); let info_plist = InfoPlist { cf_bundle_development_region: "en".into(), cf_bundle_display_name: product_name.into(), @@ -155,7 +155,7 @@ pub fn run_dev_cef_macos, ExitReason) + Send + let product_name = app_settings.get_package_settings().product_name.clone(); let version = app_settings.get_package_settings().version.clone(); - let app_bundle_path = out_dir.join(format!("{}.app", product_name)); + let app_bundle_path = out_dir.join(format!("{product_name}.app")); let _ = std::fs::remove_dir_all(&app_bundle_path); create_app_layout(&app_bundle_path)?; write_info_plist( @@ -179,7 +179,7 @@ pub fn run_dev_cef_macos, ExitReason) + Send + for helper_name in helpers { let helper_app = app_bundle_path .join(FRAMEWORKS_PATH) - .join(format!("{}.app", helper_name)); + .join(format!("{helper_name}.app")); create_app_layout(&helper_app)?; write_info_plist( &helper_app.join("Contents"), @@ -259,7 +259,7 @@ pub fn run_dev_cef_macos, ExitReason) + Send + if status.success() { on_exit(status.code(), ExitReason::NormalExit); } else { - let _ = stderr_lines.lock().unwrap().clear(); + stderr_lines.lock().unwrap().clear(); on_exit( status.code(), if manually_killed_app_.load(Ordering::Relaxed) { diff --git a/crates/tauri-cli/src/interface/rust.rs b/crates/tauri-cli/src/interface/rust.rs index 2e3e39bc4..3cf702df8 100644 --- a/crates/tauri-cli/src/interface/rust.rs +++ b/crates/tauri-cli/src/interface/rust.rs @@ -532,7 +532,6 @@ fn ensure_cef_directory_if_needed( .cargo_config .build() .target() - .map(|t| t.as_ref()) }); if let Err(e) = crate::cef::exporter::ensure_cef_directory(target_triple, &enabled_features) { log::warn!(action = "CEF"; "Failed to ensure CEF directory: {}. Continuing anyway.", e); diff --git a/crates/tauri-runtime-cef/src/cef_impl.rs b/crates/tauri-runtime-cef/src/cef_impl.rs index 0bae7a914..bb49d886f 100644 --- a/crates/tauri-runtime-cef/src/cef_impl.rs +++ b/crates/tauri-runtime-cef/src/cef_impl.rs @@ -299,7 +299,7 @@ wrap_browser_process_handler! { wrap_load_handler! { struct BrowserLoadHandler { - initialization_scripts: Vec, + initialization_scripts: Arc>, on_page_load_handler: Option>, custom_scheme_domain_names: Vec, custom_protocol_scheme: String, @@ -349,7 +349,7 @@ wrap_load_handler! { // custom schemes are handled by the request handler // where we inject scripts directly in the html - if http_status_code < 200 || http_status_code >= 300 { + if !(200..300).contains(&http_status_code) { return; } @@ -373,22 +373,20 @@ wrap_load_handler! { let is_main_frame = frame.is_main() == 1; - let scripts_to_execute: Vec<_> = if is_main_frame { - self.initialization_scripts.clone() + let scripts_to_execute = if is_main_frame { + Box::new(self.initialization_scripts.iter().map(|s| &s.script.script)) as Box> } else { - self.initialization_scripts + Box::new(self.initialization_scripts .iter() .filter(|s| !s.script.for_main_frame_only) - .cloned() - .collect() + .map(|s| &s.script.script)) as Box> }; for script in scripts_to_execute { - let script_text = script.script.script.clone(); let script_url = format!("{}://__tauri_init_script__", url_obj.as_ref().map(|u| u.scheme()).unwrap_or("http")); frame.execute_java_script( - Some(&cef::CefString::from(script_text.as_str())), + Some(&cef::CefString::from(script.as_str())), Some(&cef::CefString::from(script_url.as_str())), 0, ); @@ -530,7 +528,7 @@ wrap_download_handler! { let suggested_path = suggested_name .map(|s| s.to_string()) - .map(|s| std::path::PathBuf::from(s)) + .map(std::path::PathBuf::from) .unwrap_or_default(); let mut destination = suggested_path; @@ -592,40 +590,9 @@ wrap_download_handler! { } } -wrap_life_span_handler! { - struct BrowserLifeSpanHandler { - context: Context, - window_id: WindowId, - webview_id: u32, - devtools_enabled: bool, - } - - impl LifeSpanHandler { - fn on_after_created(&self, browser: Option<&mut Browser>) { - let Some(browser) = browser else { return; }; - - // Get the browser_view for this browser - if let Some(browser_view) = cef::browser_view_get_for_browser(Some(browser)) { - // Add the browser_view to the webviews - if let Ok(mut windows) = self.context.windows.try_borrow_mut() { - if let Some(app_window) = windows.get_mut(&self.window_id) { - app_window.webviews.push(AppWebview { - webview_id: self.webview_id, - browser_view, - overlay: None, - bounds: Arc::new(Mutex::new(None)), - devtools_enabled: self.devtools_enabled, - }); - } - } - } - } - } -} - wrap_client! { struct BrowserClient { - initialization_scripts: Vec, + initialization_scripts: Arc>, on_page_load_handler: Option>, document_title_changed_handler: Option>, navigation_handler: Option>, @@ -635,7 +602,6 @@ wrap_client! { custom_protocol_scheme: String, context: Context, window_id: WindowId, - pending_browser_webview_id: Option, } impl Client { @@ -666,11 +632,7 @@ wrap_client! { } fn download_handler(&self) -> Option { - if let Some(handler) = self.download_handler.clone() { - Some(BrowserDownloadHandler::new(handler)) - } else { - None - } + self.download_handler.clone().map(|handler| BrowserDownloadHandler::new(handler)) } fn context_menu_handler(&self) -> Option { @@ -680,30 +642,24 @@ wrap_client! { fn keyboard_handler(&self) -> Option { Some(BrowserKeyboardHandler::new(self.devtools_enabled)) } - - fn life_span_handler(&self) -> Option { - if let Some(pending_browser_webview_id) = self.pending_browser_webview_id { - Some(BrowserLifeSpanHandler::new( - self.context.clone(), - self.window_id, - pending_browser_webview_id, - self.devtools_enabled, - )) - } else { - None - } - } } } wrap_browser_view_delegate! { struct BrowserViewDelegateImpl { + browser_id: Arc>, browser_runtime_style: BrowserRuntimeStyle, } impl ViewDelegate {} impl BrowserViewDelegate { + fn on_browser_created(&self, _browser_view: Option<&mut BrowserView>, browser: Option<&mut Browser>) { + if let Some(browser) = browser { + self.browser_id.replace(browser.identifier()); + } + } + fn browser_runtime_style(&self) -> RuntimeStyle { use cef::sys::cef_runtime_style_t; @@ -829,7 +785,7 @@ wrap_window_delegate! { if let Some(window) = window { let a = self.attributes.borrow(); if let Some(icon) = a.icon.clone() { - set_window_icon(&window, icon); + set_window_icon(window, icon); } if let Some(title) = &a.title { @@ -898,7 +854,7 @@ wrap_window_delegate! { } if let Some(content_protected) = a.content_protected { - apply_content_protection(&window, content_protected); + apply_content_protection(window, content_protected); } if let Some(skip_taskbar) = a.skip_taskbar { @@ -1103,7 +1059,7 @@ fn get_browser_view( .webviews .iter() .find(|w| w.webview_id == webview_id) - .map(|w| w.browser_view.clone()) + .and_then(|w| w.browser_view.clone()) }) } @@ -1143,33 +1099,39 @@ fn handle_webview_message( } } WebviewMessage::EvaluateScript(script) => { - get_browser_view(context, window_id, webview_id) + if let Some(frame) = get_browser_view(context, window_id, webview_id) .and_then(|bv| bv.browser()) .and_then(|b| b.main_frame()) - .map(|frame| { - frame.execute_java_script( - Some(&cef::CefString::from(script.as_str())), - Some(&cef::CefString::from("")), - 0, - ); - }); + { + frame.execute_java_script( + Some(&cef::CefString::from(script.as_str())), + Some(&cef::CefString::from("")), + 0, + ); + } } WebviewMessage::Navigate(url) => { - get_browser_view(context, window_id, webview_id) + if let Some(frame) = get_browser_view(context, window_id, webview_id) .and_then(|bv| bv.browser()) .and_then(|b| b.main_frame()) - .map(|frame| frame.load_url(Some(&cef::CefString::from(url.as_str())))); + { + frame.load_url(Some(&cef::CefString::from(url.as_str()))) + } } WebviewMessage::Reload => { - get_browser_view(context, window_id, webview_id) - .and_then(|bv| bv.browser()) - .map(|browser| browser.reload()); + if let Some(browser) = + get_browser_view(context, window_id, webview_id).and_then(|bv| bv.browser()) + { + browser.reload() + } } WebviewMessage::Print => { - get_browser_view(context, window_id, webview_id) + if let Some(host) = get_browser_view(context, window_id, webview_id) .and_then(|bv| bv.browser()) .and_then(|b| b.host()) - .map(|host| host.print()); + { + host.print() + } } WebviewMessage::Close => { if let Some(app_window) = context.windows.borrow_mut().get_mut(&window_id) { @@ -1194,7 +1156,7 @@ fn handle_webview_message( } } WebviewMessage::Show => { - context + if let Some(overlay) = context .windows .borrow() .get(&window_id) @@ -1205,10 +1167,12 @@ fn handle_webview_message( .find(|w| w.webview_id == webview_id) }) .and_then(|wrapper| wrapper.overlay.as_ref()) - .map(|overlay| overlay.set_visible(1)); + { + overlay.set_visible(1) + } } WebviewMessage::Hide => { - context + if let Some(overlay) = context .windows .borrow() .get(&window_id) @@ -1219,7 +1183,9 @@ fn handle_webview_message( .find(|w| w.webview_id == webview_id) }) .and_then(|wrapper| wrapper.overlay.as_ref()) - .map(|overlay| overlay.set_visible(0)); + { + overlay.set_visible(0) + } } WebviewMessage::SetPosition(position) => { context.windows.borrow().get(&window_id).map(|app_window| { @@ -1328,19 +1294,19 @@ fn handle_webview_message( .unwrap_or(1.0); let logical_position = bounds.position.to_logical::(device_scale_factor); let logical_size = bounds.size.to_logical::(device_scale_factor); - app_window + if let Some(overlay) = app_window .webviews .iter() .find(|w| w.webview_id == webview_id) .and_then(|wrapper| wrapper.overlay.as_ref()) - .map(|overlay| { - overlay.set_bounds(Some(&cef::Rect { - x: logical_position.x, - y: logical_position.y, - width: logical_size.width as i32, - height: logical_size.height as i32, - })); - }); + { + overlay.set_bounds(Some(&cef::Rect { + x: logical_position.x, + y: logical_position.y, + width: logical_size.width as i32, + height: logical_size.height as i32, + })); + } // update autoresize ratios if enabled if let Some(wrapper) = app_window @@ -1372,10 +1338,12 @@ fn handle_webview_message( }); } WebviewMessage::SetFocus => { - get_browser_view(context, window_id, webview_id) + if let Some(host) = get_browser_view(context, window_id, webview_id) .and_then(|bv| bv.browser()) .and_then(|b| b.host()) - .map(|host| host.set_focus(1)); + { + host.set_focus(1) + } } WebviewMessage::Reparent(target_window_id, tx) => { let mut windows = context.windows.borrow_mut(); @@ -1401,6 +1369,11 @@ fn handle_webview_message( return; }; + let Some(browser_view) = webview_wrapper.browser_view.as_ref() else { + let _ = tx.send(Err(tauri_runtime::Error::FailedToSendMessage)); + return; + }; + let bounds = webview_wrapper .overlay .as_ref() @@ -1421,7 +1394,7 @@ fn handle_webview_message( let overlay = match &mut target_window.window { crate::AppWindowKind::Window(window) => window.add_overlay_view( - Some(&mut View::from(&webview_wrapper.browser_view)), + Some(&mut View::from(browser_view)), cef::DockingMode::from(cef::sys::cef_docking_mode_t::CEF_DOCKING_MODE_CUSTOM), 1, ), @@ -1479,14 +1452,16 @@ fn handle_webview_message( } } WebviewMessage::SetZoom(scale_factor) => { - get_browser_view(context, window_id, webview_id) + if let Some(host) = get_browser_view(context, window_id, webview_id) .and_then(|bv| bv.browser()) .and_then(|b| b.host()) - .map(|host| host.set_zoom_level(scale_factor)); + { + host.set_zoom_level(scale_factor) + } } WebviewMessage::SetBackgroundColor(color) => { let color_value = color_opt_to_cef_argb(color); - context + if let Some(bv) = context .windows .borrow() .get(&window_id) @@ -1496,7 +1471,10 @@ fn handle_webview_message( .iter() .find(|w| w.webview_id == webview_id) }) - .map(|wrapper| wrapper.browser_view.set_background_color(color_value)); + .and_then(|wrapper| wrapper.browser_view.as_ref()) + { + bv.set_background_color(color_value) + } } WebviewMessage::ClearAllBrowsingData => { // TODO: Implement clear browsing data @@ -1531,7 +1509,7 @@ fn handle_webview_message( .or_else(|| { let bounds = match &app_window.window { crate::AppWindowKind::Window(window) => window.bounds(), - crate::AppWindowKind::BrowserWindow => webview.browser_view.bounds(), + crate::AppWindowKind::BrowserWindow => webview.browser_view.as_ref()?.bounds(), }; Some(bounds) }); @@ -1572,7 +1550,7 @@ fn handle_webview_message( let bounds = webview.overlay.as_ref().map(|v| v.bounds()).or_else(|| { let bounds = match &app_window.window { crate::AppWindowKind::Window(window) => window.bounds(), - crate::AppWindowKind::BrowserWindow => webview.browser_view.bounds(), + crate::AppWindowKind::BrowserWindow => webview.browser_view.as_ref()?.bounds(), }; Some(bounds) })?; @@ -1603,18 +1581,13 @@ fn handle_webview_message( .iter() .find(|w| w.webview_id == webview_id) .and_then(|webview| { - let Some(bounds) = webview - .overlay - .as_ref() - .and_then(|v| Some(v.bounds())) - .or_else(|| { - let bounds = match &app_window.window { - crate::AppWindowKind::Window(window) => window.bounds(), - crate::AppWindowKind::BrowserWindow => webview.browser_view.bounds(), - }; - Some(bounds) - }) - else { + let Some(bounds) = webview.overlay.as_ref().map(|v| v.bounds()).or_else(|| { + let bounds = match &app_window.window { + crate::AppWindowKind::Window(window) => window.bounds(), + crate::AppWindowKind::BrowserWindow => webview.browser_view.as_ref()?.bounds(), + }; + Some(bounds) + }) else { return None; }; let scale = match &app_window.window { @@ -1634,9 +1607,9 @@ fn handle_webview_message( let _ = tx.send(result); } WebviewMessage::WithWebview(f) => { - get_browser_view(context, window_id, webview_id).map(|browser_view| { + if let Some(browser_view) = get_browser_view(context, window_id, webview_id) { f(Box::new(browser_view)); - }); + } } // Devtools #[cfg(any(debug_assertions, feature = "devtools"))] @@ -1644,7 +1617,7 @@ fn handle_webview_message( get_webview(context, window_id, webview_id) .and_then(|bv| { if bv.devtools_enabled { - bv.browser_view.browser() + bv.browser_view?.browser() } else { // break out of the chain if devtools are not enabled None @@ -1665,10 +1638,12 @@ fn handle_webview_message( } #[cfg(any(debug_assertions, feature = "devtools"))] WebviewMessage::CloseDevTools => { - get_browser_view(context, window_id, webview_id) + if let Some(host) = get_browser_view(context, window_id, webview_id) .and_then(|bv| bv.browser()) .and_then(|b| b.host()) - .map(|host| host.close_dev_tools()); + { + host.close_dev_tools() + } } #[cfg(any(debug_assertions, feature = "devtools"))] WebviewMessage::IsDevToolsOpen(tx) => { @@ -1809,21 +1784,19 @@ fn handle_window_message( .windows .borrow() .get(&window_id) - .and_then(|w| match &w.window { + .map(|w| match &w.window { crate::AppWindowKind::Window(window) => { let bounds = window.bounds(); let scale = window .display() .map(|d| d.device_scale_factor() as f64) .unwrap_or(1.0); - Some(Ok( + Ok( tauri_runtime::dpi::LogicalPosition::new(bounds.x, bounds.y) .to_physical::(scale), - )) - } - crate::AppWindowKind::BrowserWindow => { - Some(Err(tauri_runtime::Error::FailedToSendMessage)) + ) } + crate::AppWindowKind::BrowserWindow => Err(tauri_runtime::Error::FailedToSendMessage), }) .unwrap_or_else(|| Err(tauri_runtime::Error::FailedToSendMessage)); let _ = tx.send(result); @@ -1833,21 +1806,19 @@ fn handle_window_message( .windows .borrow() .get(&window_id) - .and_then(|w| match &w.window { + .map(|w| match &w.window { crate::AppWindowKind::Window(window) => { let bounds = window.bounds(); let scale = window .display() .map(|d| d.device_scale_factor() as f64) .unwrap_or(1.0); - Some(Ok( + Ok( tauri_runtime::dpi::LogicalPosition::new(bounds.x, bounds.y) .to_physical::(scale), - )) - } - crate::AppWindowKind::BrowserWindow => { - Some(Err(tauri_runtime::Error::FailedToSendMessage)) + ) } + crate::AppWindowKind::BrowserWindow => Err(tauri_runtime::Error::FailedToSendMessage), }) .unwrap_or_else(|| Err(tauri_runtime::Error::FailedToSendMessage)); let _ = tx.send(result); @@ -1857,21 +1828,19 @@ fn handle_window_message( .windows .borrow() .get(&window_id) - .and_then(|w| match &w.window { + .map(|w| match &w.window { crate::AppWindowKind::Window(window) => { let bounds = window.bounds(); let scale = window .display() .map(|d| d.device_scale_factor() as f64) .unwrap_or(1.0); - Some(Ok( + Ok( tauri_runtime::dpi::LogicalSize::new(bounds.width as u32, bounds.height as u32) .to_physical::(scale), - )) - } - crate::AppWindowKind::BrowserWindow => { - Some(Err(tauri_runtime::Error::FailedToSendMessage)) + ) } + crate::AppWindowKind::BrowserWindow => Err(tauri_runtime::Error::FailedToSendMessage), }) .unwrap_or_else(|| Err(tauri_runtime::Error::FailedToSendMessage)); let _ = tx.send(result); @@ -1881,21 +1850,19 @@ fn handle_window_message( .windows .borrow() .get(&window_id) - .and_then(|w| match &w.window { + .map(|w| match &w.window { crate::AppWindowKind::Window(window) => { let bounds = window.bounds(); let scale = window .display() .map(|d| d.device_scale_factor() as f64) .unwrap_or(1.0); - Some(Ok( + Ok( tauri_runtime::dpi::LogicalSize::new(bounds.width as u32, bounds.height as u32) .to_physical::(scale), - )) - } - crate::AppWindowKind::BrowserWindow => { - Some(Err(tauri_runtime::Error::FailedToSendMessage)) + ) } + crate::AppWindowKind::BrowserWindow => Err(tauri_runtime::Error::FailedToSendMessage), }) .unwrap_or_else(|| Err(tauri_runtime::Error::FailedToSendMessage)); let _ = tx.send(result); @@ -1905,11 +1872,9 @@ fn handle_window_message( .windows .borrow() .get(&window_id) - .and_then(|w| match &w.window { - crate::AppWindowKind::Window(window) => Some(Ok(window.is_fullscreen() == 1)), - crate::AppWindowKind::BrowserWindow => { - Some(Err(tauri_runtime::Error::FailedToSendMessage)) - } + .map(|w| match &w.window { + crate::AppWindowKind::Window(window) => Ok(window.is_fullscreen() == 1), + crate::AppWindowKind::BrowserWindow => Err(tauri_runtime::Error::FailedToSendMessage), }) .unwrap_or_else(|| Err(tauri_runtime::Error::FailedToSendMessage)); let _ = tx.send(result); @@ -1919,11 +1884,9 @@ fn handle_window_message( .windows .borrow() .get(&window_id) - .and_then(|w| match &w.window { - crate::AppWindowKind::Window(window) => Some(Ok(window.is_minimized() == 1)), - crate::AppWindowKind::BrowserWindow => { - Some(Err(tauri_runtime::Error::FailedToSendMessage)) - } + .map(|w| match &w.window { + crate::AppWindowKind::Window(window) => Ok(window.is_minimized() == 1), + crate::AppWindowKind::BrowserWindow => Err(tauri_runtime::Error::FailedToSendMessage), }) .unwrap_or_else(|| Err(tauri_runtime::Error::FailedToSendMessage)); let _ = tx.send(result); @@ -1933,11 +1896,9 @@ fn handle_window_message( .windows .borrow() .get(&window_id) - .and_then(|w| match &w.window { - crate::AppWindowKind::Window(window) => Some(Ok(window.is_maximized() == 1)), - crate::AppWindowKind::BrowserWindow => { - Some(Err(tauri_runtime::Error::FailedToSendMessage)) - } + .map(|w| match &w.window { + crate::AppWindowKind::Window(window) => Ok(window.is_maximized() == 1), + crate::AppWindowKind::BrowserWindow => Err(tauri_runtime::Error::FailedToSendMessage), }) .unwrap_or_else(|| Err(tauri_runtime::Error::FailedToSendMessage)); let _ = tx.send(result); @@ -1947,11 +1908,9 @@ fn handle_window_message( .windows .borrow() .get(&window_id) - .and_then(|w| match &w.window { - crate::AppWindowKind::Window(window) => Some(Ok(window.has_focus() == 1)), - crate::AppWindowKind::BrowserWindow => { - Some(Err(tauri_runtime::Error::FailedToSendMessage)) - } + .map(|w| match &w.window { + crate::AppWindowKind::Window(window) => Ok(window.has_focus() == 1), + crate::AppWindowKind::BrowserWindow => Err(tauri_runtime::Error::FailedToSendMessage), }) .unwrap_or_else(|| Err(tauri_runtime::Error::FailedToSendMessage)); let _ = tx.send(result); @@ -2006,11 +1965,9 @@ fn handle_window_message( .windows .borrow() .get(&window_id) - .and_then(|w| match &w.window { - crate::AppWindowKind::Window(window) => Some(Ok(window.is_visible() == 1)), - crate::AppWindowKind::BrowserWindow => { - Some(Err(tauri_runtime::Error::FailedToSendMessage)) - } + .map(|w| match &w.window { + crate::AppWindowKind::Window(window) => Ok(window.is_visible() == 1), + crate::AppWindowKind::BrowserWindow => Err(tauri_runtime::Error::FailedToSendMessage), }) .unwrap_or_else(|| Err(tauri_runtime::Error::FailedToSendMessage)); let _ = tx.send(result); @@ -2020,14 +1977,12 @@ fn handle_window_message( .windows .borrow() .get(&window_id) - .and_then(|w| match &w.window { + .map(|w| match &w.window { crate::AppWindowKind::Window(window) => { let title = window.title(); - Some(Ok(cef::CefString::from(&title).to_string())) - } - crate::AppWindowKind::BrowserWindow => { - Some(Err(tauri_runtime::Error::FailedToSendMessage)) + Ok(cef::CefString::from(&title).to_string()) } + crate::AppWindowKind::BrowserWindow => Err(tauri_runtime::Error::FailedToSendMessage), }) .unwrap_or_else(|| Err(tauri_runtime::Error::FailedToSendMessage)); let _ = tx.send(result); @@ -2106,11 +2061,9 @@ fn handle_window_message( .windows .borrow() .get(&window_id) - .and_then(|w| match &w.window { - crate::AppWindowKind::Window(window) => Some(Ok(window.is_always_on_top() == 1)), - crate::AppWindowKind::BrowserWindow => { - Some(Err(tauri_runtime::Error::FailedToSendMessage)) - } + .map(|w| match &w.window { + crate::AppWindowKind::Window(window) => Ok(window.is_always_on_top() == 1), + crate::AppWindowKind::BrowserWindow => Err(tauri_runtime::Error::FailedToSendMessage), }) .unwrap_or_else(|| Err(tauri_runtime::Error::FailedToSendMessage)); let _ = tx.send(result); @@ -2120,29 +2073,29 @@ fn handle_window_message( .windows .borrow() .get(&window_id) - .and_then(|w| match &w.window { + .map(|w| match &w.window { crate::AppWindowKind::Window(window) => { #[cfg(target_os = "linux")] unsafe { let xid = window.window_handle() as u64; - Some(Ok(raw_window_handle::WindowHandle::borrow_raw( + Ok(raw_window_handle::WindowHandle::borrow_raw( raw_window_handle::RawWindowHandle::Xlib(raw_window_handle::XlibWindowHandle::new( xid, )), - ))) + )) } #[cfg(target_os = "macos")] unsafe { - let ns_view = window.window_handle() as *mut std::ffi::c_void; + let ns_view = window.window_handle(); if let Some(nn) = std::ptr::NonNull::new(ns_view) { - Some(Ok(raw_window_handle::WindowHandle::borrow_raw( + Ok(raw_window_handle::WindowHandle::borrow_raw( raw_window_handle::RawWindowHandle::AppKit( raw_window_handle::AppKitWindowHandle::new(nn), ), - ))) + )) } else { - Some(Err(raw_window_handle::HandleError::Unavailable)) + Err(raw_window_handle::HandleError::Unavailable) } } @@ -2150,21 +2103,19 @@ fn handle_window_message( unsafe { let hwnd = window.window_handle().0 as isize; if let Some(nz) = std::num::NonZeroIsize::new(hwnd) { - Some(Ok(raw_window_handle::WindowHandle::borrow_raw( + Ok(raw_window_handle::WindowHandle::borrow_raw( raw_window_handle::RawWindowHandle::Win32( raw_window_handle::Win32WindowHandle::new(nz), ), - ))) + )) } else { - Some(Err(raw_window_handle::HandleError::Unavailable)) + Err(raw_window_handle::HandleError::Unavailable) } } } - crate::AppWindowKind::BrowserWindow => { - Some(Err(raw_window_handle::HandleError::Unavailable)) - } + crate::AppWindowKind::BrowserWindow => Err(raw_window_handle::HandleError::Unavailable), }) - .unwrap_or_else(|| Err(raw_window_handle::HandleError::Unavailable)); + .unwrap_or(Err(raw_window_handle::HandleError::Unavailable)); let _ = tx.send(result); } // Setters @@ -2508,18 +2459,18 @@ fn create_browser_window( download_handler, } = webview; - let initialization_scripts: Vec<_> = - std::mem::take(&mut webview_attributes.initialization_scripts) - .into_iter() - .map(CefInitScript::new) - .collect(); + let initialization_scripts = std::mem::take(&mut webview_attributes.initialization_scripts) + .into_iter() + .map(CefInitScript::new) + .collect::>(); + let initialization_scripts = Arc::new(initialization_scripts); let on_page_load_handler = on_page_load_handler.take().map(Arc::from); let document_title_changed_handler = document_title_changed_handler.map(Arc::from); let navigation_handler = navigation_handler.map(Arc::from); let devtools_enabled = (cfg!(debug_assertions) || cfg!(feature = "devtools")) - && webview_attributes.devtools.clone().unwrap_or(true); + && webview_attributes.devtools.unwrap_or(true); let custom_protocol_scheme = if webview_attributes.use_https_scheme { "https" @@ -2527,17 +2478,26 @@ fn create_browser_window( "http" }; - // Build cached domain names for custom schemes before uri_scheme_protocols is consumed - let custom_scheme_domain_names: Vec = uri_scheme_protocols - .keys() + // Build cached domain names for custom schemes and clone protocols for storage + // before uri_scheme_protocols is moved + let scheme_keys: Vec = uri_scheme_protocols.keys().cloned().collect(); + let custom_scheme_domain_names: Vec = scheme_keys + .iter() .map(|scheme| format!("{scheme}.localhost")) .collect(); + let uri_scheme_protocols: HashMap>> = uri_scheme_protocols + .into_iter() + .map(|(k, v)| (k, Arc::new(v))) + .collect(); + + let custom_schemes = uri_scheme_protocols.keys().cloned().collect::>(); + let mut request_context = request_context_from_webview_attributes( - &webview_label, + context, &webview_attributes, - uri_scheme_protocols, - &custom_protocol_scheme, + &custom_schemes, + custom_protocol_scheme, &initialization_scripts, ); @@ -2547,19 +2507,6 @@ fn create_browser_window( let force_close = Arc::new(AtomicBool::new(false)); let attributes = Arc::new(RefCell::new(window_builder)); - context.windows.borrow_mut().insert( - window_id, - AppWindow { - label: label.clone(), - window: crate::AppWindowKind::BrowserWindow, - force_close: force_close.clone(), - attributes: attributes.clone(), - webviews: Vec::new(), - window_event_listeners: Arc::new(Mutex::new(HashMap::new())), - webview_event_listeners: Arc::new(Mutex::new(HashMap::new())), - }, - ); - let mut client = BrowserClient::new( initialization_scripts.clone(), on_page_load_handler, @@ -2571,7 +2518,6 @@ fn create_browser_window( custom_protocol_scheme.to_string(), context.clone(), window_id, - Some(webview_id), ); let url = CefString::from(url.as_str()); @@ -2600,13 +2546,39 @@ fn create_browser_window( ..Default::default() }; - browser_host_create_browser( + let Some(browser) = browser_host_create_browser_sync( Some(&window_info), Some(&mut client), Some(&url), Some(&browser_settings), None, request_context.as_mut(), + ) else { + eprintln!("Failed to create browser"); + return; + }; + + context.windows.borrow_mut().insert( + window_id, + AppWindow { + label, + window: crate::AppWindowKind::BrowserWindow, + force_close: force_close.clone(), + attributes: attributes.clone(), + webviews: vec![AppWebview { + webview_id, + browser_id: Arc::new(RefCell::new(browser.identifier())), + label: webview_label, + browser_view: None, + overlay: None, + bounds: Arc::new(Mutex::new(None)), + devtools_enabled, + uri_scheme_protocols: Arc::new(uri_scheme_protocols), + initialization_scripts, + }], + window_event_listeners: Arc::new(Mutex::new(HashMap::new())), + webview_event_listeners: Arc::new(Mutex::new(HashMap::new())), + }, ); } @@ -2792,26 +2764,23 @@ pub(crate) fn create_webview( { Some(w) => w, None => { - eprintln!( - "Window {:?} not found or is a browser window when creating webview", - window_id - ); + eprintln!("Window {window_id:?} not found or is a browser window when creating webview",); return; } }; - let initialization_scripts: Vec<_> = - std::mem::take(&mut webview_attributes.initialization_scripts) - .into_iter() - .map(CefInitScript::new) - .collect(); + let initialization_scripts = std::mem::take(&mut webview_attributes.initialization_scripts) + .into_iter() + .map(CefInitScript::new) + .collect::>(); + let initialization_scripts = Arc::new(initialization_scripts); let on_page_load_handler = on_page_load_handler.take().map(Arc::from); let document_title_changed_handler = document_title_changed_handler.map(Arc::from); let navigation_handler = navigation_handler.map(Arc::from); let devtools_enabled = (cfg!(debug_assertions) || cfg!(feature = "devtools")) - && webview_attributes.devtools.clone().unwrap_or(true); + && webview_attributes.devtools.unwrap_or(true); let custom_protocol_scheme = if webview_attributes.use_https_scheme { "https" @@ -2819,9 +2788,9 @@ pub(crate) fn create_webview( "http" }; - // Build cached domain names for custom schemes before uri_scheme_protocols is consumed - let custom_scheme_domain_names: Vec = uri_scheme_protocols - .keys() + let custom_schemes = uri_scheme_protocols.keys().cloned().collect::>(); + let custom_scheme_domain_names: Vec = custom_schemes + .iter() .map(|scheme| format!("{scheme}.localhost")) .collect(); @@ -2836,19 +2805,25 @@ pub(crate) fn create_webview( custom_protocol_scheme.to_string(), context.clone(), window_id, - None, ); let url = CefString::from(url.as_str()); + let uri_scheme_protocols: HashMap>> = uri_scheme_protocols + .into_iter() + .map(|(k, v)| (k, Arc::new(v))) + .collect(); + let mut request_context = request_context_from_webview_attributes( - &label, + context, &webview_attributes, - uri_scheme_protocols, - &custom_protocol_scheme, + &custom_schemes, + custom_protocol_scheme, &initialization_scripts, ); + let browser_id = Arc::new(RefCell::new(0)); let mut browser_view_delegate = BrowserViewDelegateImpl::new( + browser_id.clone(), platform_specific_attributes .iter() .find_map(|attr| match attr { @@ -2942,11 +2917,15 @@ pub(crate) fn create_webview( .unwrap() .webviews .push(AppWebview { + label, webview_id, - browser_view, + browser_view: Some(browser_view), + browser_id, overlay: Some(overlay), bounds: Arc::new(Mutex::new(initial_bounds_ratio)), devtools_enabled, + uri_scheme_protocols: Arc::new(uri_scheme_protocols), + initialization_scripts, }); } else { window.add_child_view(Some(&mut View::from(&browser_view))); @@ -2961,11 +2940,15 @@ pub(crate) fn create_webview( .unwrap() .webviews .push(AppWebview { + label, webview_id, - browser_view, + browser_view: Some(browser_view), + browser_id, overlay: None, bounds: Arc::new(Mutex::new(None)), devtools_enabled, + uri_scheme_protocols: Arc::new(uri_scheme_protocols), + initialization_scripts, }); } } @@ -2973,32 +2956,27 @@ pub(crate) fn create_webview( fn browser_settings_from_webview_attributes( webview_attributes: &WebviewAttributes, ) -> BrowserSettings { - // Build BrowserSettings based on webview attributes - let mut browser_settings = BrowserSettings::default(); - - // Configure JavaScript - browser_settings.javascript = State::from(if webview_attributes.javascript_disabled { - sys::cef_state_t::STATE_DISABLED - } else { - sys::cef_state_t::STATE_ENABLED - }); - - // Configure clipboard access - browser_settings.javascript_access_clipboard = State::from(if webview_attributes.clipboard { - sys::cef_state_t::STATE_ENABLED - } else { - sys::cef_state_t::STATE_DISABLED - }); - - browser_settings + BrowserSettings { + javascript: State::from(if webview_attributes.javascript_disabled { + sys::cef_state_t::STATE_DISABLED + } else { + sys::cef_state_t::STATE_ENABLED + }), + javascript_access_clipboard: State::from(if webview_attributes.clipboard { + sys::cef_state_t::STATE_ENABLED + } else { + sys::cef_state_t::STATE_DISABLED + }), + ..Default::default() + } } -fn request_context_from_webview_attributes( - label: &str, +fn request_context_from_webview_attributes( + context: &Context, webview_attributes: &WebviewAttributes, - uri_scheme_protocols: HashMap>, + custom_schemes: &[String], custom_protocol_scheme: &str, - initialization_scripts: &Vec, + _initialization_scripts: &[CefInitScript], ) -> Option { let global_context = request_context_get_global_context().expect("Failed to get global request context"); @@ -3024,15 +3002,13 @@ fn request_context_from_webview_attributes( Option::<&mut RequestContextHandler>::None, ); if let Some(request_context) = &request_context { - for (custom_scheme, handler) in uri_scheme_protocols { - let webview_label = label.to_string(); + for custom_scheme in custom_schemes { request_context.register_scheme_handler_factory( Some(&custom_protocol_scheme.into()), Some(&format!("{custom_scheme}.localhost").as_str().into()), Some(&mut request_handler::UriSchemeHandlerFactory::new( - webview_label.clone(), - Arc::new(handler) as Arc, - initialization_scripts.clone(), + context.clone(), + custom_scheme.clone(), )), ); } diff --git a/crates/tauri-runtime-cef/src/cef_impl/request_handler.rs b/crates/tauri-runtime-cef/src/cef_impl/request_handler.rs index 4956275fd..a2459d769 100644 --- a/crates/tauri-runtime-cef/src/cef_impl/request_handler.rs +++ b/crates/tauri-runtime-cef/src/cef_impl/request_handler.rs @@ -16,13 +16,15 @@ use http::{ HeaderMap, HeaderName, HeaderValue, }; use kuchiki::NodeRef; -use tauri_runtime::webview::UriSchemeProtocol; +use tauri_runtime::{webview::UriSchemeProtocol, UserEvent}; use tauri_utils::{ config::{Csp, CspDirectiveSources}, html::{parse as parse_html, serialize_node}, }; use url::Url; +use crate::cef_impl::Context; + use super::CefInitScript; fn csp_inject_initialization_scripts_hashes( @@ -108,7 +110,7 @@ fn inject_scripts_into_html_body( wrap_resource_request_handler! { pub struct WebResourceRequestHandler { - initialization_scripts: Vec, + initialization_scripts: Arc>, } impl ResourceRequestHandler { @@ -128,7 +130,7 @@ wrap_resource_request_handler! { wrap_request_handler! { pub struct WebRequestHandler { - initialization_scripts: Vec, + initialization_scripts: Arc>, navigation_handler: Option>, } @@ -180,8 +182,8 @@ wrap_request_handler! { wrap_resource_handler! { pub struct WebResourceHandler { webview_label: String, - handler: Arc, - initialization_scripts: Vec, + handler: Arc>, + initialization_scripts: Arc>, // we clone response to send it to the handler thread response: Arc>>>>>, } @@ -239,7 +241,8 @@ wrap_resource_handler! { std::thread::spawn(move || { let mut http_request = http::Request::builder().method(method).uri(url.as_str()).body(data).unwrap(); *http_request.headers_mut() = headers; - (handler)(&label, http_request, responder); + // handler is Arc>, so we need to dereference to call it + (**handler)(&label, http_request, responder); }); 1 } else { @@ -319,9 +322,7 @@ wrap_resource_handler! { .unwrap_or("text/plain"); response.set_mime_type(Some(&mime_type.into())); - response_length.map(|length| { - *length = -1; - }); + if let Some(length) = response_length { *length = -1; } if let Some(redirect_url) = redirect_url { let _ = std::mem::take(redirect_url); @@ -331,21 +332,34 @@ wrap_resource_handler! { } wrap_scheme_handler_factory! { - pub struct UriSchemeHandlerFactory { - webview_label: String, - handler: Arc, - initialization_scripts: Vec, + pub struct UriSchemeHandlerFactory { + context: Context, + scheme: String, } impl SchemeHandlerFactory { fn create( &self, - _browser: Option<&mut Browser>, + browser: Option<&mut Browser>, _frame: Option<&mut Frame>, _scheme_name: Option<&CefString>, _request: Option<&mut Request>, ) -> Option { - Some(WebResourceHandler::new(self.webview_label.clone(), self.handler.clone(), self.initialization_scripts.clone(), Arc::new(RefCell::new(None)))) + let browser = browser?; + let id = browser.identifier(); + + // get handler from AppWebview - UriSchemeFactory can be overwritten + // when registered on multiple RequestContexts sharing the same cache path + let (webview_label, handler, initialization_scripts) = self.context.windows.borrow().values().find_map(|window| { + window.webviews.iter().find(|webview| *webview.browser_id.borrow() == id) + .and_then(|webview| { + webview.uri_scheme_protocols.get(&self.scheme).map(|handler| { + (webview.label.clone(), handler.clone(), webview.initialization_scripts.clone()) + }) + }) + })?; + + Some(WebResourceHandler::new(webview_label, handler, initialization_scripts, Arc::new(RefCell::new(None)))) } } } @@ -367,7 +381,7 @@ fn read_request_body(request: &mut Request) -> Vec { if let Some(post_data) = request.post_data() { let mut elements = vec![None; post_data.element_count()]; post_data.elements(Some(&mut elements)); - for element in elements.into_iter().filter_map(|v| v) { + for element in elements.into_iter().flatten() { match element.get_type().as_ref() { sys::cef_postdataelement_type_t::PDE_TYPE_BYTES => { let size = element.bytes_count(); @@ -388,7 +402,7 @@ fn read_request_body(request: &mut Request) -> Vec { if let Ok(mut file) = std::fs::File::open(&file_path) { use std::io::Read; let mut buf = Vec::new(); - if let Ok(_) = file.read_to_end(&mut buf) { + if file.read_to_end(&mut buf).is_ok() { body.extend(buf); } } diff --git a/crates/tauri-runtime-cef/src/lib.rs b/crates/tauri-runtime-cef/src/lib.rs index 2e502360b..02a48004a 100644 --- a/crates/tauri-runtime-cef/src/lib.rs +++ b/crates/tauri-runtime-cef/src/lib.rs @@ -240,10 +240,17 @@ impl Clone for Message { #[derive(Clone)] pub(crate) struct AppWebview { pub webview_id: u32, - pub browser_view: cef::BrowserView, + pub label: String, + pub browser_view: Option, + // browser_view.browser is null on the scheme handler factory, + // so we need to use the browser_id to identify the browser + pub browser_id: Arc>, pub overlay: Option, pub bounds: Arc>>, pub devtools_enabled: bool, + pub uri_scheme_protocols: + Arc>>>, + pub initialization_scripts: Arc>, } #[derive(Debug, Clone)] @@ -279,10 +286,7 @@ impl AppWindow { fn window(&self) -> Option { match &self.window { AppWindowKind::Window(window) => Some(window.clone()), - AppWindowKind::BrowserWindow => self - .webviews - .first() - .and_then(|webview| webview.browser_view.window()), + AppWindowKind::BrowserWindow => None, } } } @@ -1050,7 +1054,7 @@ impl WebviewDispatch for CefWebviewDispatcher { self.context.post_message(Message::Webview { window_id: *self.window_id.lock().unwrap(), webview_id: self.webview_id, - message: WebviewMessage::WithWebview(Box::new(move |webview| f(webview))), + message: WebviewMessage::WithWebview(Box::new(f)), }) } @@ -1863,7 +1867,7 @@ impl CefRuntime { let (event_tx, event_rx) = channel(); - let cache_base = dirs::cache_dir().unwrap_or_else(|| std::env::temp_dir()); + let cache_base = dirs::cache_dir().unwrap_or_else(std::env::temp_dir); let cache_path = cache_base.join(&runtime_args.identifier).join("cef"); // Ensure the cache directory exists