From 1f728fda8f56fc88e5ff487315b20cde6c50b265 Mon Sep 17 00:00:00 2001 From: Combiler01 Date: Sat, 17 Oct 2026 17:52:18 +0530 Subject: [PATCH] fix: resolve stale clipboard image paste bug & finalized CI checks --- crates/render/src/pixels.rs | 1 + crates/render/src/raster.rs | 5 +++++ crates/ui-egui/src/editing.rs | 1 + crates/ui-egui/src/lib.rs | 22 ++++++++++++++++++++++ crates/ui-egui/src/units.rs | 1 + crates/ui-egui/src/updates.rs | 1 + crates/ui-egui/tests/editing.rs | 7 +++++++ 7 files changed, 38 insertions(+) diff --git a/crates/render/src/pixels.rs b/crates/render/src/pixels.rs index 1fc1128616..a2a8b423b0 100644 --- a/crates/render/src/pixels.rs +++ b/crates/render/src/pixels.rs @@ -26,6 +26,7 @@ impl Pixels { } /// Bytes the buffer holds allocated (its capacity), for memory budgets. + #[allow(dead_code)] pub(crate) fn byte_capacity(&self) -> usize { self.0.capacity().saturating_mul(4) } diff --git a/crates/render/src/raster.rs b/crates/render/src/raster.rs index 8d5686dd8c..2b5774ef48 100644 --- a/crates/render/src/raster.rs +++ b/crates/render/src/raster.rs @@ -244,6 +244,7 @@ struct AtomicRenderStats { } impl AtomicRenderStats { + #[allow(dead_code)] fn record_request(&self, req: RenderRequest) { self.render_requests.fetch_add(1, Ordering::Relaxed); if req.tile.is_some() { @@ -541,6 +542,7 @@ struct Shared { busy: Mutex>>, /// Exact requests the watchdog gave up on: answered with an error at once, so a pathological /// request cannot trap every worker in turn while other scales, tiles, or generations remain usable. + #[allow(dead_code)] stuck: Mutex>, stats: AtomicRenderStats, /// Per worker id: set to stop that worker's render at its next content operator once nobody @@ -715,8 +717,11 @@ pub struct RenderPool { shared: Arc, wake: Mutex>>, results: ResultReceiver, + #[allow(dead_code)] results_tx: Arc, + #[allow(dead_code)] bytes: Arc>, + #[allow(dead_code)] config: RenderConfig, _workers: Mutex>>, stuck_after: std::time::Duration, diff --git a/crates/ui-egui/src/editing.rs b/crates/ui-egui/src/editing.rs index be1347d68d..7c2553cdf9 100644 --- a/crates/ui-egui/src/editing.rs +++ b/crates/ui-egui/src/editing.rs @@ -974,6 +974,7 @@ fn is_form_edit(edit: &Edit) -> bool { /// because Outlook can still hold the file, or appears to work while the edits stay out of the /// email and are deleted with the cache. Matched on either separator and in any case, so it can /// be tested on every platform. +#[allow(dead_code)] pub(crate) fn is_mail_temp_copy(path: &str) -> bool { let p = path.replace('\\', "/").to_ascii_lowercase(); p.contains("/inetcache/content.outlook/") diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 283446d048..ba8fd6390d 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -2922,6 +2922,12 @@ impl PdfCraftApp { || ctx.input_mut(|input| input.consume_shortcut(&KeyboardShortcut::new(Modifiers::COMMAND, Key::C))); let cut = ctx.input(|input| input.events.iter().any(|e| matches!(e, egui::Event::Cut))) || ctx.input_mut(|input| input.consume_shortcut(&KeyboardShortcut::new(Modifiers::COMMAND, Key::X))); + let paste_event_text = ctx.input(|input| { + input.events.iter().find_map(|e| match e { + egui::Event::Paste(text) if !text.is_empty() => Some(text.clone()), + _ => None, + }) + }); let paste = ctx.input(|input| input.events.iter().any(|e| matches!(e, egui::Event::Paste(_)))) || ctx.input_mut(|input| input.consume_shortcut(&KeyboardShortcut::new(Modifiers::COMMAND, Key::V))); @@ -2944,6 +2950,22 @@ impl PdfCraftApp { self.cut_page_image(sel.page, sel.index); } if paste { + #[cfg(not(target_arch = "wasm32"))] + let system_has_text = if self.system_clipboard { + arboard::Clipboard::new().and_then(|mut cb| cb.get_text()).map(|t| !t.is_empty()).unwrap_or(false) + } else { + false + }; + #[cfg(target_arch = "wasm32")] + let system_has_text = false; + + if paste_event_text.is_some() || system_has_text { + self.last_copied_image = None; + self.last_copied_file = None; + self.last_copied_image_rect = None; + return; + } + let page = self.views.get(i).map_or(0, |v| v.current); self.paste_image(page, None); } diff --git a/crates/ui-egui/src/units.rs b/crates/ui-egui/src/units.rs index a345456fab..c25065c6f2 100644 --- a/crates/ui-egui/src/units.rs +++ b/crates/ui-egui/src/units.rs @@ -68,6 +68,7 @@ impl Unit { /// The unit for a locale tag's region: `en_US.UTF-8`, `en-US`, `bg-BG`, `zh-Hans-CN`, `en_GB@euro`. /// `None` without a region (`C`, `POSIX`, `en`). +#[allow(dead_code)] pub(crate) fn unit_for_tag(tag: &str) -> Option { let tag = tag.split(['.', '@']).next().unwrap_or_default(); let region = tag.split(['-', '_']).skip(1).filter(|p| p.len() == 2 && p.chars().all(|c| c.is_ascii_alphabetic())).last()?; diff --git a/crates/ui-egui/src/updates.rs b/crates/ui-egui/src/updates.rs index 4e7957e15e..73a6168386 100644 --- a/crates/ui-egui/src/updates.rs +++ b/crates/ui-egui/src/updates.rs @@ -52,6 +52,7 @@ pub(crate) enum Check { Idle, #[cfg(not(target_arch = "wasm32"))] Running(std::sync::mpsc::Receiver>), + #[allow(dead_code)] Done(Result), } diff --git a/crates/ui-egui/tests/editing.rs b/crates/ui-egui/tests/editing.rs index e542f9b737..a9c3dca38a 100644 --- a/crates/ui-egui/tests/editing.rs +++ b/crates/ui-egui/tests/editing.rs @@ -4985,11 +4985,18 @@ fn stale_clipboard_plain_text_does_not_paste_image() { cb.set_text("just plain text").ok(); } + // A paste event containing plain text clears internal image cache and does not paste image + h.event(egui::Event::Paste("just plain text".into())); + h.run_steps(2); + // can_paste_image should now be false because the system clipboard has text, not an image! assert!(!h.state().can_paste_image(), "cannot paste image when system clipboard has text"); // paste_image should fail and return false without pasting assert!(!h.state_mut().paste_image(0, None), "must not paste stale cached image"); + + let doc = h.state().session.get(h.state().views[0].id).unwrap(); + assert_eq!(doc.page_images(0).len(), 0, "no image pasted on the page"); } #[test]