Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions docs/spec/capture-session.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ cross-platform architecture.
- On macOS, Frozen mode may recognize text from the current frozen capture and copy the recognized text to the clipboard.
- Cmd+S (macOS) / Ctrl+S saves the frozen PNG to disk.
- `Esc` cancels capture.
- In Frozen mode, a loupe and toolbar are part of the floating HUD set and can still
interact with pointer movement and redraw.
- In Frozen mode, the toolbar remains part of the floating HUD set. The live loupe is
hidden after freeze and may be recreated only when a later live-mode transition needs it.
- In Frozen mode, a dragged-region capture may be repositioned by dragging inside the
bright selected area; width and height remain fixed and the moved rect stays on the
current monitor.
Expand All @@ -51,6 +51,10 @@ cross-platform architecture.
3. When the capture session overlay is visible, underlying desktop content MUST NOT be
interactive.
4. The overlay background should be transparent and non-dimming by default.
4a. On macOS, rsnap overlay, HUD, loupe, frozen toolbar, and scroll preview windows MUST remain
externally capturable by system screenshot and screen-recording tools. Internal self-capture
correctness comes from rsnap's own exclusion filters and freeze handoff logic, not window
content protection.
5. In live mode, the overlay MUST show a HUD near the cursor with:
- global cursor coordinates `x,y`
- pixel color `rgb(r,g,b)` under the cursor
Expand All @@ -62,6 +66,9 @@ cross-platform architecture.
- `Space` -> copy the frozen cropped PNG (region/window/fullscreen) to the system clipboard, then exit
- On macOS, the frozen toolbar may expose `Recognize Text`, which runs Apple Vision OCR on the current frozen capture, copies the recognized text to the clipboard, and exits
- Cmd+S (macOS) / Ctrl+S -> save the frozen cropped PNG to disk, then exit
- On macOS, freeze may complete directly from a fresh live-stream snapshot only when the
live stream has complete self-capture exclusions. Otherwise live snapshots are preview-only
until authoritative capture completes
- In Frozen mode, toolbar-driven annotations are part of the frozen capture state. Current
annotation/edit tools are pointer, pen, arrow, text, mosaic, and spotlight; the pen-tool
contract lives in `docs/spec/annotation-pen.md`
Expand Down Expand Up @@ -198,9 +205,10 @@ Research and cross-platform notes live in:

## HUD/toolbar lifecycle

- All floating HUD windows are created at overlay start.
- In Frozen mode, loupe/toolbar visibility follows Tab + current mode state and
`show_frozen_capture` state.
- Overlay windows and the main HUD are created at overlay start.
- The loupe, frozen toolbar, and scroll preview windows may be created lazily when the
active mode first needs them.
- In Frozen mode, toolbar visibility follows current mode state and `show_frozen_capture`.

## Current non-goals

Expand Down
2 changes: 2 additions & 0 deletions packages/rsnap-overlay/src/overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ type ScrollCaptureStartedHook = Arc<dyn Fn() + Send + Sync>;

type Result<T, E = Report> = std::result::Result<T, E>;

pub(crate) const CAPTURE_WINDOW_CONTENT_PROTECTION_ENABLED: bool = false;

