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
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ homepage = "https://hack.ink/rsnap"
license = "GPL-3.0"
readme = "README.md"
repository = "https://github.com/hack-ink/rsnap"
version = "0.1.5"
version = "0.1.6"

[workspace.dependencies]
arboard = { version = "3.6" }
Expand Down Expand Up @@ -52,9 +52,9 @@ wgpu = { version = "29.0" }
winit = { version = "0.30", features = ["rwh_06"] }
xcap = { version = "0.9" }

rsnap-capture-core = { version = "0.1.5", path = "packages/rsnap-capture-core" }
rsnap-host-ffi = { version = "0.1.5", path = "packages/rsnap-host-ffi" }
rsnap-overlay = { version = "0.1.5", path = "packages/rsnap-overlay" }
rsnap-capture-core = { version = "0.1.6", path = "packages/rsnap-capture-core" }
rsnap-host-ffi = { version = "0.1.6", path = "packages/rsnap-host-ffi" }
rsnap-overlay = { version = "0.1.6", path = "packages/rsnap-overlay" }

[profile.final-release]
inherits = "release"
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Prototype / in active development.
- Menubar and Dock are not included in live window-outline targeting.
- Windows support is planned (minimum Windows 10), but not implemented yet.
- The scroll-capture engine, deterministic replay, and benchmark surfaces remain in the repository,
but the v0.1.5 native-host release does not expose scroll capture in the toolbar.
but the v0.1.6 native-host release does not expose scroll capture in the toolbar.

## Usage

Expand Down Expand Up @@ -123,7 +123,7 @@ Rsnap currently relies on **Screen Recording** permission to capture other apps/
- ScreenCaptureKit live sampling on macOS requires macOS 12.3+ and Screen Recording permission.
- Normal region/window/monitor capture does not require Accessibility or Input Monitoring.
- The retained scroll-capture path uses Screen Recording-backed screenshots plus forwarded wheel
input, but the v0.1.5 native-host release does not expose scroll capture in the toolbar.
input, but the v0.1.6 native-host release does not expose scroll capture in the toolbar.
- macOS may describe Screen Recording as `Screen & System Audio Recording` or as direct screen/audio access when Rsnap bypasses the system picker.
- Settings -> Permissions shows Screen Recording as the only required permission.
- Normal native capture depends on Screen Recording; if access is missing, Rsnap opens the Screen Recording page in System Settings and shows a floating drag-to-grant guide.
Expand Down Expand Up @@ -156,7 +156,7 @@ Rsnap currently relies on **Screen Recording** permission to capture other apps/

### Current scroll-capture status

Scroll capture is temporarily hidden in the v0.1.5 native-host release. The retained Rust
Scroll capture is temporarily hidden in the v0.1.6 native-host release. The retained Rust
scroll-capture session, deterministic replay, and benchmark surfaces remain for validation and
future re-enablement, but users should not expect a `Scroll Capture` toolbar item in this release.

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/smoke-perf-validation-surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Depends on: `docs/runbook/performance-validation.md`; `docs/spec/performance.md`
Covers: The current layer map for smoke/perf entrypoints, deterministic replay/bench surfaces,
overlay runtime integration tests, and scroll-capture session semantics tests.

Release exposure note: v0.1.5 hides user-facing scroll capture in the native host. The
Release exposure note: v0.1.6 hides user-facing scroll capture in the native host. The
scroll-capture entries in this reference describe retained internal validation assets, not a
visible toolbar feature in that release.

Expand Down
4 changes: 2 additions & 2 deletions docs/runbook/performance-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ Depends on: `docs/spec/performance.md`
Outputs: A clear command choice for the regression class you are testing, plus a repeatable local
baseline workflow for the committed Criterion benchmark targets.

Current release status: v0.1.5 hides user-facing scroll capture in the native host. The replay and
Current release status: v0.1.6 hides user-facing scroll capture in the native host. The replay and
benchmark commands in this runbook still own retained internal scroll-capture engine validation and
future re-enablement work, but they are not evidence that the v0.1.5 toolbar exposes scroll
future re-enablement work, but they are not evidence that the v0.1.6 toolbar exposes scroll
capture.

## Command selection
Expand Down
2 changes: 1 addition & 1 deletion docs/runbook/scroll-capture-benchmarks.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Depends on: `docs/spec/performance.md`
Outputs: A repeatable local benchmark run, an optional saved Criterion baseline, and a clear
understanding of what the synthetic fixture is intended to cover.

Current release status: v0.1.5 hides user-facing scroll capture in the native host. This runbook
Current release status: v0.1.6 hides user-facing scroll capture in the native host. This runbook
still applies to the retained internal scroll-capture engine, replay, and future re-enablement
work.

