-
Notifications
You must be signed in to change notification settings - Fork 902
feat: Implement new Window excluder system #1179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds a WindowExclusion model and resolver, surfaces bundle identifiers in window listings, adds UI and storage for excluded windows, runtime commands to refresh content-protection, propagates macOS recording-time exclusions into the capture pipeline, and renames a CapWindowId variant to RecordingControls. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant UI as Settings UI
participant TauriCmd as Tauri Commands
participant Store as GeneralSettingsStore
participant WinMgr as Window Manager
participant Resolver as WindowExclusion.resolve_window_ids
participant Recorder as Recording Pipeline
User->>UI: Open Settings / choose exclusions
UI->>TauriCmd: getDefaultExcludedWindows()
TauriCmd-->>UI: default exclusions
UI->>TauriCmd: save excludedWindows
TauriCmd->>Store: persist excluded_windows
TauriCmd->>WinMgr: refresh_window_content_protection()
WinMgr->>Store: read excluded_windows or defaults
WinMgr->>WinMgr: should_protect_window(title)
WinMgr-->>UI: update content_protected states
Note over UI,Recorder: On recording start (macOS)
UI->>TauriCmd: start recording
TauriCmd->>Store: read excluded_windows
TauriCmd->>Resolver: resolve_window_ids(excluded_windows)
Resolver-->>TauriCmd: WindowId[]
TauriCmd->>Recorder: start with excluded_windows
Recorder->>Recorder: ScreenCaptureConfig.init(..., excluded_windows)
Recorder-->>TauriCmd: recording started
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/recording/src/studio_recording.rs (1)
693-707
: Avoid unwrap on async screen capture initcreate_screen_capture().await.unwrap() can panic and crash recordings. Propagate an error instead.
- let screen_config = create_screen_capture( + let screen_config = create_screen_capture( &base_inputs.capture_target, !custom_cursor_capture, 120, start_time.system_time(), base_inputs.capture_system_audio, #[cfg(windows)] d3d_device, #[cfg(target_os = "macos")] base_inputs.shareable_content, - &base_inputs.excluded_windows, - ) - .await - .unwrap(); + &base_inputs.excluded_windows, + ) + .await + .context("failed to initialize screen capture")?;If you prefer a typed error, map it into CreateSegmentPipelineError.
🧹 Nitpick comments (4)
apps/desktop/src-tauri/src/windows.rs (1)
874-879
: Confirm fallback semantics for defaultsWith an existing store deserialized to an empty excluded_windows, defaults aren’t applied. If you want defaults unless the user explicitly overrides, consider:
- GeneralSettingsStore::get(app) - .ok() - .flatten() - .map(|settings| matches(&settings.excluded_windows)) - .unwrap_or_else(|| matches(&general_settings::default_excluded_windows())) + match GeneralSettingsStore::get(app).ok().flatten() { + Some(settings) if !settings.excluded_windows.is_empty() => { + matches(&settings.excluded_windows) + } + _ => matches(&general_settings::default_excluded_windows()), + }Otherwise, defaults will only apply when no store exists at all.
apps/desktop/src/routes/(window-chrome)/settings/general.tsx (2)
248-256
: Inline comments violate repo guidelinesThis file contains inline comments; guidelines state no inline/block/doc comments in TS/TSX. Please remove comments throughout the file and rely on self-explanatory code. Run pnpm format (Biome) after changes.
275-301
: Keep match semantics aligned with Rust WindowExclusion::matchesThe local matchesExclusion mirrors Rust logic. To avoid drift, consider centralizing this rule (e.g., expose prefiltered window options from Tauri) or add tests to assert parity for edge cases (ownerName+windowTitle, bundleIdentifier only).
crates/recording/src/sources/screen_capture/mod.rs (1)
62-109
: WindowExclusion::matches: add tests to lock semanticsLogic matches the UI’s matcher. Please add unit tests for:
- bundle_identifier match
- owner_name only
- owner_name + window_title (requires both)
- window_title only
- all-none returns false
I can draft these tests in this crate’s tests module if helpful.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
.claude/settings.local.json
(1 hunks)apps/desktop/src-tauri/src/general_settings.rs
(6 hunks)apps/desktop/src-tauri/src/lib.rs
(2 hunks)apps/desktop/src-tauri/src/recording.rs
(4 hunks)apps/desktop/src-tauri/src/thumbnails/mod.rs
(2 hunks)apps/desktop/src-tauri/src/windows.rs
(13 hunks)apps/desktop/src/routes/(window-chrome)/settings/general.tsx
(5 hunks)apps/desktop/src/utils/tauri.ts
(4 hunks)crates/recording/src/capture_pipeline.rs
(3 hunks)crates/recording/src/instant_recording.rs
(6 hunks)crates/recording/src/lib.rs
(2 hunks)crates/recording/src/sources/screen_capture/macos.rs
(2 hunks)crates/recording/src/sources/screen_capture/mod.rs
(7 hunks)crates/recording/src/studio_recording.rs
(6 hunks)crates/scap-targets/src/lib.rs
(1 hunks)crates/scap-targets/src/platform/macos.rs
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
crates/**/src/**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
For desktop IPC, use tauri_specta derive/macros on Rust types/events; do not hand-roll bindings
Files:
crates/scap-targets/src/lib.rs
crates/recording/src/sources/screen_capture/macos.rs
crates/recording/src/capture_pipeline.rs
crates/recording/src/sources/screen_capture/mod.rs
crates/recording/src/studio_recording.rs
crates/scap-targets/src/platform/macos.rs
crates/recording/src/lib.rs
crates/recording/src/instant_recording.rs
**/*.{ts,tsx,js,jsx,rs}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not add inline, block, or docstring comments in any language; code must be self-explanatory
Files:
crates/scap-targets/src/lib.rs
apps/desktop/src-tauri/src/thumbnails/mod.rs
crates/recording/src/sources/screen_capture/macos.rs
apps/desktop/src-tauri/src/general_settings.rs
crates/recording/src/capture_pipeline.rs
apps/desktop/src-tauri/src/lib.rs
apps/desktop/src/utils/tauri.ts
crates/recording/src/sources/screen_capture/mod.rs
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
crates/recording/src/studio_recording.rs
apps/desktop/src-tauri/src/recording.rs
crates/scap-targets/src/platform/macos.rs
apps/desktop/src-tauri/src/windows.rs
crates/recording/src/lib.rs
crates/recording/src/instant_recording.rs
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs
: Format Rust code usingrustfmt
and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.
Files:
crates/scap-targets/src/lib.rs
apps/desktop/src-tauri/src/thumbnails/mod.rs
crates/recording/src/sources/screen_capture/macos.rs
apps/desktop/src-tauri/src/general_settings.rs
crates/recording/src/capture_pipeline.rs
apps/desktop/src-tauri/src/lib.rs
crates/recording/src/sources/screen_capture/mod.rs
crates/recording/src/studio_recording.rs
apps/desktop/src-tauri/src/recording.rs
crates/scap-targets/src/platform/macos.rs
apps/desktop/src-tauri/src/windows.rs
crates/recording/src/lib.rs
crates/recording/src/instant_recording.rs
crates/*/src/**/*
📄 CodeRabbit inference engine (AGENTS.md)
Rust crates should place tests within the
src/
and/or a siblingtests/
directory for each crate insidecrates/*
.
Files:
crates/scap-targets/src/lib.rs
crates/recording/src/sources/screen_capture/macos.rs
crates/recording/src/capture_pipeline.rs
crates/recording/src/sources/screen_capture/mod.rs
crates/recording/src/studio_recording.rs
crates/scap-targets/src/platform/macos.rs
crates/recording/src/lib.rs
crates/recording/src/instant_recording.rs
**/tauri.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Never edit auto-generated IPC bindings file tauri.ts
Do not edit auto-generated files named
tauri.ts
.
Files:
apps/desktop/src/utils/tauri.ts
apps/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/desktop/**/*.{ts,tsx}
: Do not manually import icons in the desktop app; rely on auto-imported icons
In the desktop app, use @tanstack/solid-query for server state management
Files:
apps/desktop/src/utils/tauri.ts
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use strict TypeScript and avoid any; leverage shared types from packages
**/*.{ts,tsx}
: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by runningpnpm format
.
Files:
apps/desktop/src/utils/tauri.ts
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}
: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g.,user-menu.tsx
).
Use PascalCase for React/Solid components.
Files:
apps/desktop/src/utils/tauri.ts
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
🧬 Code graph analysis (13)
crates/scap-targets/src/lib.rs (1)
crates/scap-targets/src/platform/macos.rs (1)
bundle_identifier
(350-383)
crates/recording/src/sources/screen_capture/macos.rs (3)
apps/desktop/src-tauri/src/platform/macos/sc_shareable_content.rs (3)
new
(140-158)window
(164-166)display
(160-162)crates/scap-targets/src/lib.rs (5)
list
(16-18)list
(103-105)owner_name
(134-136)bundle_identifier
(142-144)display
(150-152)crates/scap-targets/src/platform/macos.rs (5)
list
(32-38)list
(237-269)owner_name
(320-332)bundle_identifier
(350-383)display
(524-544)
apps/desktop/src-tauri/src/general_settings.rs (6)
apps/desktop/src/utils/tauri.ts (1)
WindowExclusion
(488-488)apps/desktop/src-tauri/src/windows.rs (1)
title
(120-133)crates/recording/src/sources/screen_capture/mod.rs (1)
title
(243-249)crates/scap-targets/src/lib.rs (2)
bundle_identifier
(142-144)owner_name
(134-136)crates/scap-targets/src/platform/macos.rs (2)
bundle_identifier
(350-383)owner_name
(320-332)crates/scap-targets/src/platform/win.rs (1)
owner_name
(443-483)
crates/recording/src/capture_pipeline.rs (1)
apps/desktop/src/utils/tauri.ts (2)
ScreenCaptureTarget
(461-461)WindowExclusion
(488-488)
apps/desktop/src-tauri/src/lib.rs (3)
apps/desktop/src-tauri/src/windows.rs (1)
refresh_window_content_protection
(883-894)apps/desktop/src-tauri/src/general_settings.rs (1)
get_default_excluded_windows
(270-272)apps/desktop/src/utils/tauri.ts (1)
WindowExclusion
(488-488)
crates/recording/src/sources/screen_capture/mod.rs (3)
apps/desktop/src/utils/tauri.ts (2)
WindowExclusion
(488-488)CaptureWindow
(374-374)crates/scap-targets/src/lib.rs (4)
bundle_identifier
(142-144)owner_name
(134-136)name
(40-42)name
(154-156)crates/scap-targets/src/platform/macos.rs (4)
bundle_identifier
(350-383)owner_name
(320-332)name
(128-147)name
(385-397)
apps/desktop/src/routes/(window-chrome)/settings/general.tsx (2)
apps/desktop/src/utils/tauri.ts (5)
WindowExclusion
(488-488)CaptureWindow
(374-374)GeneralSettingsStore
(399-399)commands
(7-284)events
(289-335)apps/desktop/src/store.ts (1)
generalSettingsStore
(61-62)
crates/recording/src/studio_recording.rs (3)
crates/recording/src/capture_pipeline.rs (4)
OutputPipeline
(40-43)OutputPipeline
(53-54)OutputPipeline
(81-84)OutputPipeline
(100-101)apps/desktop/src/utils/tauri.ts (1)
WindowExclusion
(488-488)crates/recording/src/instant_recording.rs (2)
new
(227-235)with_excluded_windows
(247-250)
apps/desktop/src-tauri/src/recording.rs (2)
apps/desktop/src/utils/tauri.ts (3)
GeneralSettingsStore
(399-399)PostDeletionBehaviour
(436-436)PostStudioRecordingBehaviour
(437-437)apps/desktop/src-tauri/src/general_settings.rs (1)
default_excluded_windows
(50-59)
crates/scap-targets/src/platform/macos.rs (1)
crates/scap-targets/src/lib.rs (3)
bundle_identifier
(142-144)id
(28-30)id
(118-120)
apps/desktop/src-tauri/src/windows.rs (2)
crates/recording/src/sources/screen_capture/mod.rs (2)
title
(243-249)matches
(63-108)apps/desktop/src-tauri/src/general_settings.rs (2)
get
(205-216)default_excluded_windows
(50-59)
crates/recording/src/lib.rs (1)
apps/desktop/src/utils/tauri.ts (2)
ScreenCaptureTarget
(461-461)WindowExclusion
(488-488)
crates/recording/src/instant_recording.rs (2)
crates/recording/src/studio_recording.rs (3)
new
(351-361)new
(589-606)with_excluded_windows
(383-389)apps/desktop/src/utils/tauri.ts (2)
ScreenCaptureTarget
(461-461)WindowExclusion
(488-488)
🪛 GitHub Check: Clippy
crates/recording/src/sources/screen_capture/macos.rs
[warning] 13-13: unused import: collections::HashSet
warning: unused import: collections::HashSet
--> crates/recording/src/sources/screen_capture/macos.rs:13:5
|
13 | collections::HashSet,
| ^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(unused_imports)]
on by default
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
- GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
- GitHub Check: Analyze (rust)
🔇 Additional comments (23)
.claude/settings.local.json (1)
3-8
: Allowlist update aligns with new workflowAdding
Bash(cargo check:*)
keeps the local automation in sync with the cargo-based tooling introduced in this PR. Looks good.crates/scap-targets/src/lib.rs (1)
142-144
: NewWindow::bundle_identifier
API looks good; ensure cross‑platform parityConfirm
platform::WindowImpl::bundle_identifier()
exists on all targets (or gate this method with cfg) to avoid non‑macOS build breaks. Consider adding a matchingDisplay::bundle_identifier()
wrapper if you intend to expose display bundle IDs too.apps/desktop/src/utils/tauri.ts (4)
47-52
: New commands surfaced
refreshWindowContentProtection
andgetDefaultExcludedWindows
look correct in shape. Verify the backend commands exist and are exported, and that calling them is safe across platforms.
374-376
: Types extended withbundle_identifier
Adding
bundle_identifier: string | null
to window types aligns with the Rust changes. LGTM.
399-399
: GeneralSettingsStore:excludedWindows
Type looks right. Ensure Rust
GeneralSettingsStore
maps this field consistently (Option vs Vec with default), and consumers fall back to default exclusions when unset.
488-488
: NewWindowExclusion
typeShape is clear and minimal for matching. LGTM.
apps/desktop/src-tauri/src/thumbnails/mod.rs (2)
36-37
: Propagatebundle_identifier
in modelExtending
CaptureWindowWithThumbnail
is consistent with the rest of the PR. LGTM.
144-145
: Plumb throughbundle_identifier
Forwarding from
capture_window
is correct. LGTM.apps/desktop/src-tauri/src/recording.rs (3)
47-49
: Imports updated for settings/exclusionsImports look correct and scoped. LGTM.
478-480
: Studio builder: exclusions wiredChaining
.with_excluded_windows(excluded_windows.clone())
is correct. LGTM.
519-521
: Instant builder: exclusions wiredPassing
excluded_windows
here too keeps behavior consistent across modes. LGTM.crates/recording/src/studio_recording.rs (2)
347-360
: Builder wiring for excluded_windows looks goodField default and initialization are correct; no concerns.
382-389
: with_excluded_windows builder API is appropriateSimple and clear; threads through as expected.
crates/recording/src/instant_recording.rs (3)
218-234
: ActorBuilder excludes wiringNew field and default initialization are correct.
247-251
: with_excluded_windows APILooks good and consistent with studio flow.
291-302
: create_screen_capture propagationPassing excluded_windows by slice and propagating shareable_content is correct.
Consider adding a small integration test ensuring an exclusion actually removes a known window on macOS, to guard regressions.
apps/desktop/src/routes/(window-chrome)/settings/general.tsx (2)
336-348
: Apply + refresh flow is solidPersisting store, refreshing window content protection, and prewarming on macOS is correct. Nice.
37-39
: Do not manually import icons in desktop app; rely on auto-importPer guidelines, remove explicit icon imports. Also ensure IconCapChevronDown is available via auto-import; otherwise this will fail at runtime/build.
-import IconLucidePlus from "~icons/lucide/plus"; -import IconLucideX from "~icons/lucide/x";Replace usages with the auto-imported components as configured.
crates/recording/src/sources/screen_capture/mod.rs (4)
28-36
: CaptureWindow gains bundle_identifierGood addition; aligns with TS type (nullable). No issues.
51-60
: WindowExclusion public type is well-shapedSerde camelCase + specta Type are correct for IPC.
331-343
: ScreenCaptureConfig::init signature extensionAdding excluded_windows parameter is fine; keep threading consistent across platforms.
Ensure downstream callers updated (capture_pipeline, instant/studio recording).
532-548
: list_windows: owner_name and bundle_identifier captureThis matches platform capabilities; good macOS gating and Windows fallback to None.
apps/desktop/src-tauri/src/windows.rs (1)
868-895
: Content protection ignores bundleIdentifier/ownerName rules; only windowTitle is checkedUser exclusions set by bundleIdentifier or ownerName won’t protect Cap windows, since should_protect_window passes None for those. On macOS, UI often stores bundleIdentifier; content_protected will remain off unexpectedly.
Pass app owner/bundle to WindowExclusion::matches. Example:
-fn should_protect_window(app: &AppHandle<Wry>, window_title: &str) -> bool { - let matches = |list: &[WindowExclusion]| { - list.iter() - .any(|entry| entry.matches(None, None, Some(window_title))) - }; +fn should_protect_window(app: &AppHandle<Wry>, window_title: &str) -> bool { + // Derive identifiers for this app/process + // Prefer bundle identifier when available; fall back to product/app name. + #[cfg(target_os = "macos")] + let bundle_identifier: Option<String> = app + .config() + .tauri + .bundle + .identifier + .clone(); + #[cfg(not(target_os = "macos"))] + let bundle_identifier: Option<String> = None; + + let owner_name: Option<String> = Some(app.package_info().name.clone()); + + let matches = |list: &[WindowExclusion]| { + list.iter().any(|entry| { + entry.matches( + bundle_identifier.as_deref(), + owner_name.as_deref(), + Some(window_title), + ) + }) + };Adjust the retrieval if your Tauri version exposes identifiers differently. This ensures bundle/owner-based rules affect Cap windows’ content protection.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
crates/scap-targets/src/platform/win.rs (1)
485-523
: DRY via get_executable_path(), normalize to lowercase, and remove inline comments
- Reuse existing get_executable_path() to avoid code duplication and keep behavior consistent.
- Lowercase the stem for stable, case-insensitive matching (aligns with IGNORED_EXES and cross‑platform expectations).
- Remove inline comments to comply with the no‑comments guideline.
- pub fn bundle_identifier(&self) -> Option<String> { - // On Windows, use the executable name as the bundle identifier - // This is similar to the macOS bundle identifier concept - unsafe { - let mut process_id = 0u32; - GetWindowThreadProcessId(self.0, Some(&mut process_id)); - - if process_id == 0 { - return None; - } - - let process_handle = - OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, process_id).ok()?; - - let mut buffer = [0u16; 1024]; - let mut buffer_size = buffer.len() as u32; - - let result = QueryFullProcessImageNameW( - process_handle, - PROCESS_NAME_FORMAT::default(), - PWSTR(buffer.as_mut_ptr()), - &mut buffer_size, - ); - - let _ = CloseHandle(process_handle); - - if result.is_ok() && buffer_size > 0 { - let path_str = String::from_utf16_lossy(&buffer[..buffer_size as usize]); - - // Return the executable name (without extension) as the bundle identifier - std::path::Path::new(&path_str) - .file_stem() - .map(|stem| stem.to_string_lossy().into_owned()) - } else { - None - } - } - } + pub fn bundle_identifier(&self) -> Option<String> { + let path = self.get_executable_path()?; + std::path::Path::new(&path) + .file_stem() + .map(|stem| stem.to_string_lossy().into_owned().to_lowercase()) + }Please confirm that downstream exclusion matching expects a case-insensitive identifier; if so, this normalization avoids mismatches. As per coding guidelines.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
crates/scap-targets/src/platform/win.rs
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
crates/**/src/**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
For desktop IPC, use tauri_specta derive/macros on Rust types/events; do not hand-roll bindings
Files:
crates/scap-targets/src/platform/win.rs
**/*.{ts,tsx,js,jsx,rs}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not add inline, block, or docstring comments in any language; code must be self-explanatory
Files:
crates/scap-targets/src/platform/win.rs
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs
: Format Rust code usingrustfmt
and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.
Files:
crates/scap-targets/src/platform/win.rs
crates/*/src/**/*
📄 CodeRabbit inference engine (AGENTS.md)
Rust crates should place tests within the
src/
and/or a siblingtests/
directory for each crate insidecrates/*
.
Files:
crates/scap-targets/src/platform/win.rs
🧬 Code graph analysis (1)
crates/scap-targets/src/platform/win.rs (2)
crates/scap-targets/src/lib.rs (1)
bundle_identifier
(142-144)crates/scap-targets/src/platform/macos.rs (1)
bundle_identifier
(350-383)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
- GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
- GitHub Check: Analyze (rust)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
.claude/settings.local.json
(1 hunks)apps/desktop/src-tauri/src/general_settings.rs
(6 hunks)apps/desktop/src-tauri/src/lib.rs
(3 hunks)apps/desktop/src-tauri/src/recording.rs
(5 hunks)apps/desktop/src-tauri/src/window_exclusion.rs
(1 hunks)apps/desktop/src-tauri/src/windows.rs
(13 hunks)crates/recording/src/capture_pipeline.rs
(3 hunks)crates/recording/src/instant_recording.rs
(6 hunks)crates/recording/src/lib.rs
(2 hunks)crates/recording/src/sources/screen_capture/macos.rs
(2 hunks)crates/recording/src/sources/screen_capture/mod.rs
(6 hunks)crates/recording/src/studio_recording.rs
(6 hunks)crates/scap-targets/src/platform/macos.rs
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- crates/recording/src/capture_pipeline.rs
- crates/scap-targets/src/platform/macos.rs
- crates/recording/src/sources/screen_capture/mod.rs
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx,rs}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not add inline, block, or docstring comments in any language; code must be self-explanatory
Files:
apps/desktop/src-tauri/src/general_settings.rs
apps/desktop/src-tauri/src/windows.rs
apps/desktop/src-tauri/src/recording.rs
apps/desktop/src-tauri/src/lib.rs
crates/recording/src/studio_recording.rs
apps/desktop/src-tauri/src/window_exclusion.rs
crates/recording/src/instant_recording.rs
crates/recording/src/sources/screen_capture/macos.rs
crates/recording/src/lib.rs
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs
: Format Rust code usingrustfmt
and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.
Files:
apps/desktop/src-tauri/src/general_settings.rs
apps/desktop/src-tauri/src/windows.rs
apps/desktop/src-tauri/src/recording.rs
apps/desktop/src-tauri/src/lib.rs
crates/recording/src/studio_recording.rs
apps/desktop/src-tauri/src/window_exclusion.rs
crates/recording/src/instant_recording.rs
crates/recording/src/sources/screen_capture/macos.rs
crates/recording/src/lib.rs
crates/**/src/**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
For desktop IPC, use tauri_specta derive/macros on Rust types/events; do not hand-roll bindings
Files:
crates/recording/src/studio_recording.rs
crates/recording/src/instant_recording.rs
crates/recording/src/sources/screen_capture/macos.rs
crates/recording/src/lib.rs
crates/*/src/**/*
📄 CodeRabbit inference engine (AGENTS.md)
Rust crates should place tests within the
src/
and/or a siblingtests/
directory for each crate insidecrates/*
.
Files:
crates/recording/src/studio_recording.rs
crates/recording/src/instant_recording.rs
crates/recording/src/sources/screen_capture/macos.rs
crates/recording/src/lib.rs
🧬 Code graph analysis (9)
apps/desktop/src-tauri/src/general_settings.rs (5)
apps/desktop/src/utils/tauri.ts (1)
WindowExclusion
(488-488)apps/desktop/src-tauri/src/windows.rs (1)
title
(120-133)crates/recording/src/sources/screen_capture/mod.rs (1)
title
(183-189)crates/scap-targets/src/platform/macos.rs (2)
bundle_identifier
(350-378)owner_name
(320-332)crates/scap-targets/src/platform/win.rs (2)
bundle_identifier
(485-522)owner_name
(443-483)
apps/desktop/src-tauri/src/windows.rs (2)
apps/desktop/src-tauri/src/window_exclusion.rs (1)
matches
(18-63)apps/desktop/src-tauri/src/general_settings.rs (2)
get
(205-216)default_excluded_windows
(50-59)
apps/desktop/src-tauri/src/recording.rs (3)
apps/desktop/src/utils/tauri.ts (3)
GeneralSettingsStore
(399-399)PostDeletionBehaviour
(436-436)PostStudioRecordingBehaviour
(437-437)apps/desktop/src-tauri/src/general_settings.rs (1)
default_excluded_windows
(50-59)apps/desktop/src-tauri/src/window_exclusion.rs (1)
resolve_window_ids
(66-95)
apps/desktop/src-tauri/src/lib.rs (3)
apps/desktop/src-tauri/src/windows.rs (1)
refresh_window_content_protection
(883-894)apps/desktop/src-tauri/src/general_settings.rs (1)
get_default_excluded_windows
(270-272)apps/desktop/src/utils/tauri.ts (1)
WindowExclusion
(488-488)
crates/recording/src/studio_recording.rs (2)
apps/desktop/src/utils/tauri.ts (1)
WindowId
(489-489)crates/recording/src/instant_recording.rs (2)
new
(228-236)with_excluded_windows
(248-251)
apps/desktop/src-tauri/src/window_exclusion.rs (2)
apps/desktop/src/utils/tauri.ts (2)
WindowId
(489-489)WindowExclusion
(488-488)crates/scap-targets/src/platform/macos.rs (4)
bundle_identifier
(350-378)owner_name
(320-332)list
(32-38)list
(237-269)
crates/recording/src/instant_recording.rs (2)
crates/recording/src/studio_recording.rs (3)
new
(352-362)new
(587-604)with_excluded_windows
(384-387)apps/desktop/src/utils/tauri.ts (2)
ScreenCaptureTarget
(461-461)WindowId
(489-489)
crates/recording/src/sources/screen_capture/macos.rs (2)
apps/desktop/src-tauri/src/platform/macos/sc_shareable_content.rs (3)
new
(140-158)window
(164-166)display
(160-162)crates/scap-targets/src/lib.rs (3)
from_id
(32-34)from_id
(122-124)display
(150-152)
crates/recording/src/lib.rs (1)
apps/desktop/src/utils/tauri.ts (2)
WindowId
(489-489)LogicalBounds
(418-418)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
- GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
- GitHub Check: Analyze (rust)
🔇 Additional comments (5)
.claude/settings.local.json (1)
6-7
: Allow-list update looks good.Adding
Bash(cargo check:*)
keeps the pattern consistent with existing pnpm entries and enables the new workflow without broadening scope unnecessarily.crates/recording/src/instant_recording.rs (4)
4-4
: LGTM! Import changes are correct.Line 4 removes an unused import (CameraFeedLock), and Line 12 adds the necessary WindowId import for the new exclusion feature.
Also applies to: 12-12
224-224
: LGTM! Field addition follows established pattern.The
excluded_windows
field is properly initialized to an empty vector (Line 234), matching the implementation instudio_recording.rs
per the relevant snippets.Also applies to: 234-234
248-251
: LGTM! Builder method correctly implements the pattern.The
with_excluded_windows
method follows the builder pattern and matches the implementation instudio_recording.rs
(lines 379-386).
266-266
: LGTM! Exclusions correctly propagate through the pipeline.Line 266 passes
excluded_windows
intoRecordingBaseInputs
, and Line 302 correctly borrows it when callingcreate_screen_capture
. The complete flow (builder → RecordingBaseInputs → screen capture) is properly wired.Also applies to: 302-302
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/desktop/src-tauri/src/recording.rs (1)
740-757
: Race: deleting recording dir while actor may still be runningDropping the handle relies on Drop to Stop asynchronously, then removing the dir immediately. This can race with ongoing writes. Explicitly cancel/stop and await before removal.
Apply:
- if let Some((_, recording_dir, video_id)) = recording_data { + if let Some((recording, recording_dir, video_id)) = recording_data { CurrentRecordingChanged.emit(&app).ok(); RecordingStopped {}.emit(&app).ok(); - - // let _ = recording.cancel().await; + let _ = recording.cancel().await;
♻️ Duplicate comments (1)
apps/desktop/src-tauri/src/general_settings.rs (1)
43-48
: Extend defaults to protect all Cap overlays (regression risk)The default list misses occluders and overlays that were previously protected. Add them to avoid capturing Cap’s own UI on fresh installs.
const DEFAULT_EXCLUDED_WINDOW_TITLES: &[&str] = &[ "Cap", "Cap Settings", "Cap Recording Controls", "Cap Camera", + "Cap Window Capture Occluder", + "Cap Capture Area", + "Cap Recordings Overlay", ];
🧹 Nitpick comments (4)
apps/desktop/src-tauri/src/window_exclusion.rs (2)
17-64
: Match semantics are strict; consider case-insensitive/title contains for robustnessExact equality on owner/title can be brittle (minor title changes, case). Consider case-insensitive equality or a “contains” option for window_title to reduce false negatives, while keeping bundle_identifier as exact.
66-95
: Potential enhancement: deterministic ordering and early-exitFunction is correct. For stability, consider sorting resulting WindowIds to make outputs deterministic. Not required for correctness.
apps/desktop/src-tauri/src/recording.rs (1)
479-488
: macOS: exclusion plumbing looks correct; minor clone reductions possibleLogic correctly falls back to defaults and resolves WindowIds; propagation via with_excluded_windows in both Studio/Instant builders is good. Optional: avoid cloning when settings exist by borrowing or using Cow to reduce allocs.
Apply locally, if desired:
- let excluded = { - let window_exclusions = general_settings - .as_ref() - .map_or_else(general_settings::default_excluded_windows, |s| s.excluded_windows.clone()); - crate::window_exclusion::resolve_window_ids(&window_exclusions) - }; + use std::borrow::Cow; + let excluded = { + let window_exclusions: Cow<[crate::window_exclusion::WindowExclusion]> = + general_settings + .as_ref() + .map(|s| Cow::Borrowed(&s.excluded_windows)) + .unwrap_or_else(|| Cow::Owned(general_settings::default_excluded_windows())); + crate::window_exclusion::resolve_window_ids(&window_exclusions) + };Also applies to: 503-505, 546-548
apps/desktop/src-tauri/src/windows.rs (1)
882-895
: Hook refresh into settings updatesThe refresh_window_content_protection command is useful. Consider invoking it automatically after saving GeneralSettingsStore to apply changes immediately without requiring a manual refresh.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
apps/desktop/src-tauri/src/general_settings.rs
(6 hunks)apps/desktop/src-tauri/src/lib.rs
(4 hunks)apps/desktop/src-tauri/src/recording.rs
(9 hunks)apps/desktop/src-tauri/src/window_exclusion.rs
(1 hunks)apps/desktop/src-tauri/src/windows.rs
(19 hunks)apps/desktop/src/routes/(window-chrome)/settings/general.tsx
(5 hunks)apps/desktop/src/routes/debug.tsx
(1 hunks)apps/desktop/src/utils/tauri.ts
(4 hunks)crates/recording/src/capture_pipeline.rs
(3 hunks)crates/recording/src/instant_recording.rs
(6 hunks)crates/recording/src/lib.rs
(2 hunks)crates/recording/src/sources/screen_capture/mod.rs
(6 hunks)crates/recording/src/studio_recording.rs
(6 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- crates/recording/src/studio_recording.rs
- crates/recording/src/capture_pipeline.rs
- crates/recording/src/sources/screen_capture/mod.rs
- apps/desktop/src/routes/(window-chrome)/settings/general.tsx
🧰 Additional context used
📓 Path-based instructions (8)
apps/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/desktop/**/*.{ts,tsx}
: Do not manually import icons in the desktop app; rely on auto-imported icons
In the desktop app, use @tanstack/solid-query for server state management
Files:
apps/desktop/src/routes/debug.tsx
apps/desktop/src/utils/tauri.ts
**/*.{ts,tsx,js,jsx,rs}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not add inline, block, or docstring comments in any language; code must be self-explanatory
Files:
apps/desktop/src/routes/debug.tsx
apps/desktop/src-tauri/src/windows.rs
crates/recording/src/lib.rs
apps/desktop/src-tauri/src/lib.rs
apps/desktop/src/utils/tauri.ts
apps/desktop/src-tauri/src/recording.rs
crates/recording/src/instant_recording.rs
apps/desktop/src-tauri/src/general_settings.rs
apps/desktop/src-tauri/src/window_exclusion.rs
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use strict TypeScript and avoid any; leverage shared types from packages
**/*.{ts,tsx}
: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by runningpnpm format
.
Files:
apps/desktop/src/routes/debug.tsx
apps/desktop/src/utils/tauri.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}
: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g.,user-menu.tsx
).
Use PascalCase for React/Solid components.
Files:
apps/desktop/src/routes/debug.tsx
apps/desktop/src/utils/tauri.ts
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs
: Format Rust code usingrustfmt
and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.
Files:
apps/desktop/src-tauri/src/windows.rs
crates/recording/src/lib.rs
apps/desktop/src-tauri/src/lib.rs
apps/desktop/src-tauri/src/recording.rs
crates/recording/src/instant_recording.rs
apps/desktop/src-tauri/src/general_settings.rs
apps/desktop/src-tauri/src/window_exclusion.rs
crates/**/src/**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
For desktop IPC, use tauri_specta derive/macros on Rust types/events; do not hand-roll bindings
Files:
crates/recording/src/lib.rs
crates/recording/src/instant_recording.rs
crates/*/src/**/*
📄 CodeRabbit inference engine (AGENTS.md)
Rust crates should place tests within the
src/
and/or a siblingtests/
directory for each crate insidecrates/*
.
Files:
crates/recording/src/lib.rs
crates/recording/src/instant_recording.rs
**/tauri.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Never edit auto-generated IPC bindings file tauri.ts
Do not edit auto-generated files named
tauri.ts
.
Files:
apps/desktop/src/utils/tauri.ts
🧬 Code graph analysis (7)
apps/desktop/src-tauri/src/windows.rs (2)
apps/desktop/src-tauri/src/window_exclusion.rs (1)
matches
(18-63)apps/desktop/src-tauri/src/general_settings.rs (2)
get
(205-216)default_excluded_windows
(50-59)
crates/recording/src/lib.rs (3)
apps/desktop/src-tauri/src/target_select_overlay.rs (1)
scap_targets
(49-52)crates/scap-targets/src/main.rs (1)
scap_targets
(123-129)apps/desktop/src/utils/tauri.ts (2)
WindowId
(487-487)LogicalBounds
(415-415)
apps/desktop/src-tauri/src/lib.rs (3)
apps/desktop/src-tauri/src/windows.rs (1)
refresh_window_content_protection
(884-895)apps/desktop/src-tauri/src/general_settings.rs (1)
get_default_excluded_windows
(270-272)apps/desktop/src/utils/tauri.ts (1)
WindowExclusion
(486-486)
apps/desktop/src-tauri/src/recording.rs (2)
apps/desktop/src-tauri/src/general_settings.rs (1)
default_excluded_windows
(50-59)apps/desktop/src-tauri/src/window_exclusion.rs (1)
resolve_window_ids
(66-95)
crates/recording/src/instant_recording.rs (3)
crates/recording/src/studio_recording.rs (3)
new
(353-364)new
(591-608)with_excluded_windows
(387-390)apps/desktop/src/utils/tauri.ts (2)
ScreenCaptureTarget
(459-459)WindowId
(487-487)crates/scap-targets/src/platform/macos.rs (1)
Self
(286-295)
apps/desktop/src-tauri/src/general_settings.rs (5)
apps/desktop/src/utils/tauri.ts (1)
WindowExclusion
(486-486)apps/desktop/src-tauri/src/windows.rs (1)
title
(121-134)crates/recording/src/sources/screen_capture/mod.rs (1)
title
(183-189)crates/scap-targets/src/platform/macos.rs (2)
bundle_identifier
(350-378)owner_name
(320-332)crates/scap-targets/src/platform/win.rs (1)
owner_name
(443-483)
apps/desktop/src-tauri/src/window_exclusion.rs (2)
apps/desktop/src/utils/tauri.ts (2)
WindowId
(487-487)WindowExclusion
(486-486)crates/scap-targets/src/platform/macos.rs (4)
bundle_identifier
(350-378)owner_name
(320-332)list
(32-38)list
(237-269)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
- GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
- GitHub Check: Analyze (rust)
🔇 Additional comments (12)
apps/desktop/src-tauri/src/lib.rs (1)
28-28
: Wiring additions look correct and consistent
- window_exclusion module added
- Commands exposed: windows::refresh_window_content_protection and general_settings::get_default_excluded_windows
- Specta types include WindowExclusion and Flags
- Denylist updated to RecordingControls
LGTM.
Also applies to: 1922-1924, 2023-2025, 2124-2125
apps/desktop/src-tauri/src/general_settings.rs (4)
50-59
: Default exclusions builder OKMapping titles into WindowExclusion entries is correct and aligns with TS type shape.
121-123
: Store field and default initialization look goodNew excluded_windows field with sensible default is correctly added to the store and Default.
Also applies to: 186-187
239-248
: Exclusion predicate looks goodDelegates to WindowExclusion::matches; no issues.
268-272
: Command exposure OKget_default_excluded_windows properly exposed for clients.
apps/desktop/src/routes/debug.tsx (1)
25-30
: Retain InProgressRecording variant
The TSShowCapWindow
union (inapps/desktop/src/utils/tauri.ts
) only defines{ InProgressRecording: { countdown } }
—there is noRecordingControls
variant on the TS side.Likely an incorrect or invalid review comment.
apps/desktop/src-tauri/src/recording.rs (2)
48-50
: Grouped general_settings import is fineKeeps default_excluded_windows reachable without broadening scope. No issues.
598-601
: Rename to RecordingControls wired through correctlyParenting dialogs and close-on-end now reference CapWindowId::RecordingControls consistently. Looks good.
Also applies to: 640-642, 827-829
apps/desktop/src/utils/tauri.ts (1)
47-52
: New bindings and types look consistent; confirm backing commands/types existThese additions align with the Rust side changes. Since this file is auto-generated, ensure it wasn’t edited manually and that:
- Tauri commands refresh_window_content_protection and get_default_excluded_windows are exported in Rust with specta.
- CaptureWindow(_WithThumbnail).bundle_identifier and GeneralSettingsStore.excludedWindows map to Rust fields (snake_case to camelCase).
Please verify by re-running codegen (tauri-specta) and checking that apps/desktop/src-tauri/src/lib.rs exports these commands and that general_settings.rs defines excluded_windows accordingly.
Also applies to: 371-373, 396-396, 486-486
crates/recording/src/instant_recording.rs (1)
224-226
: macOS exclusions plumbed end-to-end in Instant pathBuilder field, with_excluded_windows, RecordingBaseInputs, and create_screen_capture all align. Looks good.
Confirm that scap_targets::WindowId is available on all targets (or gate the import) and that create_screen_capture signature matches on each platform so CI builds for macOS and Windows both pass.
Also applies to: 235-237, 250-254, 268-271, 305-308
apps/desktop/src-tauri/src/windows.rs (2)
47-47
: Rename + content protection applied consistently across windowsRecordingControls variant, titles, traffic lights, and content_protected logic are coherent and consistent. Good cross-module alignment.
Also applies to: 63-65, 106-106, 127-127, 157-157, 255-267, 304-309, 319-319, 530-535, 552-552, 570-580, 627-640, 660-673
869-880
: Default/fallback semantics: verify excluded_windows defaultsshould_protect_window relies on settings.excluded_windows directly. Ensure GeneralSettingsStore.excluded_windows uses serde default = default_excluded_windows (not empty Vec) so first load or missing field preserves defaults; otherwise opening settings could unintentionally disable protection.
If not already, define excluded_windows as Vec with #[serde(default = "default_excluded_windows")] in general_settings.rs. Also verify DEFAULT_EXCLUDED_WINDOW_TITLES exactly match CapWindowId::title() strings to avoid drift.
use cap_media::MediaError; | ||
use feeds::microphone::MicrophoneFeedLock; | ||
use scap_targets::bounds::LogicalBounds; | ||
use scap_targets::{WindowId, bounds::LogicalBounds}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
macOS excluded_windows plumbed into base inputs
Importing WindowId and adding excluded_windows under macOS looks good.
Also applies to: 51-53
🏁 Script executed:
#!/bin/bash
# Verify excluded_windows is propagated through the pipeline.
echo "Sites instantiating RecordingBaseInputs:"
rg -nP -C3 'RecordingBaseInputs\s*\{'
echo
echo "Occurrences of excluded_windows across the repo:"
rg -nP -C2 '\bexcluded_windows\b'
Length of output: 13045
Propagate excluded_windows
when constructing RecordingBaseInputs
RecordingBaseInputs
(crates/recording/src/lib.rs:52) now includes a macOS-only excluded_windows
field but its struct literals in instant_recording and studio_recording omit it. In
- crates/recording/src/instant_recording.rs at the
RecordingBaseInputs { … }
(around line 262) - crates/recording/src/studio_recording.rs at the
RecordingBaseInputs { … }
(around line 398)
add:
#[cfg(target_os = "macos")]
excluded_windows: self.excluded_windows,
🤖 Prompt for AI Agents
In crates/recording/src/instant_recording.rs around line 262 and
crates/recording/src/studio_recording.rs around line 398, the
RecordingBaseInputs struct literals omit the new macOS-only excluded_windows
field; add the field guarded by cfg so it propagates the value from self:
#[cfg(target_os = "macos")] excluded_windows: self.excluded_windows, inserting
that line into each RecordingBaseInputs { … } initializer so the macOS-only
field is passed through.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/desktop/src-tauri/src/recording.rs (1)
479-543
: Fix non-mac build for excluded window support
with_excluded_windows
(and the corresponding field) only exists behind#[cfg(target_os = "macos")]
, but we’re calling it unconditionally in both the studio and instant builder chains. That will fail to compile on Windows/Linux. Wrap theresolve_window_ids
/with_excluded_windows
bits in macOS-onlycfg
blocks so the other targets keep building. For example:- let window_exclusions = general_settings - .as_ref() - .map_or_else(general_settings::default_excluded_windows, |settings| { - settings.excluded_windows.clone() - }); - let excluded_windows = - crate::window_exclusion::resolve_window_ids(&window_exclusions); + #[cfg(target_os = "macos")] + let window_exclusions = general_settings + .as_ref() + .map_or_else(general_settings::default_excluded_windows, |settings| { + settings.excluded_windows.clone() + }); + #[cfg(target_os = "macos")] + let excluded_windows = + crate::window_exclusion::resolve_window_ids(&window_exclusions); @@ - let mut builder = studio_recording::Actor::builder( + let mut builder = studio_recording::Actor::builder( recording_dir.clone(), inputs.capture_target.clone(), ) .with_system_audio(inputs.capture_system_audio) - .with_custom_cursor( + .with_custom_cursor( general_settings .map(|s| s.custom_cursor_capture) .unwrap_or_default(), - ) - .with_excluded_windows(excluded_windows.clone()); + ); + #[cfg(target_os = "macos")] + { + builder = + builder.with_excluded_windows(excluded_windows.clone()); + } @@ - let mut builder = instant_recording::Actor::builder( + let mut builder = instant_recording::Actor::builder( recording_dir.clone(), inputs.capture_target.clone(), - ) - .with_system_audio(inputs.capture_system_audio) - .with_excluded_windows(excluded_windows.clone()); + ) + .with_system_audio(inputs.capture_system_audio); + #[cfg(target_os = "macos")] + { + builder = + builder.with_excluded_windows(excluded_windows.clone()); + }crates/recording/src/studio_recording.rs (1)
695-710
: Don’t unwrap create_screen_capture; propagate error instead.unwrap() will panic on capture init failures. Return a proper error with context.
- let screen_config = create_screen_capture( + let screen_config = create_screen_capture( &base_inputs.capture_target, !custom_cursor_capture, 120, start_time.system_time(), base_inputs.capture_system_audio, #[cfg(windows)] d3d_device, #[cfg(target_os = "macos")] base_inputs.shareable_content, #[cfg(target_os = "macos")] base_inputs.excluded_windows, - ) - .await - .unwrap(); + ) + .await + .context("screen capture init")?;
♻️ Duplicate comments (1)
apps/desktop/src-tauri/src/general_settings.rs (1)
43-48
: Extend default exclusions to include all Cap overlays.Defaults omit overlays that were previously protected. Add these to avoid regressions on fresh installs.
const DEFAULT_EXCLUDED_WINDOW_TITLES: &[&str] = &[ "Cap", "Cap Settings", "Cap Recording Controls", "Cap Camera", + "Cap Window Capture Occluder", + "Cap Capture Area", + "Cap Recordings Overlay", ];References: apps/desktop/src-tauri/src/windows.rs titles.
🧹 Nitpick comments (6)
apps/desktop/src-tauri/src/windows.rs (1)
204-207
: Inconsistent enum variant naming.The
ShowCapWindow::InProgressRecording
variant retains the old name whileCapWindowId
uses the newRecordingControls
name. This naming inconsistency could cause confusion for maintainers.Consider renaming for consistency:
- InProgressRecording { + RecordingControls { countdown: Option<u32>, },And update the mapping at line 787:
- ShowCapWindow::InProgressRecording { .. } => CapWindowId::RecordingControls, + ShowCapWindow::RecordingControls { .. } => CapWindowId::RecordingControls,apps/desktop/src/routes/(window-chrome)/settings/general.tsx (2)
231-237
: Clarify the Cap window detection logic.The
isManagedWindowsApp
function checks if the bundle identifier contains "so.cap.desktop" or if the owner name includes "cap" (case-insensitive). This might produce false positives for windows from applications with "cap" in their name (e.g., "Capture Pro", "Capital One").Consider making the check more specific:
const isManagedWindowsApp = (window: CaptureWindow) => { const bundle = window.bundle_identifier?.toLowerCase() ?? ""; if (bundle.includes("so.cap.desktop")) { return true; } - return window.owner_name.toLowerCase().includes("cap"); + return window.owner_name.toLowerCase() === "cap"; };Or use a more explicit pattern like checking for "cap.so" or the full bundle identifier.
283-295
: Consider preserving bundle_identifier when available.Line 284 sets
windowTitle
tonull
whenbundle_identifier
exists, but this might lose useful information. If a window has both a bundle identifier and a title, both could be preserved for more precise matching.Consider preserving both fields:
const handleAddWindow = async (window: CaptureWindow) => { - const windowTitle = window.bundle_identifier ? null : window.name; const next = [ ...excludedWindows(), { bundleIdentifier: window.bundle_identifier ?? null, ownerName: window.owner_name ?? null, - windowTitle, + windowTitle: window.name ?? null, }, ]; await applyExcludedWindows(next); };This allows the backend's
WindowExclusion::matches
to use the most specific match available.crates/recording/src/instant_recording.rs (1)
12-12
: Gate WindowId import to macOS to avoid unused-import warnings.Import is only used behind cfg(target_os = "macos"). Gate it to satisfy clippy.
- use scap_targets::WindowId; + #[cfg(target_os = "macos")] + use scap_targets::WindowId;Also applies to: 224-226
crates/recording/src/studio_recording.rs (1)
17-17
: Gate WindowId import/usage to macOS to satisfy clippy on other targets.Avoid unused import warnings on non-mac builds.
- use scap_targets::WindowId; + #[cfg(target_os = "macos")] + use scap_targets::WindowId;Also applies to: 348-350
crates/recording/src/sources/screen_capture/mod.rs (1)
475-491
: Avoid duplicate owner_name lookup on macOS.Minor perf/readability: cache owner_name once for filter and struct fill.
- #[cfg(target_os = "macos")] - { - if v.raw_handle().level() != Some(0) - || v.owner_name().filter(|v| v == "Window Server").is_some() - { - return None; - } - } - - let owner_name = v.owner_name()?; + #[cfg(target_os = "macos")] + let owner_name = { + let name = v.owner_name()?; + if v.raw_handle().level() != Some(0) || name == "Window Server" { + return None; + } + name + }; + #[cfg(not(target_os = "macos"))] + let owner_name = v.owner_name()?;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
apps/desktop/src-tauri/src/general_settings.rs
(6 hunks)apps/desktop/src-tauri/src/lib.rs
(4 hunks)apps/desktop/src-tauri/src/recording.rs
(9 hunks)apps/desktop/src-tauri/src/window_exclusion.rs
(1 hunks)apps/desktop/src-tauri/src/windows.rs
(19 hunks)apps/desktop/src/routes/(window-chrome)/settings/general.tsx
(5 hunks)apps/desktop/src/routes/debug.tsx
(1 hunks)apps/desktop/src/utils/tauri.ts
(4 hunks)crates/recording/src/capture_pipeline.rs
(3 hunks)crates/recording/src/instant_recording.rs
(6 hunks)crates/recording/src/lib.rs
(2 hunks)crates/recording/src/sources/screen_capture/mod.rs
(6 hunks)crates/recording/src/studio_recording.rs
(6 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/desktop/src/routes/debug.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/desktop/src-tauri/src/window_exclusion.rs
- apps/desktop/src/utils/tauri.ts
- crates/recording/src/capture_pipeline.rs
🧰 Additional context used
📓 Path-based instructions (7)
crates/**/src/**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
For desktop IPC, use tauri_specta derive/macros on Rust types/events; do not hand-roll bindings
Files:
crates/recording/src/instant_recording.rs
crates/recording/src/lib.rs
crates/recording/src/studio_recording.rs
crates/recording/src/sources/screen_capture/mod.rs
**/*.{ts,tsx,js,jsx,rs}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not add inline, block, or docstring comments in any language; code must be self-explanatory
Files:
crates/recording/src/instant_recording.rs
apps/desktop/src-tauri/src/lib.rs
crates/recording/src/lib.rs
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
crates/recording/src/studio_recording.rs
crates/recording/src/sources/screen_capture/mod.rs
apps/desktop/src-tauri/src/general_settings.rs
apps/desktop/src-tauri/src/windows.rs
apps/desktop/src-tauri/src/recording.rs
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs
: Format Rust code usingrustfmt
and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.
Files:
crates/recording/src/instant_recording.rs
apps/desktop/src-tauri/src/lib.rs
crates/recording/src/lib.rs
crates/recording/src/studio_recording.rs
crates/recording/src/sources/screen_capture/mod.rs
apps/desktop/src-tauri/src/general_settings.rs
apps/desktop/src-tauri/src/windows.rs
apps/desktop/src-tauri/src/recording.rs
crates/*/src/**/*
📄 CodeRabbit inference engine (AGENTS.md)
Rust crates should place tests within the
src/
and/or a siblingtests/
directory for each crate insidecrates/*
.
Files:
crates/recording/src/instant_recording.rs
crates/recording/src/lib.rs
crates/recording/src/studio_recording.rs
crates/recording/src/sources/screen_capture/mod.rs
apps/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/desktop/**/*.{ts,tsx}
: Do not manually import icons in the desktop app; rely on auto-imported icons
In the desktop app, use @tanstack/solid-query for server state management
Files:
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use strict TypeScript and avoid any; leverage shared types from packages
**/*.{ts,tsx}
: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by runningpnpm format
.
Files:
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}
: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g.,user-menu.tsx
).
Use PascalCase for React/Solid components.
Files:
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
🧬 Code graph analysis (9)
crates/recording/src/instant_recording.rs (3)
crates/recording/src/studio_recording.rs (3)
new
(353-364)new
(591-608)with_excluded_windows
(387-390)apps/desktop/src/utils/tauri.ts (2)
ScreenCaptureTarget
(459-459)WindowId
(487-487)crates/scap-targets/src/platform/macos.rs (1)
Self
(286-295)
apps/desktop/src-tauri/src/lib.rs (4)
crates/scap-targets/src/platform/win.rs (2)
windows
(260-260)windows
(1150-1150)apps/desktop/src-tauri/src/windows.rs (1)
refresh_window_content_protection
(884-895)apps/desktop/src-tauri/src/general_settings.rs (1)
get_default_excluded_windows
(270-272)apps/desktop/src/utils/tauri.ts (2)
Flags
(394-394)WindowExclusion
(486-486)
crates/recording/src/lib.rs (3)
apps/desktop/src-tauri/src/target_select_overlay.rs (1)
scap_targets
(49-52)crates/scap-targets/src/main.rs (1)
scap_targets
(123-129)apps/desktop/src/utils/tauri.ts (2)
WindowId
(487-487)LogicalBounds
(415-415)
apps/desktop/src/routes/(window-chrome)/settings/general.tsx (2)
apps/desktop/src/utils/tauri.ts (5)
WindowExclusion
(486-486)CaptureWindow
(371-371)GeneralSettingsStore
(396-396)commands
(7-284)events
(289-333)apps/desktop/src/store.ts (1)
generalSettingsStore
(61-62)
crates/recording/src/studio_recording.rs (2)
apps/desktop/src/utils/tauri.ts (1)
WindowId
(487-487)crates/recording/src/instant_recording.rs (2)
new
(229-238)with_excluded_windows
(251-254)
crates/recording/src/sources/screen_capture/mod.rs (3)
apps/desktop/src/utils/tauri.ts (2)
WindowId
(487-487)CaptureWindow
(371-371)crates/scap-targets/src/lib.rs (3)
owner_name
(134-136)name
(40-42)name
(150-152)crates/scap-targets/src/platform/macos.rs (4)
owner_name
(320-332)bundle_identifier
(350-378)name
(128-147)name
(380-392)
apps/desktop/src-tauri/src/general_settings.rs (6)
apps/desktop/src/utils/tauri.ts (1)
WindowExclusion
(486-486)apps/desktop/src-tauri/src/windows.rs (1)
title
(121-134)crates/recording/src/sources/screen_capture/mod.rs (1)
title
(183-189)crates/scap-targets/src/platform/macos.rs (2)
bundle_identifier
(350-378)owner_name
(320-332)crates/scap-targets/src/lib.rs (1)
owner_name
(134-136)crates/scap-targets/src/platform/win.rs (1)
owner_name
(443-483)
apps/desktop/src-tauri/src/windows.rs (3)
apps/desktop/src/utils/tauri.ts (3)
AppTheme
(341-341)GeneralSettingsStore
(396-396)WindowExclusion
(486-486)apps/desktop/src-tauri/src/window_exclusion.rs (1)
matches
(18-63)apps/desktop/src-tauri/src/general_settings.rs (2)
get
(205-216)default_excluded_windows
(50-59)
apps/desktop/src-tauri/src/recording.rs (2)
apps/desktop/src-tauri/src/general_settings.rs (1)
default_excluded_windows
(50-59)apps/desktop/src-tauri/src/window_exclusion.rs (1)
resolve_window_ids
(66-95)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
- GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: Analyze (rust)
🔇 Additional comments (27)
apps/desktop/src-tauri/src/windows.rs (3)
882-895
: LGTM — Well-structured command for refreshing window protection.The command iterates over all webview windows, derives their IDs, and updates content protection based on current exclusions. The error handling and return type are appropriate.
255-266
: Validate content_protected on all platforms..content_protected(should_protect)
is applied unconditionally (in windows.rs and recording.rs); confirm Tauri supports it on Windows/Linux or add platform-specific guards or fallbacks.
869-880
: Title-only exclusion matching is correct here. CapWindowId only exposes window titles, so bundle_identifier and owner_name aren’t available in this context.Likely an incorrect or invalid review comment.
apps/desktop/src/routes/(window-chrome)/settings/general.tsx (7)
203-229
: Ensure frontend matching logic mirrors backend WindowExclusion::matches.The
matchesExclusion
function duplicates the matching logic from the Rust backend. Any divergence between these implementations could lead to inconsistent behavior where the UI shows different exclusions than what's actually applied.Compare this logic against
apps/desktop/src-tauri/src/window_exclusion.rs
lines 17-62 to confirm the matching rules are identical. Pay special attention to:
- Bundle identifier precedence
- Owner name + window title combination logic
- Fallback behavior when fields are null
Based on the relevant code snippet, the Rust implementation returns
true
immediately ifbundle_identifier
matches (lines 18-24 in window_exclusion.rs). The TypeScript version also does this (lines 207-210). However, verify that the combined owner + title logic (lines 216-218 TS vs lines 36-48 Rust) matches exactly.
179-188
: Good practice: delayed initial fetch to avoid blocking render.The 100ms delay before fetching windows prevents blocking the initial render, which improves perceived performance.
254-262
: Verify error handling doesn't silently mask failures.The
refreshAvailableWindows
function logs errors but returns the staleavailableWindows()
on failure. This could mask issues if window enumeration consistently fails.Consider whether the UI should display an error state when window refresh fails, rather than silently using stale data. This would help users understand if the exclusion system isn't working correctly.
738-789
: Verify menu scroll position restoration works reliably.Lines 777-785 save and restore the scroll position around the menu popup. This workaround suggests the menu popup might be causing unwanted scroll changes. Verify this is consistently effective across different scroll positions and window sizes.
Test the menu behavior:
- Scroll to various positions in the settings panel
- Open the "Add" menu
- Confirm the scroll position is restored after closing the menu
If the issue persists, consider filing a bug report with the Tauri menu API maintainers.
725-872
: LGTM — Well-structured exclusion management UI.The
ExcludedWindowsCard
component provides clear controls for adding, removing, and resetting exclusions. The loading states, empty states, and OS-specific messaging are all handled appropriately.
874-892
: Good accessibility: skeleton includes aria-hidden.The loading skeleton correctly uses
aria-hidden="true"
to prevent screen readers from announcing placeholder content.
264-275
: macOS prewarm event with force=true is required to reset ScreenCaptureKit cache so updated exclusions take effect immediately.apps/desktop/src-tauri/src/general_settings.rs (6)
50-59
: LGTM: default_excluded_windows helper.Clear, simple construction of defaults.
121-122
: LGTM: serde default for excluded_windows.Correctly seeds existing configs with defaults.
186-186
: LGTM: Default impl seeds excluded_windows.Consistent with serde default; good for new configs.
239-248
: Confirm matching semantics in WindowExclusion::matches.Ensure match is robust:
- Case-insensitive for owner/title?
- Trims/normalizes whitespace?
- Treats None and empty strings consistently.
If not, we may miss intended exclusions.
268-272
: LGTM: get_default_excluded_windows command.Properly exposed via specta for the frontend.
1-1
: LGTM: WindowExclusion import.crates/recording/src/instant_recording.rs (4)
235-237
: LGTM: initialize excluded_windows on macOS.
250-254
: LGTM: with_excluded_windows builder.
268-271
: LGTM: propagate excluded_windows into RecordingBaseInputs.
305-308
: LGTM: pass excluded_windows into create_screen_capture.Matches ScreenCaptureConfig::init signature (macOS-gated).
crates/recording/src/studio_recording.rs (2)
386-391
: LGTM: with_excluded_windows builder.
405-407
: LGTM: propagate excluded_windows into RecordingBaseInputs.crates/recording/src/sources/screen_capture/mod.rs (5)
35-36
: LGTM: CaptureWindow.bundle_identifier added.Matches frontend type (apps/desktop/src/utils/tauri.ts) and enables bundle-based exclusions.
201-204
: LGTM: ScreenCaptureConfig.excluded_windows (macOS).Properly stored on the config for downstream usage.
240-242
: LGTM: clone excluded_windows.
283-284
: LGTM: init signature extended with excluded_windows (macOS).
409-412
: LGTM: plumb excluded_windows through init.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/desktop/src-tauri/src/recording.rs (1)
492-506
: Immutable builder reassigned on non-macOS → compile error; avoid cfg shadowing and make builder mutable
let builder = ...
is immutable, yet later you reassignbuilder = ...
when adding feeds. On macOS you shadow it with a mutablelet mut
, but on non‑macOS that line is compiled out, leaving an immutablebuilder
and causing a compile error.Apply:
- let builder = studio_recording::Actor::builder( + let mut builder = studio_recording::Actor::builder( recording_dir.clone(), inputs.capture_target.clone(), ) .with_system_audio(inputs.capture_system_audio) .with_custom_cursor( general_settings .map(|s| s.custom_cursor_capture) .unwrap_or_default(), ); - #[cfg(target_os = "macos")] - let mut builder = builder.with_excluded_windows(excluded_windows.clone()); + #[cfg(target_os = "macos")] + { + builder = builder.with_excluded_windows(excluded_windows.clone()); + }This keeps a single mutable binding across platforms and avoids shadowing under cfg.
🧹 Nitpick comments (6)
crates/recording/src/instant_recording.rs (1)
12-12
: Gate WindowId import to macOS to avoid unused-import lint on other OSesPrevents clippy/rustc warnings when building for non-macOS.
As per coding guidelines
-use scap_targets::WindowId; +#[cfg(target_os = "macos")] +use scap_targets::WindowId;crates/recording/src/sources/screen_capture/mod.rs (3)
203-204
: Scope excluded_windows more narrowly (optional)Consider restricting to pub(crate) to avoid unnecessary public API surface unless external crates need this.
- pub excluded_windows: Vec<WindowId>, + pub(crate) excluded_windows: Vec<WindowId>,
283-285
: Accept a slice for excluded_windows for ergonomics and to match callersTaking
&[WindowId]
avoids forcing ownership at call sites and aligns with passing&inputs.excluded_windows
. Convert to Vec internally.- #[cfg(target_os = "macos")] excluded_windows: Vec<WindowId>, + #[cfg(target_os = "macos")] excluded_windows: &[WindowId],And when constructing Self:
- #[cfg(target_os = "macos")] - excluded_windows, + #[cfg(target_os = "macos")] + excluded_windows: excluded_windows.to_vec(),
475-491
: Minor: avoid duplicate owner_name retrievalYou call v.owner_name() in the macOS filter and again to bind owner_name. Retrieve once and reuse to cut duplicate work and syscalls.
apps/desktop/src-tauri/src/recording.rs (1)
546-548
: Avoid shadowingbuilder
under cfg in Instant pathShadowing
builder
again under macOS is unnecessary. Reassign instead to keep one binding (mirrors Studio fix).- #[cfg(target_os = "macos")] - let mut builder = builder.with_excluded_windows(excluded_windows.clone()); + #[cfg(target_os = "macos")] + { + builder = builder.with_excluded_windows(excluded_windows.clone()); + }apps/desktop/src/routes/(window-chrome)/settings/general.tsx (1)
37-38
: Do not manually import icons in desktop appPer guidelines, rely on auto-imported icons instead of manual imports.
Apply:
- import IconLucidePlus from "~icons/lucide/plus"; - import IconLucideX from "~icons/lucide/x";Keep usages (
<IconLucidePlus />
,<IconLucideX />
) as-is if your icon auto-import plugin is configured.
As per coding guidelines
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
apps/desktop/src-tauri/src/general_settings.rs
(6 hunks)apps/desktop/src-tauri/src/lib.rs
(4 hunks)apps/desktop/src-tauri/src/recording.rs
(9 hunks)apps/desktop/src-tauri/src/window_exclusion.rs
(1 hunks)apps/desktop/src-tauri/src/windows.rs
(19 hunks)apps/desktop/src/routes/(window-chrome)/settings/general.tsx
(5 hunks)apps/desktop/src/routes/debug.tsx
(1 hunks)apps/desktop/src/utils/tauri.ts
(4 hunks)crates/recording/src/capture_pipeline.rs
(3 hunks)crates/recording/src/instant_recording.rs
(6 hunks)crates/recording/src/lib.rs
(2 hunks)crates/recording/src/sources/screen_capture/mod.rs
(6 hunks)crates/recording/src/studio_recording.rs
(6 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/desktop/src/routes/debug.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- crates/recording/src/capture_pipeline.rs
- apps/desktop/src-tauri/src/general_settings.rs
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx,rs}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not add inline, block, or docstring comments in any language; code must be self-explanatory
Files:
apps/desktop/src-tauri/src/window_exclusion.rs
crates/recording/src/studio_recording.rs
apps/desktop/src/utils/tauri.ts
crates/recording/src/instant_recording.rs
apps/desktop/src-tauri/src/windows.rs
crates/recording/src/sources/screen_capture/mod.rs
apps/desktop/src-tauri/src/lib.rs
apps/desktop/src-tauri/src/recording.rs
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
crates/recording/src/lib.rs
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs
: Format Rust code usingrustfmt
and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.
Files:
apps/desktop/src-tauri/src/window_exclusion.rs
crates/recording/src/studio_recording.rs
crates/recording/src/instant_recording.rs
apps/desktop/src-tauri/src/windows.rs
crates/recording/src/sources/screen_capture/mod.rs
apps/desktop/src-tauri/src/lib.rs
apps/desktop/src-tauri/src/recording.rs
crates/recording/src/lib.rs
crates/**/src/**/*.rs
📄 CodeRabbit inference engine (CLAUDE.md)
For desktop IPC, use tauri_specta derive/macros on Rust types/events; do not hand-roll bindings
Files:
crates/recording/src/studio_recording.rs
crates/recording/src/instant_recording.rs
crates/recording/src/sources/screen_capture/mod.rs
crates/recording/src/lib.rs
crates/*/src/**/*
📄 CodeRabbit inference engine (AGENTS.md)
Rust crates should place tests within the
src/
and/or a siblingtests/
directory for each crate insidecrates/*
.
Files:
crates/recording/src/studio_recording.rs
crates/recording/src/instant_recording.rs
crates/recording/src/sources/screen_capture/mod.rs
crates/recording/src/lib.rs
**/tauri.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Never edit auto-generated IPC bindings file tauri.ts
Do not edit auto-generated files named
tauri.ts
.
Files:
apps/desktop/src/utils/tauri.ts
apps/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/desktop/**/*.{ts,tsx}
: Do not manually import icons in the desktop app; rely on auto-imported icons
In the desktop app, use @tanstack/solid-query for server state management
Files:
apps/desktop/src/utils/tauri.ts
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use strict TypeScript and avoid any; leverage shared types from packages
**/*.{ts,tsx}
: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by runningpnpm format
.
Files:
apps/desktop/src/utils/tauri.ts
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}
: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g.,user-menu.tsx
).
Use PascalCase for React/Solid components.
Files:
apps/desktop/src/utils/tauri.ts
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
🧬 Code graph analysis (9)
apps/desktop/src-tauri/src/window_exclusion.rs (2)
apps/desktop/src/utils/tauri.ts (2)
WindowId
(487-487)WindowExclusion
(486-486)crates/scap-targets/src/platform/macos.rs (4)
bundle_identifier
(350-378)owner_name
(320-332)list
(32-38)list
(237-269)
crates/recording/src/studio_recording.rs (2)
apps/desktop/src/utils/tauri.ts (1)
WindowId
(487-487)crates/recording/src/instant_recording.rs (2)
new
(229-238)with_excluded_windows
(251-254)
crates/recording/src/instant_recording.rs (3)
crates/recording/src/studio_recording.rs (3)
new
(353-364)new
(591-608)with_excluded_windows
(387-390)apps/desktop/src/utils/tauri.ts (2)
ScreenCaptureTarget
(459-459)WindowId
(487-487)crates/scap-targets/src/platform/macos.rs (1)
Self
(286-295)
apps/desktop/src-tauri/src/windows.rs (4)
apps/desktop/src/utils/tauri.ts (5)
AppTheme
(341-341)GeneralSettingsStore
(396-396)RecordingTargetMode
(449-449)WindowExclusion
(486-486)ShowCapWindow
(464-464)apps/desktop/src-tauri/src/target_select_overlay.rs (1)
display_id
(131-132)apps/desktop/src-tauri/src/window_exclusion.rs (1)
matches
(18-63)apps/desktop/src-tauri/src/general_settings.rs (2)
get
(205-216)default_excluded_windows
(50-59)
crates/recording/src/sources/screen_capture/mod.rs (2)
apps/desktop/src/utils/tauri.ts (2)
WindowId
(487-487)CaptureWindow
(371-371)crates/scap-targets/src/platform/macos.rs (4)
owner_name
(320-332)bundle_identifier
(350-378)name
(128-147)name
(380-392)
apps/desktop/src-tauri/src/lib.rs (3)
apps/desktop/src-tauri/src/windows.rs (1)
refresh_window_content_protection
(884-895)apps/desktop/src-tauri/src/general_settings.rs (1)
get_default_excluded_windows
(270-272)apps/desktop/src/utils/tauri.ts (1)
WindowExclusion
(486-486)
apps/desktop/src-tauri/src/recording.rs (2)
apps/desktop/src-tauri/src/general_settings.rs (1)
default_excluded_windows
(50-59)apps/desktop/src-tauri/src/window_exclusion.rs (1)
resolve_window_ids
(66-95)
apps/desktop/src/routes/(window-chrome)/settings/general.tsx (3)
apps/desktop/src/utils/tauri.ts (5)
WindowExclusion
(486-486)CaptureWindow
(371-371)GeneralSettingsStore
(396-396)commands
(7-284)events
(289-333)apps/desktop/src/store.ts (1)
generalSettingsStore
(61-62)packages/ui-solid/src/Button.tsx (1)
Button
(40-50)
crates/recording/src/lib.rs (1)
apps/desktop/src/utils/tauri.ts (2)
WindowId
(487-487)LogicalBounds
(415-415)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
- GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
- GitHub Check: Analyze (rust)
🔇 Additional comments (19)
crates/recording/src/instant_recording.rs (6)
4-4
: Import swap to MicrophoneFeedLock looks correctMatches usage in create_pipeline; no issues.
224-226
: ActorBuilder: macOS-only excluded_windows field is appropriateField scoping and visibility look right.
235-237
: Good: default excluded_windows to empty vec on macOSSane default; aligns with studio_recording builder.
250-254
: Builder method with_excluded_windows: API shape LGTMFluent builder style; no issues.
268-271
: Propagation into RecordingBaseInputs looks correctField wired through under macOS as expected.
306-308
: Remove suggestion to borrow excluded_windows; Vec is required
create_screen_capture’s signature (and ScreenCaptureConfig::init) takes excluded_windows: Vec by value, and build(self) owns the builder so moving the Vec is correct—using &inputs.excluded_windows would be a type mismatch.Likely an incorrect or invalid review comment.
crates/recording/src/sources/screen_capture/mod.rs (2)
35-35
: CaptureWindow: bundle_identifier field addition looks goodOptional on macOS, null elsewhere; aligns with TS type.
241-242
: Clone impl correctly includes excluded_windowsNo issues.
crates/recording/src/lib.rs (1)
51-53
: macOS exclusion plumbed correctly into inputsAdding
excluded_windows: Vec<WindowId>
under macOS inRecordingBaseInputs
looks correct and aligns with the capture pipeline changes.apps/desktop/src-tauri/src/recording.rs (2)
598-601
: Dialog parenting updated to RecordingControlsUsing
CapWindowId::RecordingControls
for dialog parent is correct after the rename.
827-829
: Close RecordingControls window on finishWindow closure updated to
RecordingControls
variant looks good.apps/desktop/src-tauri/src/lib.rs (1)
28-29
: Wiring: expose window_exclusion and commands via specta
- New
mod window_exclusion
and.typ::<crate::window_exclusion::WindowExclusion>()
are correctly added.- Commands
refresh_window_content_protection
andget_default_excluded_windows
are exported.Also applies to: 1922-1924, 2023-2025
apps/desktop/src/utils/tauri.ts (1)
47-52
: Auto-generated bindings OKNew commands and types (CaptureWindow with bundle_identifier, WindowExclusion, GeneralSettingsStore.excludedWindows) are present and consistent with Rust types.
Also applies to: 371-373, 396-396, 486-486
apps/desktop/src-tauri/src/windows.rs (1)
869-895
: Content protection refresh and matching logic look good
should_protect_window
andrefresh_window_content_protection
integrate settings with a sensible default fallback and update all windows’ protection flags. Title-based matching is appropriate for Cap windows.If users set only bundleIdentifier/ownerName exclusions, those won’t affect content protection (title-only match). Confirm this is intended; otherwise consider enriching the predicate.
apps/desktop/src-tauri/src/window_exclusion.rs (2)
6-63
: WindowExclusion model and matching logic are clear and robust
- Derives and camelCase serde align with TS.
matches
handles bundle, owner(+optional title), and title cases.
66-95
: Resolving window IDs from exclusions is correctEnumerating windows and filtering via
matches
is straightforward. macOS bundle identifier gating is handled.apps/desktop/src/routes/(window-chrome)/settings/general.tsx (2)
264-275
: Good: persist exclusions, refresh protection, and prewarm macOSPersisting
excludedWindows
, callingrefreshWindowContentProtection
, and emitting a prewarm on macOS is the right end-to-end flow.
203-229
: Local exclusion matcher mirrors backend logicFrontend
matchesExclusion
logic is consistent with RustWindowExclusion::matches
. This prevents drift in UI filtering.crates/recording/src/studio_recording.rs (1)
695-707
: No adjustment needed for excluded_windows argument
create_screen_capture
’s signature isexcluded_windows: Vec<WindowId>
, so passingbase_inputs.excluded_windows
by value is correct.Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
apps/desktop/src-tauri/src/window_exclusion.rs (2)
33-54
: Simplify the combined owner and title matching logic.The nested Option handling at lines 38-49 makes the logic harder to follow. Extracting the title matching into a separate binding would improve clarity.
Apply this diff to simplify the logic:
if let Some(expected_owner) = self.owner_name.as_deref() { let owner_matches = owner_name .map(|candidate| candidate == expected_owner) .unwrap_or(false); - if self.window_title.is_some() { - return owner_matches - && self - .window_title - .as_deref() - .map(|expected_title| { - window_title - .map(|candidate| candidate == expected_title) - .unwrap_or(false) - }) - .unwrap_or(false); + if let Some(expected_title) = self.window_title.as_deref() { + let title_matches = window_title + .map(|candidate| candidate == expected_title) + .unwrap_or(false); + return owner_matches && title_matches; } if owner_matches { return true; } }
77-81
: Consider consistent typing across platforms.The code works correctly, but using
Option<&str>
on non-macOS while macOS returnsOption<String>
creates a minor type inconsistency. While.as_deref()
at line 87 handles both cases, explicit type annotation would make the cross-platform handling clearer.Apply this diff for consistency:
#[cfg(target_os = "macos")] let bundle_identifier = window.raw_handle().bundle_identifier(); #[cfg(not(target_os = "macos"))] -let bundle_identifier = None::<&str>; +let bundle_identifier: Option<String> = None;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/desktop/src-tauri/src/general_settings.rs
(5 hunks)apps/desktop/src-tauri/src/window_exclusion.rs
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/desktop/src-tauri/src/general_settings.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx,rs}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not add inline, block, or docstring comments in any language; code must be self-explanatory
Files:
apps/desktop/src-tauri/src/window_exclusion.rs
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs
: Format Rust code usingrustfmt
and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.
Files:
apps/desktop/src-tauri/src/window_exclusion.rs
🧬 Code graph analysis (1)
apps/desktop/src-tauri/src/window_exclusion.rs (2)
apps/desktop/src/utils/tauri.ts (2)
WindowId
(487-487)WindowExclusion
(486-486)crates/scap-targets/src/platform/macos.rs (4)
bundle_identifier
(350-378)owner_name
(320-332)list
(32-38)list
(237-269)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
- GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
- GitHub Check: Analyze (rust)
🔇 Additional comments (1)
apps/desktop/src-tauri/src/window_exclusion.rs (1)
6-15
: LGTM!The struct definition is well-designed with appropriate derives and serialization attributes. The optional fields provide flexibility for different exclusion strategies.
This pull request introduces a new feature that allows users to configure which application windows should be excluded from screen recordings, by default and via user settings. It also ensures that certain Cap windows (like settings or overlays) are protected from being captured, based on these exclusions.
On macOS, users can exclude any window. However, on Windows, users can only exclude Windows owned by the app due to API limitations.
Demo:
https://internal.cap.so/s/17wy532211mjptb (the native screen recording freezes once I start the Cap recording - but GitHub was successfully excluded from capture)
Summary by CodeRabbit
New Features
UI
Terminology