Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
26d1cb8
feat(desktop-gpui): resize a picked window to a ratio or size, and fo…
richiemcilroy Oct 27, 2026
981d474
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
22eead8
refactor(desktop-gpui): drop the unused forget_arranged
richiemcilroy Oct 27, 2026
842bcde
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
8ebbe51
fix(desktop-gpui): share Focus across overlays and apply it to picks,…
richiemcilroy Oct 27, 2026
662b388
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
6e2ab57
fix(desktop-gpui): run window moves and restores in order, and pick t…
richiemcilroy Oct 27, 2026
6e3d8de
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
0fbf152
fix(desktop-gpui): say when Instant with a camera keeps the screen re…
richiemcilroy Oct 27, 2026
79492cf
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
cbeda16
fix(desktop-gpui): colour the window size chip's chevron
richiemcilroy Oct 27, 2026
70d4077
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
77c2f41
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
370929d
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
63d2dbb
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
db1e726
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
73e92c0
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
f220b1a
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
06ab8c4
Merge feat/recording-window-only into feat/gpui-window-arrange-focus
richiemcilroy Oct 27, 2026
d6c80f6
fix(desktop-gpui): wait for pending window moves before recording and…
richiemcilroy Oct 27, 2026
a8bcd6c
fix(desktop-gpui): tie a waiting Start to its picker, give up on wind…
richiemcilroy Oct 28, 2026
be4fe9d
fix(desktop-gpui): close the picker and show the main window when Sta…
richiemcilroy Oct 28, 2026
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
6 changes: 5 additions & 1 deletion .github/workflows/picker-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ on:
- "apps/desktop-gpui/src/camera_window.rs"
- "apps/desktop-gpui/src/picker_probe.rs"
- "apps/desktop-gpui/src/main_window.rs"
- "apps/desktop-gpui/src/foreign_window.rs"
- "apps/desktop-gpui/src/window_arrange.rs"
- "apps/desktop-gpui/src/platform.rs"
- "apps/desktop-gpui/src/platform/**"
- "scripts/picker-smoke/**"
Expand Down Expand Up @@ -136,7 +138,9 @@ jobs:
db="/Library/Application Support/com.apple.TCC/TCC.db"
now=$(date +%s)
for client in "$app" /bin/bash /Users/runner/bin/Runner.Worker /Users/runner/bin/Runner.Listener; do
sudo sqlite3 "$db" "INSERT OR REPLACE INTO access (service,client,client_type,auth_value,auth_reason,auth_version,indirect_object_identifier,flags,last_modified) VALUES ('kTCCServiceScreenCapture','$client',1,2,4,1,'UNUSED',0,$now);"
for service in kTCCServiceScreenCapture kTCCServiceAccessibility; do

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: macOS picker smoke grants Accessibility TCC to runner processes used by fork-PR code

New loop grants Accessibility TCC to /bin/bash and runner worker processes used by untrusted fork-PR builds.

Grant Accessibility only to the built app, or prevent fork PRs from running this self-hosted smoke with the grant.

AI prompt
Check if this security scanner issue is valid. If so, understand the root cause and fix it. If appropriate, update or add tests. Keep the change focused and preserve intended behavior.

<file name=".github/workflows/picker-smoke.yml">
<violation number="1" location=".github/workflows/picker-smoke.yml:141">
<priority>P2</priority>
<title>macOS picker smoke grants Accessibility TCC to runner processes used by fork-PR code</title>
<evidence>The permission step previously inserted only `kTCCServiceScreenCapture` for the built app, `/bin/bash`, `Runner.Worker`, and `Runner.Listener`. The changed loop now inserts both `kTCCServiceScreenCapture` and `kTCCServiceAccessibility` for the same clients. This workflow is triggered by `pull_request` and, for fork PRs that touch `apps/desktop-gpui/src/**`, runs the PR-built binary and PR-controlled `scripts/setup.js`/`scripts/picker-smoke/run.sh` on Blacksmith macOS runners. Granting Accessibility to `/bin/bash` and the runner worker processes means any later shell step can use macOS UI automation, read other applications' accessibility trees, and synthesize input without an additional prompt. That is broader than the pre-existing screen-capture grant.</evidence>
<recommendation>Do not grant `kTCCServiceAccessibility` to `/bin/bash`, `Runner.Worker`, or `Runner.Listener`. Grant it only to the specific built binary, ideally only after the build has been reviewed, or restrict this workflow to same-repository PRs/trusted branches. If the smoke must run on fork PRs, use an ephemeral runner account that has no access to other applications or credentials and explicitly reset the TCC grant after the job.</recommendation>
</violation>
</file>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This grant does not widen what PR code can do on that runner. The Blacksmith macOS runner is a single-use VM, and the same job already runs with passwordless sudo (this very step writes TCC.db with it), so code from a fork PR could grant itself any TCC service anyway. Accessibility is needed because the smoke moves another app's window through the AX API, and macOS checks that against the responsible process (the runner that launches cap-gpui), not the binary alone; granting it to the app only would make the window-arrangement check fail.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The developer’s explanation addresses the core concern: the Blacksmith runner is a single-use VM, so the TCC grant is not persistent, and the same job already runs with passwordless sudo—meaning untrusted code could already modify TCC.db directly. Additionally, the Accessibility grant to the runner processes is technically required because macOS applies the AX permission check to the responsible process launching the app, not the built binary alone, so restricting the grant to the app would break the smoke test. No additional exposure is introduced by this change.