Expand Down
6 changes: 3 additions & 3 deletions docs/runbook/validate-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ manual first-run/user-flow validation.
- Sparkle update signing is configured: `SUPublicEDKey` is checked into
`scripts/build_and_run.sh`, and `SPARKLE_PRIVATE_ED_KEY` is available to the Release workflow
for signing the published update archive.
- Apple notary credentials are optional for v0.1.5; when absent, the Release workflow still
- Apple notary credentials are optional for v0.1.6; when absent, the Release workflow still
publishes a signed but unnotarized macOS zip.
3. Confirm local gates:
- `cargo make checks`
Expand Down Expand Up @@ -58,7 +58,7 @@ Validate these user-visible flows:
fullscreen fallback.
- Frozen toolbar tools: pointer, pen, arrow, text, mosaic, spotlight, undo, redo, auto-center,
Recognize Text, copy, and save.
- Scroll capture is hidden in the v0.1.5 native-host release: the toolbar must not show a scroll
- Scroll capture is hidden in the v0.1.6 native-host release: the toolbar must not show a scroll
capture item, and pressing `s` must not enter scroll capture.
- Light and dark appearance; Classic Glass and Liquid Glass where the OS and current build support
Liquid Glass.
Expand Down Expand Up @@ -96,7 +96,7 @@ user-entered annotation text.
4. Treat notarization failure as a release blocker only when notary credentials are configured.
5. The Release workflow publishes the signed macOS zip and `appcast.xml` to the GitHub release.
It notarizes and staples the app only when notary credentials are configured. It does not
publish crates.io packages or non-macOS desktop archives for v0.1.5.
publish crates.io packages or non-macOS desktop archives for v0.1.6.

## Published Artifact Check

Expand Down
2 changes: 1 addition & 1 deletion docs/spec/capture-session.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ product level rather than binding itself to a particular window toolkit or shell

## Scroll capture

