Save: don't wait forever for the thumbnail frame or screenshot

A save from the active drawing first redraws the viewport without its
overlays and screenshots it for the file's preview. When the compositor
delivered no frame or never answered the screenshot (an occluded or
throttled Wayland window), the save never started: the input layer stayed
hidden, so the window ignored the mouse and keyboard, and automation
requests waited on the save forever. A timer now stands in for the frame,
and the screenshot races a half-second timeout; whichever answers first
runs the save, without the refreshed preview if it has to.

Closes #1801

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 5.5 committed 2026-10-16 23:25:59 +03:00
1 parent 854641bb55
commit f07d6e19fc
2 files changed
+40 -9

No files matched your search

+33 -8
View File
@@ -3578,14 +3578,39 @@ impl OpenCADStudio {
)
};
match capture_window {
Some(window) => iced::window::screenshot(window)
.map(Some)
.then(move |screenshot| {
Task::batch([
Task::done(Message::ThumbnailCaptureFinished),
run_save(screenshot),
])
}),
// The screenshot may never come back (a window the compositor
// does not draw), so it races a short timeout: whichever answers
// first runs the save, with or without the picture.
Some(window) => {
fn finish<F>(
slot: &std::sync::Mutex<Option<F>>,
screenshot: Option<iced::window::Screenshot>,
) -> Task<Message>
where
F: FnMut(Option<iced::window::Screenshot>) -> Task<Message>,
{
match slot.lock().ok().and_then(|mut run| run.take()) {
Some(mut run_save) => Task::batch([
Task::done(Message::ThumbnailCaptureFinished),
run_save(screenshot),
]),
None => Task::none(),
}
}
let slot = std::sync::Arc::new(std::sync::Mutex::new(Some(run_save)));
let (shot_slot, timeout_slot) = (slot.clone(), slot);
let (tx, rx) = iced::futures::channel::oneshot::channel::<()>();
std::thread::spawn(move || {
std::thread::sleep(std::time::Duration::from_millis(500));
let _ = tx.send(());
});
Task::batch([
iced::window::screenshot(window)
.map(Some)
.then(move |screenshot| finish(&shot_slot, screenshot)),
Task::perform(rx, |_| ()).then(move |_| finish(&timeout_slot, None)),
])
}
None => {
self.thumbnail_capture_clean = false;
run_save(None)
+7 -1
View File
@@ -2861,8 +2861,14 @@ impl OpenCADStudio {
} else {
Subscription::none()
};
// A compositor that delivers no frame (an occluded or throttled
// window) must not hold the save: a timer goes ahead without it.
let thumbnail_capture = if self.thumbnail_capture_clean {
window::frames().map(|_| Message::ThumbnailCaptureFrame)
Subscription::batch([
window::frames().map(|_| Message::ThumbnailCaptureFrame),
iced::time::every(std::time::Duration::from_millis(300))
.map(|_| Message::ThumbnailCaptureFrame),
])
} else {
Subscription::none()
};