From 38e5c4bb5b1e93a82e1de16a4dafb723781031ec Mon Sep 17 00:00:00 2001 From: manchitmr <74224148+manchitmr@users.noreply.github.com> Date: Thu, 15 Oct 2026 13:59:35 +0530 Subject: [PATCH 1/3] Bring the window forward when the running app is handed files Opening a PDF from Finder (or Open With, or a Dock drop) while PdfCraft was already running added the tab but left the window where it was: behind Finder, minimized, or full screen on another Space, so nothing seemed to happen. The same applies to files handed over by another launch on Windows and Linux, which arrive through the same OsEvent::Open path. After opening the files, un-minimize the window and focus it, which on macOS activates the app and orders the window front (switching to its full-screen Space). Co-Authored-By: Claude Opus 5.5 (1M context) --- crates/ui-egui/src/lib.rs | 8 +++++++- crates/ui-egui/tests/ui.rs | 9 +++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 7b421263d..bdc3444c3 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -3047,7 +3047,13 @@ impl eframe::App for PdfCraftApp { for e in os_events { match e { #[cfg(not(target_arch = "wasm32"))] - OsEvent::Open(paths) => paths.iter().for_each(|p| self.open_path(p)), + OsEvent::Open(paths) => { + paths.iter().for_each(|p| self.open_path(p)); + // Files handed to the running app (Finder, or another launch): bring its + // window to the front, also when minimized or full screen on another Space. + ctx.send_viewport_cmd(egui::ViewportCommand::Minimized(false)); + ctx.send_viewport_cmd(egui::ViewportCommand::Focus); + } #[cfg(target_arch = "wasm32")] OsEvent::Open(_) => {} // Like closing the window: `guard_quit` asks about unsaved changes. diff --git a/crates/ui-egui/tests/ui.rs b/crates/ui-egui/tests/ui.rs index b86f7699f..eacc46015 100644 --- a/crates/ui-egui/tests/ui.rs +++ b/crates/ui-egui/tests/ui.rs @@ -878,6 +878,15 @@ fn files_and_quit_from_the_operating_system() { std::fs::remove_file(&path).ok(); assert_eq!(h.state().views.len(), 1, "the file opens in a tab"); h.get_by_label_contains(&name); + // A file opened while the app runs brings its window forward, even minimized or full screen + // on another Space. + std::fs::write(&path, FIXTURE).unwrap(); + queue.borrow_mut().push(OsEvent::Open(vec![path.to_string_lossy().into_owned()])); + h.step(); + std::fs::remove_file(&path).ok(); + let commands: Vec<_> = h.output().viewport_output.values().flat_map(|v| v.commands.clone()).collect(); + assert!(commands.contains(&egui::ViewportCommand::Minimized(false)), "{commands:?}"); + assert!(commands.contains(&egui::ViewportCommand::Focus), "{commands:?}"); // Quit closes the window like the close button, so unsaved changes are asked about. queue.borrow_mut().push(OsEvent::Quit); h.step(); From 4242e7ed50deda581a78504e994c504f958ba696 Mon Sep 17 00:00:00 2001 From: Chaturanga Manchanayake Date: Mon, 19 Oct 2026 11:39:30 +0530 Subject: [PATCH 2/3] Test bringing the window forward for a new file while it is still preparing Review follow-up: the earlier assertion reopened the same path, which takes the existing-tab shortcut. This one hands the running app a new file with preparation held, checks Minimized(false) and Focus are sent before release, and checks the new file is the selected tab once it is prepared. Co-Authored-By: Claude Opus 5.5 (1M context) --- crates/ui-egui/src/open_worker_tests.rs | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/crates/ui-egui/src/open_worker_tests.rs b/crates/ui-egui/src/open_worker_tests.rs index ebdd45054..4fb705c6d 100644 --- a/crates/ui-egui/src/open_worker_tests.rs +++ b/crates/ui-egui/src/open_worker_tests.rs @@ -670,3 +670,33 @@ fn startup_files_wait_for_absolute_link_consent_and_preparation() { assert_eq!(app.active, Some(1), "the user's approved navigation keeps focus"); let _ = std::fs::remove_file(path); } + +#[test] +#[allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)] +fn a_new_file_from_the_os_brings_the_window_forward_before_it_is_prepared() { + let (mut harness, _client) = harness(); + let (gate, started, release, finished) = open_worker::prepare_gate(); + harness.state_mut().open_prepare_gate = Some(gate); + let path = std::env::temp_dir().join(format!("pdfcraft-os-open-worker-{}.pdf", std::process::id())); + std::fs::write(&path, fixture(2)).expect("write the handed-over PDF"); + let mut queue = vec![crate::OsEvent::Open(vec![path.to_string_lossy().into_owned()])]; + harness.state_mut().os_events = Some(Box::new(move || std::mem::take(&mut queue))); + harness.step(); + started.recv_timeout(Duration::from_secs(5)).expect("the handed-over PDF reached preparation"); + let commands: Vec<_> = harness.output().viewport_output.values().flat_map(|v| v.commands.clone()).collect(); + let visible = harness.state().views.len(); + // Always release before asserting: a failure must not strand the worker at the barrier. + release.send(()).expect("release the handed-over PDF"); + finished.recv_timeout(Duration::from_secs(5)).expect("the handed-over PDF prepared"); + assert!(commands.contains(&egui::ViewportCommand::Minimized(false)), "{commands:?}"); + assert!(commands.contains(&egui::ViewportCommand::Focus), "{commands:?}"); + assert_eq!(visible, 1, "the window comes forward while the file is still preparing"); + harness.step(); + let app = harness.state(); + assert_eq!(app.views.len(), 2); + let active = app.active.expect("a selected document"); + let doc = app.session.get(app.views[active].id).expect("the handed-over document"); + assert_eq!(doc.path.as_deref(), Some(path.to_string_lossy().as_ref()), "the new file is the selected tab"); + assert_eq!(doc.info.pages.len(), 2); + let _ = std::fs::remove_file(path); +} From 5397a4af8b58bc6639cb10da6f6df47fe0b55c44 Mon Sep 17 00:00:00 2001 From: Chaturanga Manchanayake Date: Mon, 19 Oct 2026 12:27:59 +0530 Subject: [PATCH 3/3] Document the new-file OS open test Co-Authored-By: Claude Opus 5.5 (1M context) --- crates/ui-egui/src/open_worker_tests.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/ui-egui/src/open_worker_tests.rs b/crates/ui-egui/src/open_worker_tests.rs index 4fb705c6d..af847b9a2 100644 --- a/crates/ui-egui/src/open_worker_tests.rs +++ b/crates/ui-egui/src/open_worker_tests.rs @@ -671,6 +671,8 @@ fn startup_files_wait_for_absolute_link_consent_and_preparation() { let _ = std::fs::remove_file(path); } +/// #1928: a new file handed over by the OS (Finder, or another launch) raises the window at once, +/// before it is prepared, and is the selected tab once it opens. #[test] #[allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)] fn a_new_file_from_the_os_brings_the_window_forward_before_it_is_prepared() {