diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs index 2a0eb78225..cbb8d1c828 100644 --- a/apps/desktop/src-tauri/src/lib.rs +++ b/apps/desktop/src-tauri/src/lib.rs @@ -2184,6 +2184,13 @@ pub async fn run(recording_logging_handle: LoggingHandle, logs_dir: PathBuf) { #[cfg(target_os = "macos")] app.manage(crate::platform::ScreenCapturePrewarmer::default()); + tokio::spawn({ + let app = app.clone(); + async move { + target_select_overlay::init(&app).await; + } + }); + tokio::spawn({ let camera_feed = camera_feed.clone(); let app = app.clone(); @@ -2351,7 +2358,7 @@ pub async fn run(recording_logging_handle: LoggingHandle, logs_dir: PathBuf) { if let Ok(CapWindowId::TargetSelectOverlay { .. }) = CapWindowId::from_str(&id) { - let _ = window.close(); + let _ = window.hide(); } } diff --git a/apps/desktop/src-tauri/src/recording.rs b/apps/desktop/src-tauri/src/recording.rs index 10b136e552..5e4ae9236f 100644 --- a/apps/desktop/src-tauri/src/recording.rs +++ b/apps/desktop/src-tauri/src/recording.rs @@ -415,7 +415,7 @@ pub async fn start_recording( .filter_map(|(label, win)| CapWindowId::from_str(label).ok().map(|id| (id, win))) { if matches!(id, CapWindowId::TargetSelectOverlay { .. }) { - win.close().ok(); + win.hide().ok(); } } let _ = ShowCapWindow::InProgressRecording { countdown } diff --git a/apps/desktop/src-tauri/src/target_select_overlay.rs b/apps/desktop/src-tauri/src/target_select_overlay.rs index 31a030d6b7..c0679ccb1e 100644 --- a/apps/desktop/src-tauri/src/target_select_overlay.rs +++ b/apps/desktop/src-tauri/src/target_select_overlay.rs @@ -7,6 +7,7 @@ use std::{ use base64::prelude::*; use cap_recording::screen_capture::ScreenCaptureTarget; +use futures::future::join_all; use crate::windows::{CapWindowId, ShowCapWindow}; use scap_targets::{ @@ -41,6 +42,31 @@ pub struct DisplayInformation { refresh_rate: String, } +// We create the windows hidden at app launch so they are ready when used. +// Otherwise we have noticed they can take a while to load on first interaction (especially on Windows). +pub async fn init(app: &AppHandle) { + join_all( + scap_targets::Display::list() + .into_iter() + .map(|d| d.id()) + .map(|display_id| { + let app = app.clone(); + + async move { + let result = ShowCapWindow::TargetSelectOverlay { display_id } + .show(&app) + .await + .map_err(|err| error!("Error initializing target select overlay: {err}")); + + if let Ok(window) = result { + window.hide().ok(); + } + } + }), + ) + .await; +} + #[specta::specta] #[tauri::command] #[instrument(skip(app, state))] @@ -49,15 +75,23 @@ pub async fn open_target_select_overlays( state: tauri::State<'_, WindowFocusManager>, focused_target: Option, ) -> Result<(), String> { - let displays = scap_targets::Display::list() - .into_iter() - .map(|d| d.id()) - .collect::>(); - for display_id in displays { - let _ = ShowCapWindow::TargetSelectOverlay { display_id } - .show(&app) - .await; - } + join_all( + scap_targets::Display::list() + .into_iter() + .map(|d| d.id()) + .map(|display_id| { + let app = app.clone(); + + async move { + ShowCapWindow::TargetSelectOverlay { display_id } + .show(&app) + .await + .map_err(|err| error!("Error initializing target select overlay: {err}")) + .ok(); + } + }), + ) + .await; let handle = tokio::spawn({ let app = app.clone(); @@ -116,7 +150,10 @@ pub async fn open_target_select_overlays( pub async fn close_target_select_overlays(app: AppHandle) -> Result<(), String> { for (id, window) in app.webview_windows() { if let Ok(CapWindowId::TargetSelectOverlay { .. }) = CapWindowId::from_str(&id) { - let _ = window.close(); + window + .hide() + .map_err(|err| error!("Error hiding target select overlay: {err}")) + .ok(); } } diff --git a/apps/desktop/src/routes/target-select-overlay.tsx b/apps/desktop/src/routes/target-select-overlay.tsx index cecab14f97..393de284a5 100644 --- a/apps/desktop/src/routes/target-select-overlay.tsx +++ b/apps/desktop/src/routes/target-select-overlay.tsx @@ -995,9 +995,3 @@ function ResizeHandle( /> ); } - -function getDisplayId(displayId: string | undefined) { - const id = Number(displayId); - if (Number.isNaN(id)) return 0; - return id; -}