Skip to content

Conversation

@richiemcilroy
Copy link
Member

@richiemcilroy richiemcilroy commented Dec 7, 2025

Improvements to window management on macOS, refines user interface text, and adjusts navigation logic in the desktop app. The most significant changes are the addition of a helper for making windows visible on all workspaces, consistent application of this behaviour across window types, and minor UI and logic tweaks

Summary by CodeRabbit

  • New Features

    • macOS windows now remain visible across all workspaces during recording and capture operations.
  • Bug Fixes

    • Refined navigation logic to prevent unintended route switching when toggling recording modes.
    • Disabled right-click context menu during active recording sessions.
  • UI/UX

    • Updated Settings panel text and reorganized Cap Pro-specific options.
    • Adjusted Settings window size for improved layout.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 7, 2025

Walkthrough

This PR adds macOS window management functionality to keep windows visible across all workspaces via a new set_window_visible_on_all_workspaces function. The function is integrated into multiple window lifecycle events in the window manager. Additionally, navigation logic in main routes is refined with path guards to prevent unintended route transitions, settings UI is reorganized, a window size constraint is adjusted, and context menu prevention is added to the in-progress recording view.

Changes

Cohort / File(s) Summary
macOS window visibility
apps/desktop/src-tauri/src/platform/macos/mod.rs
Added set_window_visible_on_all_workspaces function to modify NSWindow collectionBehavior by OR-ing CanJoinAllSpaces, FullScreenAuxiliary, and Stationary flags.
Window manager integration
apps/desktop/src-tauri/src/windows.rs
Integrated set_window_visible_on_all_workspaces calls across multiple macOS window types (Main, TargetSelectOverlay, WindowCaptureOccluder, CaptureArea, Camera, InProgressRecording); adjusted Settings window min_size from 450.0 to 470.0 height.
Frontend navigation guards
apps/desktop/src/routes/(window-chrome)/(main).tsx, apps/desktop/src/routes/(window-chrome)/new-main/index.tsx
Added path-based guards to window focus listeners to prevent unintended navigation between routes when enableNewRecordingFlow state changes.
Settings UI updates
apps/desktop/src/routes/(window-chrome)/settings/general.tsx
Updated AppearanceSection heading and description text; relocated "Automatically open shareable links" toggle to a new Cap Pro Specific group.
Context menu prevention
apps/desktop/src/routes/in-progress-recording.tsx
Added onContextMenu handler to suppress default right-click context menu on the root container.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Specific areas requiring attention:
    • Window-level assignments and set_window_visible_on_all_workspaces calls in windows.rs across different window types to ensure correct ordering and consistent application
    • Navigation guard logic changes in both main and new-main routes to verify path checks prevent edge cases
    • Settings UI relocation to confirm the toggle functionality and grouping are preserved correctly

Possibly related PRs

Suggested labels

codex

Suggested reviewers

  • Brendonovich

Poem

🐰 Windows hop through all workspaces with glee,
Navigation guards keep routes running free,
Settings reorganized, menus suppressed just right,
Another hop forward, the app shines bright! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title uses vague terminology ('misc UX stuff') that obscures the main changes. While it mentions 'fix for macOS virtual screens,' the majority of changes involve window management refactoring, navigation logic adjustments, and UI text updates, making the title insufficiently specific and descriptive. Consider a more descriptive title like 'feat: Improve macOS window visibility across workspaces and refine navigation logic' to better reflect the substantive changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch misc-bits

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cea939a and 6e0fbb8.

📒 Files selected for processing (6)
  • apps/desktop/src-tauri/src/platform/macos/mod.rs (1 hunks)
  • apps/desktop/src-tauri/src/windows.rs (8 hunks)
  • apps/desktop/src/routes/(window-chrome)/(main).tsx (1 hunks)
  • apps/desktop/src/routes/(window-chrome)/new-main/index.tsx (1 hunks)
  • apps/desktop/src/routes/(window-chrome)/settings/general.tsx (2 hunks)
  • apps/desktop/src/routes/in-progress-recording.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Never use dbg!() macro; use proper logging (tracing::debug!, etc.) instead
