From 6ba9105f4aec07187e679d78ee489dc3c35424b9 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Sun, 7 Dec 2025 16:58:32 +0000 Subject: [PATCH 1/4] Add macOS support for window visibility on all workspaces --- .../src-tauri/src/platform/macos/mod.rs | 19 ++++++++++ apps/desktop/src-tauri/src/windows.rs | 37 +++++++++++-------- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/apps/desktop/src-tauri/src/platform/macos/mod.rs b/apps/desktop/src-tauri/src/platform/macos/mod.rs index f6d5d47010..1cb74c9b98 100644 --- a/apps/desktop/src-tauri/src/platform/macos/mod.rs +++ b/apps/desktop/src-tauri/src/platform/macos/mod.rs @@ -26,6 +26,25 @@ pub fn set_window_level(window: tauri::Window, level: objc2_app_kit::NSWindowLev }); } +pub fn set_window_visible_on_all_workspaces(window: tauri::Window) { + use objc2_app_kit::NSWindowCollectionBehavior; + + let c_window = window.clone(); + _ = window.run_on_main_thread(move || unsafe { + let ns_win = c_window + .ns_window() + .expect("Failed to get native window handle") + as *const objc2_app_kit::NSWindow; + let current_behavior = (*ns_win).collectionBehavior(); + (*ns_win).setCollectionBehavior( + current_behavior + | NSWindowCollectionBehavior::CanJoinAllSpaces + | NSWindowCollectionBehavior::FullScreenAuxiliary + | NSWindowCollectionBehavior::Stationary, + ); + }); +} + // pub fn get_ns_window_number(ns_window: *mut c_void) -> isize { // let ns_window = ns_window as *const objc2_app_kit::NSWindow; diff --git a/apps/desktop/src-tauri/src/windows.rs b/apps/desktop/src-tauri/src/windows.rs index 0e817aa101..8a5d25f594 100644 --- a/apps/desktop/src-tauri/src/windows.rs +++ b/apps/desktop/src-tauri/src/windows.rs @@ -185,7 +185,7 @@ impl CapWindowId { Self::Main => (300.0, 360.0), Self::Editor { .. } => (1275.0, 800.0), Self::ScreenshotEditor { .. } => (800.0, 600.0), - Self::Settings => (600.0, 450.0), + Self::Settings => (600.0, 470.0), Self::Camera => (200.0, 200.0), Self::Upgrade => (950.0, 850.0), Self::ModeSelect => (900.0, 500.0), @@ -317,7 +317,12 @@ impl ShowCapWindow { if new_recording_flow { #[cfg(target_os = "macos")] - crate::platform::set_window_level(window.as_ref().window(), 50); + { + crate::platform::set_window_level(window.as_ref().window(), 50); + crate::platform::set_window_visible_on_all_workspaces( + window.as_ref().window(), + ); + } } #[cfg(target_os = "macos")] @@ -412,6 +417,7 @@ impl ShowCapWindow { #[cfg(target_os = "macos")] { crate::platform::set_window_level(window.as_ref().window(), 45); + crate::platform::set_window_visible_on_all_workspaces(window.as_ref().window()); } window @@ -585,16 +591,9 @@ impl ShowCapWindow { #[cfg(target_os = "macos")] { crate::platform::set_window_level(window.as_ref().window(), 60); - - _ = window.run_on_main_thread({ - let window = window.as_ref().window(); - move || unsafe { - let win = window.ns_window().unwrap() as *const objc2_app_kit::NSWindow; - (*win).setCollectionBehavior( - (*win).collectionBehavior() | objc2_app_kit::NSWindowCollectionBehavior::FullScreenAuxiliary, - ); - } - }); + crate::platform::set_window_visible_on_all_workspaces( + window.as_ref().window(), + ); } window @@ -640,6 +639,7 @@ impl ShowCapWindow { #[cfg(target_os = "macos")] { crate::platform::set_window_level(window.as_ref().window(), 900); + crate::platform::set_window_visible_on_all_workspaces(window.as_ref().window()); } window @@ -655,6 +655,7 @@ impl ShowCapWindow { .shadow(false) .resizable(false) .always_on_top(true) + .visible_on_all_workspaces(true) .content_protected(should_protect) .skip_taskbar(true) .closable(true) @@ -682,10 +683,13 @@ impl ShowCapWindow { let window = window_builder.build()?; #[cfg(target_os = "macos")] - crate::platform::set_window_level( - window.as_ref().window(), - objc2_app_kit::NSPopUpMenuWindowLevel, - ); + { + crate::platform::set_window_level( + window.as_ref().window(), + objc2_app_kit::NSPopUpMenuWindowLevel, + ); + crate::platform::set_window_visible_on_all_workspaces(window.as_ref().window()); + } // Hide the main window if the target monitor is the same if let Some(main_window) = CapWindowId::Main.get(app) @@ -731,6 +735,7 @@ impl ShowCapWindow { #[cfg(target_os = "macos")] { crate::platform::set_window_level(window.as_ref().window(), 1000); + crate::platform::set_window_visible_on_all_workspaces(window.as_ref().window()); } fake_window::spawn_fake_window_listener(app.clone(), window.clone()); From a1eb1e5b9ce71cc8b02a3c58a3e50364c38a58e9 Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Sun, 7 Dec 2025 16:58:47 +0000 Subject: [PATCH 2/4] Add pathname check to window focus navigation logic --- apps/desktop/src/routes/(window-chrome)/(main).tsx | 6 ++++-- apps/desktop/src/routes/(window-chrome)/new-main/index.tsx | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/routes/(window-chrome)/(main).tsx b/apps/desktop/src/routes/(window-chrome)/(main).tsx index 3f1be75165..f89b0574ba 100644 --- a/apps/desktop/src/routes/(window-chrome)/(main).tsx +++ b/apps/desktop/src/routes/(window-chrome)/(main).tsx @@ -59,10 +59,12 @@ function Page() { const currentRecording = createCurrentRecordingQuery(); const generalSettings = generalSettingsStore.createQuery(); - // We do this on focus so the window doesn't get revealed when toggling the setting const navigate = useNavigate(); createEventListener(window, "focus", () => { - if (generalSettings.data?.enableNewRecordingFlow === true) + if ( + window.location.pathname === "/" && + generalSettings.data?.enableNewRecordingFlow === true + ) navigate("/new-main"); }); diff --git a/apps/desktop/src/routes/(window-chrome)/new-main/index.tsx b/apps/desktop/src/routes/(window-chrome)/new-main/index.tsx index 82e0200fec..ff6866680d 100644 --- a/apps/desktop/src/routes/(window-chrome)/new-main/index.tsx +++ b/apps/desktop/src/routes/(window-chrome)/new-main/index.tsx @@ -343,7 +343,11 @@ export default function () { const navigate = useNavigate(); createEventListener(window, "focus", () => { - if (generalSettings.data?.enableNewRecordingFlow === false) navigate("/"); + if ( + window.location.pathname === "/new-main" && + generalSettings.data?.enableNewRecordingFlow === false + ) + navigate("/"); }); return ( From bc63d33409fdf7f22d6e2a2ca1456ee3735cfcae Mon Sep 17 00:00:00 2001 From: Richie McIlroy <33632126+richiemcilroy@users.noreply.github.com> Date: Sun, 7 Dec 2025 16:58:53 +0000 Subject: [PATCH 3/4] Update general settings section and Cap Pro group --- .../(window-chrome)/settings/general.tsx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/desktop/src/routes/(window-chrome)/settings/general.tsx b/apps/desktop/src/routes/(window-chrome)/settings/general.tsx index bf282d4b5b..02a8105ed8 100644 --- a/apps/desktop/src/routes/(window-chrome)/settings/general.tsx +++ b/apps/desktop/src/routes/(window-chrome)/settings/general.tsx @@ -153,9 +153,9 @@ function AppearanceSection(props: { return (
- General settings of your Cap application. + Customize how Cap looks, feels, and behaves.