sudo sqlite3 "$db" "INSERT OR REPLACE INTO access (service,client,client_type,auth_value,auth_reason,auth_version,indirect_object_identifier,flags,last_modified) VALUES ('$service','$client',1,2,4,1,'UNUSED',0,$now);"
done
done
sudo killall tccd || true
sleep 2
Expand Down
1 change: 1 addition & 0 deletions apps/desktop-gpui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ raw-window-handle = "0.6"
tray-icon = { version = "0.21.1", default-features = false }
windows-sys = { version = "0.59", features = [
"Win32_Foundation",
"Win32_Graphics_Dwm",
"Win32_Security",
"Win32_Storage_FileSystem",
"Win32_System_Console",
Expand Down
8 changes: 8 additions & 0 deletions apps/desktop-gpui/locales/de.toml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ label = "Studio Sound für neue Aufnahmen"
description = "Was mit dem Hauptfenster passiert, sobald eine Aufnahme beginnt."
label = "Hauptfenster beim Aufnahmestart"

[settings.general.recording.window_capture]
description = "Wie eine Fensteraufnahme das gewählte Fenster erfasst. „Fokussiertes Fenster“ nimmt nur dieses Fenster auf, zentriert und folgt ihm, wenn es verschoben wird; „Bildschirmbereich“ nimmt den Bereich des Bildschirms auf, den es abdeckt."
label = "Fensteraufnahme"

[settings.general.recording.post_deletion]
description = "Ob das Aufnahmefenster wieder geöffnet werden soll."
label = "Nach dem Löschen einer Aufnahme"
Expand Down Expand Up @@ -351,6 +355,10 @@ ultra = "Ultra"
close = "Schließen"
minimise = "Minimieren"

[settings.options.window_capture]
focused_window = "Fokussiertes Fenster"
screen_region = "Bildschirmbereich"

[settings.options.post_studio]
do_nothing = "Nichts tun"
open_editor = "Editor öffnen"
Expand Down
8 changes: 8 additions & 0 deletions apps/desktop-gpui/locales/en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ label = { text = "Studio Sound on new recordings", context = "Studio Sound is th
description = "What happens to the main window once a recording begins."
label = "Main window when recording starts"

[settings.general.recording.window_capture]
description = "How a window recording captures the window you pick. Focused window records only that window, centred and followed if it moves; Screen region records the area of the screen it covers."
label = "Window capture style"

[settings.general.recording.post_deletion]
description = "Whether the recording window should reopen."
label = "After deleting a recording"
Expand Down Expand Up @@ -353,6 +357,10 @@ ultra = "Ultra"
close = { text = "Close", max_px = 180, size = 12 }
minimise = { text = "Minimise", max_px = 180, size = 12 }

[settings.options.window_capture]
focused_window = { text = "Focused window", max_px = 180, size = 12 }
screen_region = { text = "Screen region", max_px = 180, size = 12 }

[settings.options.post_studio]
do_nothing = "Do nothing"
open_editor = "Open editor"
Expand Down
8 changes: 8 additions & 0 deletions apps/desktop-gpui/locales/es.toml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ label = "Studio Sound en las grabaciones nuevas"
description = "Qué ocurre con la ventana principal cuando empieza una grabación."
label = "Ventana principal al empezar a grabar"

[settings.general.recording.window_capture]
description = "Cómo captura una grabación de ventana la ventana que eliges. Ventana enfocada graba solo esa ventana, centrada y siguiéndola si se mueve; Región de pantalla graba el área de la pantalla que ocupa."
label = "Captura de ventanas"

[settings.general.recording.post_deletion]
description = "Si la ventana de grabación debe volver a abrirse."
label = "Después de eliminar una grabación"
Expand Down Expand Up @@ -351,6 +355,10 @@ ultra = "Ultra"
close = "Cerrar"
minimise = "Minimizar"

[settings.options.window_capture]
focused_window = "Ventana enfocada"
screen_region = "Región de pantalla"

[settings.options.post_studio]
do_nothing = "No hacer nada"
open_editor = "Abrir el editor"
Expand Down
8 changes: 8 additions & 0 deletions apps/desktop-gpui/locales/fr.toml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ label = "Studio Sound sur les nouveaux enregistrements"
description = "Ce que devient la fenêtre principale lorsqu'un enregistrement commence."
label = "Fenêtre principale au début de l'enregistrement"

[settings.general.recording.window_capture]
description = "La façon dont un enregistrement de fenêtre capture la fenêtre choisie. Fenêtre ciblée enregistre uniquement cette fenêtre, centrée et suivie si elle bouge ; Zone de l’écran enregistre la zone de l’écran qu’elle couvre."
label = "Capture de fenêtre"

[settings.general.recording.post_deletion]
description = "Indique si la fenêtre d'enregistrement doit se rouvrir."
label = "Après la suppression d'un enregistrement"
Expand Down Expand Up @@ -351,6 +355,10 @@ ultra = "Ultra"
close = "Fermer"
minimise = "Réduire"

[settings.options.window_capture]
focused_window = "Fenêtre ciblée"
screen_region = "Zone de l’écran"

[settings.options.post_studio]
do_nothing = "Ne rien faire"
open_editor = "Ouvrir l'éditeur"
Expand Down
8 changes: 8 additions & 0 deletions apps/desktop-gpui/locales/hi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ label = "नई रिकॉर्डिंग में Studio Sound"
description = "रिकॉर्डिंग शुरू होने पर मुख्य विंडो के साथ क्या होता है।"
label = "रिकॉर्डिंग शुरू होने पर मुख्य विंडो"

[settings.general.recording.window_capture]
description = "विंडो रिकॉर्डिंग आपकी चुनी हुई विंडो को कैसे कैप्चर करती है। फ़ोकस की गई विंडो केवल उसी विंडो को रिकॉर्ड करती है, बीच में रखकर और हिलने पर उसका पीछा करते हुए; स्क्रीन क्षेत्र स्क्रीन का वह हिस्सा रिकॉर्ड करता है जिसे वह ढकती है।"
label = "विंडो कैप्चर शैली"

[settings.general.recording.post_deletion]
description = "क्या रिकॉर्डिंग विंडो फिर से खुलनी चाहिए।"
label = "रिकॉर्डिंग हटाने के बाद"
Expand Down Expand Up @@ -351,6 +355,10 @@ ultra = "अल्ट्रा"
close = "बंद करें"
minimise = "छोटा करें"

[settings.options.window_capture]
focused_window = "फ़ोकस की गई विंडो"
screen_region = "स्क्रीन क्षेत्र"

[settings.options.post_studio]
do_nothing = "कुछ न करें"
open_editor = "एडिटर खोलें"
Expand Down
8 changes: 8 additions & 0 deletions apps/desktop-gpui/locales/ja.toml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ label = "新しい録画でStudio Soundを使用"
description = "録画が始まったときのメインウィンドウの動作。"
label = "録画開始時のメインウィンドウ"

[settings.general.recording.window_capture]
description = "ウインドウ録画で選んだウインドウをどのようにキャプチャするか。「フォーカスしたウインドウ」はそのウインドウだけを中央に配置し、移動しても追従して録画します。「画面の範囲」はウインドウが覆う画面の範囲を録画します。"
label = "ウインドウのキャプチャ方法"

[settings.general.recording.post_deletion]
description = "録画ウィンドウをもう一度開くかどうか。"
label = "録画を削除した後"
Expand Down Expand Up @@ -351,6 +355,10 @@ ultra = "最高"
close = "閉じる"
minimise = "最小化"

[settings.options.window_capture]
focused_window = "フォーカスしたウインドウ"
screen_region = "画面の範囲"

[settings.options.post_studio]
do_nothing = "何もしない"
open_editor = "エディタを開く"
Expand Down
8 changes: 8 additions & 0 deletions apps/desktop-gpui/locales/zh-CN.toml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ label = "新录制默认开启 Studio Sound"
description = "录制开始后主窗口的处理方式。"
label = "开始录制时的主窗口"

[settings.general.recording.window_capture]
description = "窗口录制如何捕获你选择的窗口。“聚焦窗口”只录制该窗口,将其居中并在移动时跟随;“屏幕区域”录制它所覆盖的屏幕区域。"
label = "窗口捕获方式"

[settings.general.recording.post_deletion]
description = "是否重新打开录制窗口。"
label = "删除录制后"
Expand Down Expand Up @@ -351,6 +355,10 @@ ultra = "超高"
close = "关闭"
minimise = "最小化"

[settings.options.window_capture]
focused_window = "聚焦窗口"
screen_region = "屏幕区域"

[settings.options.post_studio]
do_nothing = "不执行任何操作"
open_editor = "打开编辑器"
Expand Down
83 changes: 83 additions & 0 deletions apps/desktop-gpui/src/app_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,7 @@ pub(crate) fn show_main_window_after_capture_pause(cx: &mut App) {
windows.main_hidden_for_picker || !windows.overlays.is_empty()
};
if picker_open {
restore_arranged_windows(cx);
close_target_overlays(cx);
}
cx.global_mut::<AppWindows>().main_hidden_for_picker = false;
Expand Down Expand Up @@ -1097,6 +1098,7 @@ pub fn request_close_main(cx: &mut App) {
}

close_camera_window(cx);
restore_arranged_windows(cx);
close_target_overlays(cx);
// Closing the main window explicitly is not a picker dismissal; a stale
// flag here would reveal the window the user just closed.
Expand Down Expand Up @@ -2146,13 +2148,38 @@ fn open_overlays_core(request: OverlayRequest, cx: &mut App) -> bool {
true
}

/// Put back every window the picker moved or resized: the picker closed
/// without recording them.
fn restore_arranged_windows(cx: &mut App) {
let arranged = TargetSelect::global(cx).update(cx, |select, _| select.take_arranged());
crate::foreign_window::put_back_all(arranged, cx.background_executor());
}

/// A start the user turned back from (a storage or microphone prompt): the
/// windows the picker shaped go back. Never while a capture runs, which may be
/// recording them.
pub(crate) fn restore_arranged_windows_if_idle(cx: &mut App) {
if RecordingSession::global(cx).read(cx).phase == Phase::Idle {
restore_arranged_windows(cx);
}
}

/// A recording or screenshot is about to capture the windows the picker
/// shaped, so they stay where they are.
fn keep_arranged_windows(cx: &mut App) {
TargetSelect::global(cx).update(cx, |select, _| {
select.take_arranged();
});
}

/// Close the overlays and clear the main window's armed target -- Escape, the
/// overlay's own close button, or the main window toggling the mode off.
///
/// A "cancelled" dismissal in the Tauri vocabulary, which is the kind that
/// reveals the main window again (`dismissalReveals`,
/// `new-main/index.tsx:2047-2058`).
pub fn dismiss_target_overlays(cx: &mut App) {
restore_arranged_windows(cx);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reopening Cap bypasses restoration of arranged windows

Medium Severity

The unchanged show_main_window_after_capture_pause path calls close_target_overlays directly. After resizing or focusing a window, choosing Open Cap from the tray therefore closes the picker without calling this restore helper. The next TargetSelect::arm clears the saved originals, permanently leaving the other application's window rearranged despite no recording starting. Route non-recording picker exits through restoration, including the main-window reveal path.

Open in Capy

Comment on lines 2181 to +2182

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Some exits leave windows changed

Window restoration only runs through dismiss_target_overlays, but other user actions close the picker directly. Choosing Open Cap from the tray calls show_main_window, which closes the overlays without restoring moved windows. The next picker opening clears arranged, losing the original positions.

Restore moved windows on non-recording close paths too.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/app_windows.rs
Line: 2173-2174

Comment:
**Some exits leave windows changed**

Window restoration only runs through `dismiss_target_overlays`, but other user actions close the picker directly. Choosing Open Cap from the tray calls `show_main_window`, which closes the overlays without restoring moved windows. The next picker opening clears `arranged`, losing the original positions.

Restore moved windows on non-recording close paths too.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

if RecordingSession::global(cx).read(cx).phase == Phase::Idle
&& RecordingSession::global(cx)
.read(cx)
Expand Down Expand Up @@ -2388,6 +2415,14 @@ pub fn refresh_microphone_overlays(cx: &mut App) {
}

/// The overlays' native window numbers, for capture exclusion.
fn overlay_handles(cx: &App) -> Vec<gpui::AnyWindowHandle> {
cx.global::<AppWindows>()
.overlays
.iter()
.map(|(_, handle)| (*handle).into())
.collect()
}

fn overlay_window_ids(cx: &mut App) -> Vec<scap_targets::WindowId> {
let handles: Vec<_> = cx
.global::<AppWindows>()
Expand Down Expand Up @@ -2418,7 +2453,52 @@ pub fn show_instant_sign_in(kind: crate::main_window::TargetType, cx: &mut App)
show_main_window(cx);
}

/// How long Start waits for the picker's window moves to land. A move waits
/// on the target app; one still pending after this does not start a
/// recording of bounds that are about to change.
const ARRANGE_SETTLE_LIMIT: std::time::Duration = std::time::Duration::from_secs(5);

pub fn start_recording_from_overlay(target: ScreenCaptureTarget, cx: &mut App) {
if !TargetSelect::global(cx).read(cx).has_arranged() {
start_recording_from_overlay_now(target, cx);
return;
}
// A size the user just chose may still be on its way to the window, and
// the capture reads the window's bounds when it starts. The Start belongs
// to these overlays: dismissing them, or opening a new picker, drops it.
let overlays = overlay_handles(cx);
let settled = crate::foreign_window::in_order(|| ());
cx.spawn(async move |cx| {
let limit = cx.background_executor().timer(ARRANGE_SETTLE_LIMIT);
let settled = matches!(
futures_util::future::select(std::pin::pin!(settled), std::pin::pin!(limit)).await,
futures_util::future::Either::Left(_)
);
cx.update(|cx| {
let current = overlay_handles(cx);
if current.is_empty() || current != overlays {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferred Start records the click-time target after the pick changes

Medium Severity

The deferred Start captured target from the picker's selection at click time (target_overlay.rs start_recording), but the revalidation at app_windows.rs:2479 only compares overlay-window identity, and the new comment's claim that opening a new picker drops the Start does not hold for a same-mode re-open. While the settle wait runs (up to 5 s with the new limit), the picker stays interactive: a click on another window re-pins through the overlay's click-anywhere-to-select (pin_hovered), and a same-mode re-arm (tray item, hotkey) goes through open_overlays_core/reopens_overlays (app_windows.rs:1951), which keeps the identical overlay windows when the armed mode already matches, so current == overlays passes. The deferred task then calls start_recording_from_overlay_now with the stale target: it force-closes the picker that now presents window B and records window A; keep_arranged_windows at app_windows.rs:4015 then drains every arranged entry including B's saved original, so a B the user resized after the click is left moved with nothing to put it back. Bind the waiting Start to the picked target — compare the click-time target/pinned window against TargetSelect's current one and drop when it moved — not just to the overlay set.

Open in Capy

return;
}
if !settled {
tracing::warn!("a picked window is still moving; recording not started");
// The picker has nowhere to show the error: close it, which
// puts the windows back, and bring the main window forward.
dismiss_target_overlays(cx);
show_main_window(cx);
RecordingSession::global(cx).update(cx, |session, cx| {
session.error =
Some("The window is still being resized. Try starting again.".into());
cx.notify();
});
return;
Comment on lines +2482 to +2493

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Start hides its retry message

When a window move takes more than five seconds, Start stops and saves the retry message in session.error. The picker stays open, but only the hidden main window shows that error. The user sees neither a recording nor an explanation until they close the picker.

Show the error in the picker, or reveal the main window when Start times out.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/app_windows.rs
Line: 2482-2489

Comment:
**Start hides its retry message**

When a window move takes more than five seconds, Start stops and saves the retry message in `session.error`. The picker stays open, but only the hidden main window shows that error. The user sees neither a recording nor an explanation until they close the picker.

Show the error in the picker, or reveal the main window when Start times out.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

}
start_recording_from_overlay_now(target, cx);
});
})
.detach();
}

fn start_recording_from_overlay_now(target: ScreenCaptureTarget, cx: &mut App) {
let main = cx.global::<AppWindows>().main;
if RecordingSession::global(cx).read(cx).phase != Phase::Idle
|| main
Expand Down Expand Up @@ -3936,6 +4016,7 @@ fn begin_recording_after_preflight(config: StartConfig, cx: &mut App) {
if session.read(cx).phase != Phase::Idle {
return;
}
keep_arranged_windows(cx);

// `start_recording`'s first act (`src-tauri/src/recording.rs:1492-1494`):
// an armed editor recording target forces Studio, whatever mode the main
Expand Down Expand Up @@ -6658,6 +6739,7 @@ pub fn abort_editor_recording_flow(cx: &mut App) {
}) else {
return;
};
restore_arranged_windows(cx);
close_target_overlays(cx);
cx.global_mut::<AppWindows>().editor_hidden_for_picker = None;
cx.global_mut::<AppWindows>().main_hidden_for_picker = false;
Expand Down Expand Up @@ -6848,6 +6930,7 @@ pub fn prepare_for_screenshot_capture(cx: &mut App) -> bool {
// The screenshot branch of `onRecordingStart` nulls the saved camera bounds
// just like the recording branch does, so a parked bubble stays parked.
release_camera_park(cx);
keep_arranged_windows(cx);
close_target_overlays(cx);
true
}
Expand Down
Loading
Loading