Never write let _ = async_fn() which silently drops futures; await or explicitly handle them
Use duration.saturating_sub(other) instead of duration - other to avoid panics on underflow
Merge nested if statements: write 'if a && b { }' instead of 'if a { if b { } }'
Don't call .clone() on Copy types (integers, bools, etc.); copy them directly
Use function references directly: iter.map(foo) instead of iter.map(|x| foo(x))
Accept &[T] or &str instead of &Vec or &String in function parameters for flexibility
Use .is_empty() instead of .len() == 0 or .len() > 0 / .len() != 0
Don't assign () to a variable: write foo(); instead of let _ = foo(); or let x = foo(); when return is unit
Use .unwrap_or(val) instead of .unwrap_or_else(|| val) when the default is a simple/cheap value
Use 'for item in &collection' or 'for (i, item) in collection.iter().enumerate()' instead of 'for i in 0..collection.len()'
Use value.clamp(min, max) instead of manual if chains or .min(max).max(min) patterns
Always handle Result/Option or types marked #[must_use]; never ignore them

**/*.rs: Use rustfmt and workspace clippy lints for Rust code formatting and linting
Use snake_case for Rust module names and kebab-case for crate names
Never use dbg!() macro in Rust code; use proper logging instead (Clippy: dbg_macro = deny)
Always handle Result/Option or types marked #[must_use]; never ignore them (Rust compiler lint: unused_must_use = deny)
Never write let _ = async_fn() which silently drops futures; await or explicitly handle them (Clippy: let_underscore_future = deny)
Use saturating_sub instead of - for Duration to avoid panics (Clippy: unchecked_duration_subtraction = deny)
Merge nested if statements: use if a && b { } instead of if a { if b { } } (Clippy: collapsible_if = deny)
Don't call .clone() on Copy types; just copy them directly (Clippy: clone_on_copy = deny)
U...

Files:

  • apps/desktop/src-tauri/src/platform/macos/mod.rs
  • apps/desktop/src-tauri/src/windows.rs
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (AGENTS.md)

Never add comments to code (//, /* */, ///, //!, #, etc.); code must be self-explanatory through naming, types, and structure

Files:

  • apps/desktop/src-tauri/src/platform/macos/mod.rs
  • apps/desktop/src/routes/(window-chrome)/(main).tsx
  • apps/desktop/src/routes/in-progress-recording.tsx
  • apps/desktop/src/routes/(window-chrome)/new-main/index.tsx
  • apps/desktop/src/routes/(window-chrome)/settings/general.tsx
  • apps/desktop/src-tauri/src/windows.rs
**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Use React Query hooks with Server Actions for mutations and perform precise cache updates using setQueryData/setQueriesData instead of broad invalidations

Files:

  • apps/desktop/src/routes/(window-chrome)/(main).tsx
  • apps/desktop/src/routes/in-progress-recording.tsx
  • apps/desktop/src/routes/(window-chrome)/new-main/index.tsx
  • apps/desktop/src/routes/(window-chrome)/settings/general.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: Use strict TypeScript; avoid any type; leverage shared types from @cap/* packages
Follow camelCase naming for variables and functions; PascalCase for components; hooks must start with 'use' prefix
Use Biome for linting and formatting; match existing formatting conventions in the codebase
Use Tailwind CSS for styling in web components; stay consistent with spacing and tokens
Use static skeletons for loading states that mirror content; avoid bouncing animations
Memoize expensive work, code-split naturally, and use Next/Image for remote assets

**/*.{ts,tsx,js,jsx}: Use 2-space indent for TypeScript files; format with Biome using pnpm format
Use Biome for code formatting and linting; run pnpm format regularly
Use kebab-case for file names (e.g., user-menu.tsx); use PascalCase for components