#[cfg(target_os = "macos")]
const KCG_HID_EVENT_TAP: u32 = 0;
#[cfg(target_os = "macos")]
Expand Down
2 changes: 2 additions & 0 deletions packages/rsnap-overlay/src/overlay/rendering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use self::hud_rendering::LiveLoupeTexture;
use self::hud_surface::{HudBg, HudBlurUniformRaw};
#[cfg(target_os = "macos")]
use crate::overlay::MacOSOverlayCursorRectSupport;
#[cfg(target_os = "macos")]
use crate::overlay::macos_configure_hud_window;
use crate::overlay::{
self, AcquiredSurfaceFrame, Adapter, AddressMode, Arc, BindGroupLayout, BindingResource,
BindingType, BlendState, Buffer, BufferBindingType, BufferSize, BufferUsages, ClippedPrimitive,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use wgpu::SurfaceConfiguration;

#[cfg(target_os = "macos")]
use crate::overlay;
use crate::overlay::rendering::{GpuContext, ScrollPreviewView, WindowRenderer};
use crate::overlay::{
AcquiredSurfaceFrame, ActiveEventLoop, Align, Arc, CentralPanel, Color32, ColorImage,
Expand Down Expand Up @@ -33,7 +31,7 @@ impl ScrollPreviewWindow {
.with_visible(false)
.with_resizable(false)
.with_decorations(false)
.with_content_protected(cfg!(target_os = "macos"))
.with_content_protected(super::overlay::CAPTURE_WINDOW_CONTENT_PROTECTION_ENABLED)
.with_transparent(true)
.with_inner_size(LogicalSize::new(
SCROLL_PREVIEW_WINDOW_WIDTH_POINTS,
Expand Down Expand Up @@ -84,7 +82,7 @@ impl ScrollPreviewWindow {
let _ = window.set_cursor_hittest(false);

#[cfg(target_os = "macos")]
overlay::macos_configure_hud_window(window.as_ref(), false, 0.0, Some(18.0));
super::macos_configure_hud_window(window.as_ref(), false, 0.0, Some(18.0));

Ok(Self {
window,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,13 @@ fn authoritative_freeze_capture_hides_overlay_windows_on_macos() {
assert!(session.should_hide_overlay_windows_during_capture());
}

#[cfg(target_os = "macos")]
#[test]
#[allow(clippy::assertions_on_constants)]
fn capture_windows_are_not_content_protected_on_macos() {
assert!(!super::super::CAPTURE_WINDOW_CONTENT_PROTECTION_ENABLED);
}

#[cfg(target_os = "macos")]
#[test]
fn repeated_freeze_capture_send_full_aborts_and_restores_hidden_windows() {
Expand Down
8 changes: 4 additions & 4 deletions packages/rsnap-overlay/src/overlay/window_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ impl OverlaySession {
.with_title("rsnap-overlay")
.with_decorations(false)
.with_resizable(false)
.with_content_protected(cfg!(target_os = "macos"))
.with_content_protected(overlay::CAPTURE_WINDOW_CONTENT_PROTECTION_ENABLED)
.with_transparent(true)
.with_window_level(WindowLevel::AlwaysOnTop)
.with_inner_size(LogicalSize::new(
Expand Down Expand Up @@ -769,7 +769,7 @@ impl OverlaySession {
.with_title("rsnap-hud")
.with_decorations(false)
.with_resizable(false)
.with_content_protected(cfg!(target_os = "macos"))
.with_content_protected(overlay::CAPTURE_WINDOW_CONTENT_PROTECTION_ENABLED)
.with_transparent(true)
.with_visible(false)
.with_window_level(WindowLevel::AlwaysOnTop)
Expand Down Expand Up @@ -803,7 +803,7 @@ impl OverlaySession {
.with_title("rsnap-loupe")
.with_decorations(false)
.with_resizable(false)
.with_content_protected(cfg!(target_os = "macos"))
.with_content_protected(overlay::CAPTURE_WINDOW_CONTENT_PROTECTION_ENABLED)
.with_transparent(true)
.with_visible(false)
.with_window_level(WindowLevel::AlwaysOnTop)
Expand Down Expand Up @@ -840,7 +840,7 @@ impl OverlaySession {
.with_title("rsnap-toolbar")
.with_decorations(false)
.with_resizable(false)
.with_content_protected(cfg!(target_os = "macos"))
.with_content_protected(overlay::CAPTURE_WINDOW_CONTENT_PROTECTION_ENABLED)
.with_inner_size(LogicalSize::new(
startup_size.x as f64,
f64::from(startup_size.y.max(TOOLBAR_EXPANDED_HEIGHT_PX)),
Expand Down
Loading