- The v0.1.5 native-host release does not expose scroll capture. The frozen toolbar MUST NOT show a
- The v0.1.6 native-host release does not expose scroll capture. The frozen toolbar MUST NOT show a
scroll-capture item while the native-host scroll-capture gate is disabled, and plain `s` MUST NOT
enter scroll capture in that state.
- When scroll capture is re-enabled, it is available only from a dragged-region freeze on macOS.
Expand Down
125 changes: 85 additions & 40 deletions native/macos-host/Sources/RsnapNativeHostKit/NativeHostApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4782,7 +4782,7 @@ final class CaptureHostView: NSView {
clearLivePrimaryInteractionState(rendersImmediately: false)
resetLivePointerPreview()
liveHighlightedWindowPreview = nil
refreshHoveredToolbarAction()
clearHoveredToolbarAction()
syncVisibleCursor()
needsDisplay = true
controller?.updateLivePreviewDemand(
Expand Down Expand Up @@ -6144,9 +6144,13 @@ final class CaptureHostView: NSView {
return nil
}

let styleKind =
items.first(where: { $0.selected })
.flatMap { FrozenAnnotationStyleToolbarKind(selectedTool: $0.kind) }
var styleKind: FrozenAnnotationStyleToolbarKind?
for item in items where item.selected {
if let kind = FrozenAnnotationStyleToolbarKind(selectedTool: item.kind) {
styleKind = kind
break
}
}
let metrics = CaptureChrome.toolbarMetrics()
let itemCount = CGFloat(items.count)
let primaryContentWidth =
Expand Down Expand Up @@ -6201,14 +6205,17 @@ final class CaptureHostView: NSView {
cursorX += metrics.buttonSize + metrics.itemSpacing
}

let styleLayout = styleKind.map {
annotationStyleLayout(
for: $0,
let styleLayout: FrozenAnnotationStyleLayout?
if let styleKind {
styleLayout = annotationStyleLayout(
for: styleKind,
in: frame,
contentWidth: styleContentWidth,
metrics: metrics,
toolbarAboveSelection: toolbarAboveSelection
)
} else {
styleLayout = nil
}

return FrozenToolbarLayout(
Expand Down Expand Up @@ -6336,8 +6343,9 @@ final class CaptureHostView: NSView {
}

private func visibleToolbarItems() -> [ToolbarItem] {
scene.toolbarItems.compactMap { item in
var item = item
var items: [ToolbarItem] = []
for originalItem in scene.toolbarItems {
var item = originalItem
switch item.kind {
case .pen, .arrow, .mosaic, .spotlight, .text:
item.enabled = true
Expand All @@ -6351,44 +6359,27 @@ final class CaptureHostView: NSView {
&& !chrome.frozenOverlay.keepsFrozenSelectionFixed
case .scroll:
guard controller?.scrollCaptureToolbarEnabled == true else {
return nil
continue
}
item.enabled = controller?.scrollCaptureToolbarEnabled ?? false
default:
break
}
return item
items.append(item)
}
return items
}

private func toolbarItem(_ kind: ToolbarItemKind) -> ToolbarItem? {
scene.toolbarItems.first(where: { $0.kind == kind })
}

private func toolbarAction(at point: CGPoint) -> ToolbarItemKind? {
guard scene.mode == .frozen, let selection = localFrozenSelectionRect(),
let layout = toolbarLayout(for: selection)
else {
return nil
}
return layout.items.first(where: { $0.frame.contains(point) && $0.enabled })?.kind
frozenToolbarHitState(at: point).toolbarAction
}

private func annotationStyleAction(at point: CGPoint) -> FrozenAnnotationStyleAction? {
guard scene.mode == .frozen, let selection = localFrozenSelectionRect(),
let styleLayout = toolbarLayout(for: selection)?.annotationStyle
else {
return nil
}
if styleLayout.decreaseFrame.contains(point) {
return .decreaseSize
}
if styleLayout.increaseFrame.contains(point) {
return .increaseSize
}
return styleLayout.swatches.first(where: { $0.frame.contains(point) }).map {
.color($0.color)
}
frozenToolbarHitState(at: point).annotationStyleAction
}

private func annotationStyleSizeControlContains(_ point: CGPoint) -> Bool {
Expand All @@ -6401,12 +6392,7 @@ final class CaptureHostView: NSView {
}

private func toolbarFrameContains(_ point: CGPoint) -> Bool {
guard scene.mode == .frozen, let selection = localFrozenSelectionRect(),
let layout = toolbarLayout(for: selection)
else {
return false
}
return layout.frame.contains(point)
frozenToolbarHitState(at: point).pointerOverToolbar
}

private func performToolbarAction(_ action: ToolbarItemKind) {
Expand All @@ -6426,11 +6412,70 @@ final class CaptureHostView: NSView {
controller?.performFrozenAnnotationStyleAction(action)
}

private func frozenToolbarHitState(at point: CGPoint) -> (
pointerOverToolbar: Bool,
toolbarAction: ToolbarItemKind?,
annotationStyleAction: FrozenAnnotationStyleAction?
) {
guard scene.mode == .frozen, let selection = localFrozenSelectionRect(),
let layout = toolbarLayout(for: selection)
else {
return (false, nil, nil)
}

var hoveredAction: ToolbarItemKind?
for item in layout.items where item.enabled {
if item.frame.contains(point) {
hoveredAction = item.kind
break
}
}

var hoveredStyleAction: FrozenAnnotationStyleAction?
if let styleLayout = layout.annotationStyle {
if styleLayout.decreaseFrame.contains(point) {
hoveredStyleAction = .decreaseSize
} else if styleLayout.increaseFrame.contains(point) {
hoveredStyleAction = .increaseSize
} else {
for swatch in styleLayout.swatches where swatch.frame.contains(point) {
hoveredStyleAction = .color(swatch.color)
break
}
}
}

return (layout.frame.contains(point), hoveredAction, hoveredStyleAction)
}

private func clearHoveredToolbarAction() {
guard
pointerOverFrozenToolbar || hoveredToolbarAction != nil
|| hoveredAnnotationStyleAction != nil
else {
return
}
pointerOverFrozenToolbar = false
hoveredToolbarAction = nil
hoveredAnnotationStyleAction = nil
}

private func refreshHoveredToolbarAction(for localPoint: CGPoint? = nil) {
let probePoint = scene.mode == .frozen ? (localPoint ?? currentLocalMousePoint()) : nil
let pointerOverToolbar = probePoint.map(toolbarFrameContains) ?? false
let hoveredAction = probePoint.flatMap(toolbarAction(at:))
let hoveredStyleAction = probePoint.flatMap(annotationStyleAction(at:))
let hitState:
(
pointerOverToolbar: Bool,
toolbarAction: ToolbarItemKind?,
annotationStyleAction: FrozenAnnotationStyleAction?
)
if let probePoint {
hitState = frozenToolbarHitState(at: probePoint)
} else {
hitState = (false, nil, nil)
}
let pointerOverToolbar = hitState.pointerOverToolbar
let hoveredAction = hitState.toolbarAction
let hoveredStyleAction = hitState.annotationStyleAction
if hoveredToolbarAction != hoveredAction
|| hoveredAnnotationStyleAction != hoveredStyleAction
|| pointerOverFrozenToolbar != pointerOverToolbar
Expand Down
2 changes: 1 addition & 1 deletion scripts/build_and_run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ APP_VERSION="${RSNAP_NATIVE_HOST_APP_VERSION:-}"
if [[ -z "$APP_VERSION" ]]; then
APP_VERSION="$(sed -n '/^\[workspace.package\]/,/^\[/s/^version *= *"\(.*\)"/\1/p' "$ROOT_DIR/Cargo.toml" | head -n 1)"
fi
APP_VERSION="${APP_VERSION:-0.1.5}"
APP_VERSION="${APP_VERSION:-0.1.6}"

require_liquid_glass_capable_swift_for_release() {
[[ "$SWIFT_CONFIGURATION" == "release" ]] || return 0
Expand Down
Loading