Files:

  • apps/desktop/src/routes/(window-chrome)/(main).tsx
  • apps/desktop/src/routes/in-progress-recording.tsx
  • apps/desktop/src/routes/(window-chrome)/new-main/index.tsx
  • apps/desktop/src/routes/(window-chrome)/settings/general.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Never add any form of comments to code (single-line //, multi-line /* /, JSDoc /* */, or any other comment syntax); code must be self-explanatory through naming, types, and structure
Directory naming must use lowercase-dashed convention

Files:

  • apps/desktop/src/routes/(window-chrome)/(main).tsx
  • apps/desktop/src/routes/in-progress-recording.tsx
  • apps/desktop/src/routes/(window-chrome)/new-main/index.tsx
  • apps/desktop/src/routes/(window-chrome)/settings/general.tsx
🧬 Code graph analysis (1)
apps/desktop/src-tauri/src/windows.rs (1)
apps/desktop/src-tauri/src/platform/macos/mod.rs (2)
  • set_window_level (18-27)
  • set_window_visible_on_all_workspaces (29-46)
⏰ 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: Clippy (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Clippy (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (13)
apps/desktop/src/routes/(window-chrome)/(main).tsx (1)

64-69: Good path guard to prevent unintended navigation.

The added pathname check ensures navigation to /new-main only occurs when on the root path, preventing focus-triggered redirects when the user is already viewing other routes.

apps/desktop/src/routes/(window-chrome)/new-main/index.tsx (1)

346-351: Symmetric path guard with (main).tsx.

This properly mirrors the navigation guard in (main).tsx, ensuring navigation from /new-main to / only occurs when actually on the new-main route and the feature flag is disabled.

apps/desktop/src/routes/in-progress-recording.tsx (1)

530-533: Appropriate context menu suppression for recording controls.

Disabling the browser's default right-click menu on the recording controls overlay is sensible UX, preventing accidental browser actions during recording.

apps/desktop/src/routes/(window-chrome)/settings/general.tsx (2)

156-159: Clear and descriptive section heading.

The updated heading and description better communicate the section's purpose.


565-575: Good reorganization of Cap Pro settings.

Moving the auto-open shareable links toggle to a dedicated "Cap Pro Specific" group improves settings organization and makes it clear this is a Pro feature.

apps/desktop/src-tauri/src/platform/macos/mod.rs (1)

29-46: Well-structured function following existing patterns.

The implementation correctly mirrors set_window_level's approach and applies appropriate NSWindowCollectionBehavior flags for cross-workspace visibility. The combination of CanJoinAllSpaces, FullScreenAuxiliary, and Stationary ensures windows remain visible across all macOS spaces including fullscreen contexts.

apps/desktop/src-tauri/src/windows.rs (7)

188-188: Minor min_size adjustment for Settings window.

The height increase from 450.0 to 470.0 accommodates the UI changes in the settings page.


320-325: Consistent visibility handling for main window.

Calling set_window_visible_on_all_workspaces after setting the window level ensures the main window (new recording flow) remains visible across all macOS spaces/virtual desktops.


419-421: TargetSelectOverlay visibility across workspaces.

Good addition to ensure target selection overlays follow the user across spaces.


593-597: Camera window visibility across workspaces.

Ensures the camera preview window remains visible when switching spaces during recording.


640-643: WindowCaptureOccluder visibility across workspaces.

Consistent with other overlay windows.


658-658: CaptureArea visibility handling.

The builder's .visible_on_all_workspaces(true) sets initial Tauri-level visibility, while set_window_visible_on_all_workspaces adds the additional macOS-specific collection behaviors (CanJoinAllSpaces, FullScreenAuxiliary, Stationary) for robust cross-space visibility.

Also applies to: 686-692


737-739: InProgressRecording visibility across workspaces.

Critical for recording controls to remain accessible when the user switches spaces during an active recording.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants