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
9 changes: 8 additions & 1 deletion apps/desktop/src-tauri/src/general_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,14 @@ pub fn default_studio_recording_quality() -> StudioRecordingQuality {
impl MainWindowRecordingStartBehaviour {
pub fn perform(&self, window: &tauri::WebviewWindow) -> tauri::Result<()> {
match self {
Self::Close => window.hide(),
Self::Close => {
// On Windows, hide() leaves the DirectComposition surface composited on screen as
// a white ghost box. minimize() releases the surface without leaving an artifact.
#[cfg(windows)]
return window.minimize();
#[cfg(not(windows))]
window.hide()
Comment on lines +91 to +94

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Small thing: you can avoid the early return here so this match arm stays expression-based (makes it harder to accidentally skip future logic added after the match).

Suggested change
#[cfg(windows)]
return window.minimize();
#[cfg(not(windows))]
window.hide()
#[cfg(windows)]
window.minimize()
#[cfg(not(windows))]
window.hide()

}
Self::Minimise => window.minimize(),
}
}
Expand Down
8 changes: 6 additions & 2 deletions apps/desktop/src-tauri/src/recording.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3011,11 +3011,15 @@ async fn handle_recording_end(
let _ = window.hide();
}

// Destroy any target-select overlays that were hidden when recording started
// so they don't reappear when the main window comes back.
// Destroy any target-select overlays so they don't reappear when the main window comes back.
// On Windows, hide() leaves the DirectComposition transparency surface composited on screen
// (ghost overlay); closing the window releases the surface entirely.
let focus_manager = handle.try_state::<crate::target_select_overlay::WindowFocusManager>();
for (label, window) in handle.webview_windows() {
if let Ok(CapWindowId::TargetSelectOverlay { display_id }) = CapWindowId::from_str(&label) {
#[cfg(windows)]
let _ = window.close();
#[cfg(not(windows))]
hide_overlay(&window);
if let Some(ref fm) = focus_manager {
fm.destroy(&display_id, handle.global_shortcut());
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop/src-tauri/src/target_select_overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ pub fn close_target_select_overlay_windows(app: &AppHandle) {
for (id, window) in app.webview_windows() {
if let Ok(CapWindowId::TargetSelectOverlay { display_id }) = CapWindowId::from_str(&id) {
saw_overlay = true;
// On Windows, hide() leaves the DirectComposition transparency surface composited on
// screen (ghost overlay). Closing the window fully releases the surface.
#[cfg(windows)]
let _ = window.close();
Comment on lines +330 to +331

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Since this is a Windows-only compositor issue, it might be worth logging close() failures so we have signal if this ever regresses (same pattern appears in handle_recording_end).

Suggested change
#[cfg(windows)]
let _ = window.close();
#[cfg(windows)]
if let Err(err) = window.close() {
debug!(?err, "Failed to close target-select overlay window");
}

#[cfg(not(windows))]
hide_overlay(&window);
if let Some(state) = state.as_ref() {
state.destroy(&display_id, app.global_shortcut());
Expand Down
Loading