diff --git a/packages/rsnap-overlay/src/overlay.rs b/packages/rsnap-overlay/src/overlay.rs index c15e0ba1..1741433f 100644 --- a/packages/rsnap-overlay/src/overlay.rs +++ b/packages/rsnap-overlay/src/overlay.rs @@ -1474,12 +1474,6 @@ impl OverlaySession { && self.inflight_freeze_capture.is_none() } - fn should_force_pending_hud_and_loupe_moves(&self) -> bool { - matches!(self.state.mode, OverlayMode::Frozen) - && self.state.monitor.is_some() - && !self.frozen_final_capture_ready() - } - #[cfg(target_os = "macos")] fn try_latest_live_freeze_preview(&mut self, monitor: MonitorRect) -> Option { if self.state.live_bg_monitor == Some(monitor) @@ -1505,7 +1499,6 @@ impl OverlaySession { if let Some(cursor) = cursor { self.update_cursor_state(monitor, cursor); - self.update_hud_window_position(monitor, cursor); } } @@ -1566,26 +1559,11 @@ impl OverlaySession { } } - fn refresh_frozen_helper_windows_for_transition( - &mut self, - monitor: MonitorRect, - cursor: Option, - ) { - if let Some(cursor) = cursor { - self.update_hud_window_position(monitor, cursor); - } - - if self.should_force_pending_hud_and_loupe_moves() { - self.force_apply_pending_hud_and_loupe_moves(); - } - + fn refresh_frozen_helper_windows_for_transition(&mut self, monitor: MonitorRect) { + self.force_apply_pending_toolbar_window_move(); self.schedule_egui_repaint_after(self.repaint_interval_for_monitor(Some(monitor))); self.request_redraw_for_monitor(monitor); - self.request_redraw_hud_window(); - - if self.state.alt_held || self.loupe_window_visible { - self.request_redraw_loupe_window(); - } + self.request_redraw_toolbar_window(); } fn begin_frozen_capture_with_rect( @@ -1604,12 +1582,13 @@ impl OverlaySession { }; let capture_rect = rect.unwrap_or(RectPoints::new(0, 0, monitor.width, monitor.height)); - let frozen_rgb = self.state.rgb; - let frozen_loupe = self.state.loupe.as_ref().map(|loupe| crate::state::LoupeSample { - center: loupe.center, - patch: loupe.patch.clone(), - }); + self.state.alt_held = false; + self.loupe_activation_key_down = false; + self.state.rgb = None; + self.state.loupe = None; + + self.set_alt_loupe_window_visible(None, false); self.state.clear_error(); self.state.begin_freeze(monitor); @@ -1650,8 +1629,6 @@ impl OverlaySession { self.seed_frozen_toolbar_default_position(monitor, capture_rect); self.request_redraw_toolbar_window(); - self.state.rgb = frozen_rgb; - self.state.loupe = frozen_loupe; self.pending_freeze_capture = Some(monitor); self.pending_freeze_capture_armed = false; self.inflight_freeze_capture = None; @@ -1665,7 +1642,7 @@ impl OverlaySession { self.left_mouse_button_down_monitor = None; self.left_mouse_button_down_global = None; - self.refresh_frozen_helper_windows_for_transition(monitor, cursor); + self.refresh_frozen_helper_windows_for_transition(monitor); #[cfg(target_os = "macos")] { @@ -1674,7 +1651,7 @@ impl OverlaySession { self.state.live_bg_image = None; self.commit_frozen_preview(monitor, image, cursor); - self.force_apply_pending_hud_and_loupe_moves(); + self.force_apply_pending_toolbar_window_move(); } else { self.state.live_bg_monitor = None; self.state.live_bg_image = None; @@ -1698,12 +1675,9 @@ impl OverlaySession { if let Some(cursor) = cursor { self.update_cursor_state(monitor, cursor); - self.update_hud_window_position(monitor, cursor); } - if self.should_force_pending_hud_and_loupe_moves() { - self.force_apply_pending_hud_and_loupe_moves(); - } + self.force_apply_pending_toolbar_window_move(); } else { self.state.live_bg_monitor = None; self.state.live_bg_image = None; @@ -1715,6 +1689,8 @@ impl OverlaySession { } fn update_live_drag_rect(&mut self, monitor: MonitorRect, global: GlobalPoint) { + let was_active = self.live_drag_hides_auxiliary_windows(); + if !matches!(self.state.mode, OverlayMode::Live) { self.state.drag_rect = None; @@ -1744,6 +1720,10 @@ impl OverlaySession { } self.state.drag_rect = Some(MonitorRectPoints { monitor_id: monitor.id, rect }); + + if !was_active { + self.hide_auxiliary_windows_for_live_drag(); + } } fn frozen_capture_rect_drag_target(&self) -> Option<(MonitorRect, RectPoints)> { @@ -2168,6 +2148,10 @@ impl OverlaySession { matches!(self.state.mode, OverlayMode::Frozen) && self.frozen_selection_drag.active } + pub(super) fn live_drag_hides_auxiliary_windows(&self) -> bool { + matches!(self.state.mode, OverlayMode::Live) && self.state.drag_rect.is_some() + } + fn hide_auxiliary_windows_for_frozen_selection_drag(&mut self) { if let Some(hud_window) = self.hud_window.as_ref() { hud_window.window.set_visible(false); @@ -2198,6 +2182,24 @@ impl OverlaySession { self.last_present_at = Instant::now(); } + fn hide_auxiliary_windows_for_live_drag(&mut self) { + if let Some(hud_window) = self.hud_window.as_ref() { + hud_window.window.set_visible(false); + } + + self.hud_window_visible = false; + + if let Some(loupe_window) = self.loupe_window.as_ref() { + loupe_window.window.set_visible(false); + } + + self.loupe_window_visible = false; + + self.reset_loupe_window_warmup_redraws(); + + self.last_present_at = Instant::now(); + } + fn stop_frozen_selection_drag(&mut self) { let was_active = self.frozen_selection_drag.active; @@ -3934,33 +3936,12 @@ impl OverlaySession { }) } - fn refresh_frozen_cursor_samples(&mut self, monitor: MonitorRect) { - if let Some(cursor) = self.state.cursor { - self.state.rgb = - image_helpers::frozen_rgb(&self.state.frozen_image, Some(monitor), cursor); - self.state.loupe = image_helpers::frozen_loupe_patch( - &self.state.frozen_image, - Some(monitor), - cursor, - self.loupe_patch_width_px, - self.loupe_patch_height_px, - ) - .map(|patch| crate::state::LoupeSample { center: cursor, patch }); - } - } - fn note_frozen_image_mutated(&mut self, monitor: MonitorRect) { self.state.frozen_generation = self.state.frozen_generation.wrapping_add(1); - self.refresh_frozen_cursor_samples(monitor); self.sync_frozen_toolbar_state(); self.request_redraw_for_monitor(monitor); - self.request_redraw_hud_window(); self.request_redraw_toolbar_window(); - - if self.state.alt_held || self.loupe_window_visible { - self.request_redraw_loupe_window(); - } } fn push_frozen_mosaic_edit(&mut self, edit: FrozenMosaicEdit) { @@ -4251,25 +4232,7 @@ impl OverlaySession { } if let Some(cursor) = self.state.cursor { - self.state.rgb = - image_helpers::frozen_rgb(&self.state.frozen_image, Some(monitor), cursor); - self.state.loupe = image_helpers::frozen_loupe_patch( - &self.state.frozen_image, - Some(monitor), - cursor, - self.loupe_patch_width_px, - self.loupe_patch_height_px, - ) - .map(|patch| crate::state::LoupeSample { center: cursor, patch }); - - self.update_hud_window_position(monitor, cursor); - } - - self.maybe_start_loupe_window_warmup_redraw(); - self.request_redraw_hud_window(); - - if self.state.alt_held || self.loupe_window_visible { - self.request_redraw_loupe_window(); + self.update_cursor_state(monitor, cursor); } self.request_redraw_toolbar_window(); @@ -4585,6 +4548,9 @@ impl OverlaySession { if self.state.alt_held == alt { return; } + if alt && !matches!(self.state.mode, OverlayMode::Live) { + return; + } self.state.alt_held = alt; @@ -4593,6 +4559,13 @@ impl OverlaySession { return; } + if self.live_drag_hides_auxiliary_windows() { + self.state.loupe = None; + + self.set_alt_loupe_window_visible(None, false); + + return; + } let Some((monitor, cursor)) = self.alt_activation_cursor_context() else { return; @@ -4604,10 +4577,7 @@ impl OverlaySession { self.maybe_request_live_bg(monitor); } - match self.state.mode { - OverlayMode::Live => self.request_live_alt_samples(monitor, cursor), - OverlayMode::Frozen => self.request_frozen_alt_samples(cursor), - } + self.request_live_alt_samples(monitor, cursor); } fn apply_loupe_activation_input(&mut self, pressed: bool, repeat: bool) -> bool { @@ -4626,6 +4596,12 @@ impl OverlaySession { } fn apply_loupe_activation_key_event(&mut self, pressed: bool, repeat: bool) -> bool { + if !matches!(self.state.mode, OverlayMode::Live) { + self.loupe_activation_key_down = false; + + return false; + } + self.loupe_activation_key_down = pressed; if !pressed && !self.state.alt_held { @@ -4673,14 +4649,6 @@ impl OverlaySession { { self.request_redraw_loupe_window(); } - - return OverlayControl::Continue; - } - - if let Some(monitor) = self.active_cursor_monitor() { - self.request_redraw_for_monitor(monitor); - } else { - self.request_redraw_all(); } OverlayControl::Continue @@ -4715,10 +4683,7 @@ impl OverlaySession { OverlayMode::Live => { self.update_cursor_for_live_move(old_monitor, old_cursor, monitor, cursor) }, - OverlayMode::Frozen => { - self.update_cursor_state(monitor, cursor); - self.update_hud_window_position(monitor, cursor); - }, + OverlayMode::Frozen => self.update_cursor_state(monitor, cursor), } } @@ -4731,16 +4696,22 @@ impl OverlaySession { if matches!(self.state.mode, OverlayMode::Live) { self.request_redraw_hud_window(); - - return; - } - - if let Some(monitor) = self.active_cursor_monitor() { - self.request_redraw_for_monitor(monitor); } } fn set_alt_loupe_window_visible(&mut self, monitor: Option, visible: bool) { + if !matches!(self.state.mode, OverlayMode::Live) { + self.loupe_window_visible = false; + + self.reset_loupe_window_warmup_redraws(); + + if let Some(loupe_window) = self.loupe_window.as_ref() { + loupe_window.window.set_visible(false); + loupe_window.window.request_redraw(); + } + + return; + } if self.live_loupe_uses_hud_window() { self.loupe_window_visible = false; @@ -4802,23 +4773,6 @@ impl OverlaySession { } } - fn request_frozen_alt_samples(&mut self, cursor: GlobalPoint) { - if let (Some(frozen_monitor), Some(_)) = - (self.state.monitor, self.state.frozen_image.as_ref()) - { - self.state.loupe = image_helpers::frozen_loupe_patch( - &self.state.frozen_image, - Some(frozen_monitor), - cursor, - self.loupe_patch_width_px, - self.loupe_patch_height_px, - ) - .map(|patch| crate::state::LoupeSample { center: cursor, patch }); - - self.request_redraw_for_monitor(frozen_monitor); - } - } - fn handle_resized(&mut self, window_id: WindowId, size: PhysicalSize) -> OverlayControl { let window_scale_factor = self .windows @@ -6110,7 +6064,8 @@ impl OverlaySession { } fn loupe_activation_shortcut_available(&self) -> bool { - !self.keyboard_modifiers.shift_key() + matches!(self.state.mode, OverlayMode::Live) + && !self.keyboard_modifiers.shift_key() && !self.keyboard_modifiers.alt_key() && !self.keyboard_modifiers.control_key() && !self.keyboard_modifiers.super_key() diff --git a/packages/rsnap-overlay/src/overlay/aux_window_runtime.rs b/packages/rsnap-overlay/src/overlay/aux_window_runtime.rs index 1c1b886b..69324498 100644 --- a/packages/rsnap-overlay/src/overlay/aux_window_runtime.rs +++ b/packages/rsnap-overlay/src/overlay/aux_window_runtime.rs @@ -352,12 +352,6 @@ impl OverlaySession { self.last_hud_window_move_at = now; } - pub(super) fn force_apply_pending_hud_and_loupe_moves(&mut self) { - self.force_apply_pending_hud_window_move(); - self.force_apply_pending_loupe_window_move(); - self.force_apply_pending_toolbar_window_move(); - } - pub(super) fn maybe_apply_pending_loupe_window_move(&mut self, now: Instant) { self.apply_pending_loupe_window_move(now, false); } diff --git a/packages/rsnap-overlay/src/overlay/capture_window_runtime.rs b/packages/rsnap-overlay/src/overlay/capture_window_runtime.rs index 3fca2f60..f180c292 100644 --- a/packages/rsnap-overlay/src/overlay/capture_window_runtime.rs +++ b/packages/rsnap-overlay/src/overlay/capture_window_runtime.rs @@ -1,36 +1,10 @@ #[allow(unused_imports)] -use crate::overlay::{GlobalPoint, MonitorRect, OverlayMode, OverlaySession, image_helpers}; +use crate::overlay::{GlobalPoint, MonitorRect, OverlayMode, OverlaySession}; impl OverlaySession { pub(super) fn update_cursor_state(&mut self, monitor: MonitorRect, cursor: GlobalPoint) { self.cursor_monitor = Some(monitor); self.state.cursor = Some(cursor); - - match self.state.mode { - OverlayMode::Live => {}, - OverlayMode::Frozen => { - if self.state.frozen_image.is_none() { - return; - } - - let frozen_monitor = self.state.monitor; - - self.state.rgb = - image_helpers::frozen_rgb(&self.state.frozen_image, frozen_monitor, cursor); - self.state.loupe = if self.state.alt_held { - image_helpers::frozen_loupe_patch( - &self.state.frozen_image, - frozen_monitor, - cursor, - self.loupe_patch_width_px, - self.loupe_patch_height_px, - ) - .map(|patch| crate::state::LoupeSample { center: cursor, patch }) - } else { - None - }; - }, - } } #[cfg(not(target_os = "macos"))] @@ -56,16 +30,20 @@ impl OverlaySession { self.capture_windows_hidden = false; #[cfg(not(target_os = "macos"))] { - if let Some(hud_window) = &self.hud_window { - hud_window.window.set_visible(true); - } + if matches!(self.state.mode, OverlayMode::Live) { + if let Some(hud_window) = &self.hud_window { + hud_window.window.set_visible(true); + } - self.hud_window_visible = true; - } + self.hud_window_visible = true; - #[cfg(not(target_os = "macos"))] - if let Some(loupe_window) = &self.loupe_window { - loupe_window.window.set_visible(self.state.alt_held); + if let Some(loupe_window) = &self.loupe_window { + loupe_window.window.set_visible(self.state.alt_held); + } + } else { + self.hud_window_visible = false; + self.loupe_window_visible = false; + } } } diff --git a/packages/rsnap-overlay/src/overlay/cursor_runtime.rs b/packages/rsnap-overlay/src/overlay/cursor_runtime.rs index ab2e0a94..7d49701b 100644 --- a/packages/rsnap-overlay/src/overlay/cursor_runtime.rs +++ b/packages/rsnap-overlay/src/overlay/cursor_runtime.rs @@ -39,6 +39,29 @@ impl OverlaySession { return; } + if self.toolbar_pointer_local.is_some() + && self.toolbar_state.visible + && let Some((monitor, global)) = self.last_event_cursor + { + let old_monitor = self.active_cursor_monitor(); + + if tracing::enabled!(tracing::Level::TRACE) { + tracing::trace!( + mode = "frozen", + source = DeviceCursorPointSource::EventRecentFallback.as_str(), + monitor_id = monitor.id, + toolbar_hover = true, + "Resolved toolbar hover cursor for frozen tick." + ); + } + if self.state.cursor == Some(global) && old_monitor == Some(monitor) { + return; + } + + self.apply_frozen_cursor_tracking_update(old_monitor, monitor, global); + + return; + } if !poll_due { return; } @@ -75,7 +98,6 @@ impl OverlaySession { let previous_drag_rect = self.state.drag_rect; self.update_cursor_state(monitor, global); - self.update_hud_window_position(monitor, global); self.update_live_drag_rect(monitor, global); self.update_frozen_selection_drag_rect(global); self.update_frozen_mosaic_drag_rect(global); @@ -83,12 +105,6 @@ impl OverlaySession { let brush_changed = self.update_frozen_brush_stroke(global); self.sync_overlay_cursor_icons(); - self.force_apply_pending_hud_and_loupe_moves(); - self.request_redraw_hud_window(); - - if self.state.alt_held || self.loupe_window_visible { - self.request_redraw_loupe_window(); - } if let Some(old_monitor) = old_monitor && old_monitor != monitor diff --git a/packages/rsnap-overlay/src/overlay/hud_runtime.rs b/packages/rsnap-overlay/src/overlay/hud_runtime.rs index a892b8ca..67d9a382 100644 --- a/packages/rsnap-overlay/src/overlay/hud_runtime.rs +++ b/packages/rsnap-overlay/src/overlay/hud_runtime.rs @@ -33,6 +33,18 @@ impl OverlaySession { } pub(super) fn maybe_skip_hud_redraw(&mut self) -> Option { + if self.live_drag_hides_auxiliary_windows() { + if let Some(hud_window) = self.hud_window.as_ref() + && self.hud_window_visible + { + hud_window.window.set_visible(false); + } + + self.hud_window_visible = false; + self.last_present_at = Instant::now(); + + return Some(OverlayControl::Continue); + } if self.frozen_selection_drag_hides_auxiliary_windows() { if let Some(hud_window) = self.hud_window.as_ref() && self.hud_window_visible @@ -57,26 +69,38 @@ impl OverlaySession { return Some(OverlayControl::Continue); } - if self.capture_windows_hidden { - #[cfg(not(target_os = "macos"))] + if matches!(self.state.mode, OverlayMode::Frozen) && self.state.error_message.is_none() { + if let Some(hud_window) = self.hud_window.as_ref() + && self.hud_window_visible { - if let Some(hud_window) = self.hud_window.as_ref() - && self.hud_window_visible - { - hud_window.window.set_visible(false); - } + hud_window.window.set_visible(false); + } - self.hud_window_visible = false; - self.last_present_at = Instant::now(); + self.hud_window_visible = false; + self.last_present_at = Instant::now(); - #[cfg(not(target_os = "macos"))] - return Some(OverlayControl::Continue); + return Some(OverlayControl::Continue); + } + if self.capture_windows_hidden && !cfg!(target_os = "macos") { + if let Some(hud_window) = self.hud_window.as_ref() + && self.hud_window_visible + { + hud_window.window.set_visible(false); } + + self.hud_window_visible = false; + self.last_present_at = Instant::now(); + + return Some(OverlayControl::Continue); } None } + pub(super) fn should_force_pending_hud_window_move_before_redraw(&self) -> bool { + !self.hud_window_visible && self.pending_hud_outer_pos.is_some() + } + pub(super) fn draw_hud_window_frame( &mut self, live_loupe_in_hud: bool, @@ -303,6 +327,10 @@ impl OverlaySession { return control; } + if self.should_force_pending_hud_window_move_before_redraw() { + self.force_apply_pending_hud_window_move(); + } + let summary = match self.draw_hud_window_frame(live_loupe_in_hud) { Ok(summary) => summary, Err(err) => return self.exit(OverlayExit::Error(format!("{err:#}"))), @@ -340,11 +368,13 @@ impl OverlaySession { } pub(super) fn should_skip_loupe_redraw(&self) -> bool { - self.frozen_selection_drag_hides_auxiliary_windows() + self.live_drag_hides_auxiliary_windows() + || !matches!(self.state.mode, OverlayMode::Live) + || self.frozen_selection_drag_hides_auxiliary_windows() || self.scroll_capture.active || self.capture_windows_hidden || !self.state.alt_held - || (matches!(self.state.mode, OverlayMode::Live) && self.live_loupe_uses_hud_window()) + || self.live_loupe_uses_hud_window() } pub(super) fn current_loupe_draw_target(&self) -> Option<(MonitorRect, GlobalPoint)> { diff --git a/packages/rsnap-overlay/src/overlay/image_helpers.rs b/packages/rsnap-overlay/src/overlay/image_helpers.rs index 69af8c82..feeabcb7 100644 --- a/packages/rsnap-overlay/src/overlay/image_helpers.rs +++ b/packages/rsnap-overlay/src/overlay/image_helpers.rs @@ -6,7 +6,6 @@ use image::{ }; use crate::overlay::SCROLL_CAPTURE_PREVIEW_WIDTH_PX; -use crate::state::{GlobalPoint, MonitorRect, Rgb}; pub(super) fn resize_scroll_preview_segment(segment: &RgbaImage) -> RgbaImage { if segment.width() <= SCROLL_CAPTURE_PREVIEW_WIDTH_PX { @@ -21,64 +20,6 @@ pub(super) fn resize_scroll_preview_segment(segment: &RgbaImage) -> RgbaImage { imageops::resize(segment, SCROLL_CAPTURE_PREVIEW_WIDTH_PX, preview_height, FilterType::Triangle) } -pub(super) fn frozen_rgb( - image: &Option, - monitor: Option, - point: GlobalPoint, -) -> Option { - let Some(image) = image else { - return None; - }; - let monitor = monitor?; - let (x, y) = monitor.local_u32_pixels(point)?; - let pixel = image.get_pixel_checked(x, y)?; - - Some(Rgb::new(pixel.0[0], pixel.0[1], pixel.0[2])) -} - -pub(super) fn frozen_loupe_patch( - image: &Option, - monitor: Option, - point: GlobalPoint, - width_px: u32, - height_px: u32, -) -> Option { - let Some(image) = image else { - return None; - }; - let monitor = monitor?; - let (center_x, center_y) = monitor.local_u32_pixels(point)?; - let mut out = RgbaImage::new(width_px.max(1), height_px.max(1)); - let out_width = out.width() as i32; - let out_height = out.height() as i32; - let half_width = out_width / 2; - let half_height = out_height / 2; - let center_x = center_x as i32; - let center_y = center_y as i32; - let image_width = image.width() as i32; - let image_height = image.height() as i32; - - for out_y in 0..out.height() { - for out_x in 0..out.width() { - let image_x = center_x + (out_x as i32) - half_width; - let image_y = center_y + (out_y as i32) - half_height; - let color = if image_x >= 0 - && image_y >= 0 - && image_x < image_width - && image_y < image_height - { - *image.get_pixel(image_x as u32, image_y as u32) - } else { - image::Rgba([0, 0, 0, 0]) - }; - - out.put_pixel(out_x, out_y, color); - } - } - - Some(out) -} - pub(super) fn pad_rows( src: &[u8], src_row_bytes: usize, diff --git a/packages/rsnap-overlay/src/overlay/rendering/hud_rendering.rs b/packages/rsnap-overlay/src/overlay/rendering/hud_rendering.rs index 520597b2..c34f66e5 100644 --- a/packages/rsnap-overlay/src/overlay/rendering/hud_rendering.rs +++ b/packages/rsnap-overlay/src/overlay/rendering/hud_rendering.rs @@ -22,14 +22,9 @@ impl WindowRenderer { state: &OverlayState, monitor: MonitorRect, ) -> bool { - if cfg!(target_os = "macos") && matches!(state.mode, OverlayMode::Frozen) { - return true; - } + let _ = monitor; - !matches!(state.mode, OverlayMode::Frozen) - || state.monitor != Some(monitor) - || state.frozen_image.is_some() - || state.error_message.is_some() + matches!(state.mode, OverlayMode::Live) || state.error_message.is_some() } #[allow(clippy::too_many_arguments)] @@ -370,30 +365,8 @@ impl WindowRenderer { ) { const CELL: f32 = 10.0; - let mode = state.mode; - - if matches!(mode, OverlayMode::Live) { + if matches!(state.mode, OverlayMode::Live) { self.render_live_loupe(ui, state, CELL, hud_blur_active, hud_opaque, theme); - } else if matches!(mode, OverlayMode::Frozen) - && (state.frozen_image.is_some() || state.loupe.is_some()) - { - let Some(monitor) = state.monitor else { - return; - }; - let Some(cursor) = state.cursor else { - return; - }; - - self.render_frozen_loupe( - ui, - state, - monitor, - cursor, - CELL, - hud_blur_active, - hud_opaque, - theme, - ); } } @@ -488,90 +461,4 @@ impl WindowRenderer { StrokeKind::Inside, ); } - - #[allow(clippy::too_many_arguments)] - fn render_frozen_loupe( - &mut self, - ui: &mut Ui, - state: &OverlayState, - monitor: MonitorRect, - cursor: GlobalPoint, - cell: f32, - hud_blur_active: bool, - hud_opaque: bool, - theme: HudTheme, - ) { - if state.loupe.is_some() { - self.render_live_loupe(ui, state, cell, hud_blur_active, hud_opaque, theme); - - return; - } - - const LOUPE_RADIUS_PX: i32 = 5; - const LOUPE_SIDE_PX: i32 = (LOUPE_RADIUS_PX * 2) + 1; - - let side = (LOUPE_SIDE_PX as f32) * cell; - let (rect, _) = ui.allocate_exact_size(Vec2::new(side, side), Sense::hover()); - let Some(image) = state.frozen_image.as_ref() else { - return; - }; - let Some((center_x, center_y)) = monitor.local_u32_pixels(cursor) else { - return; - }; - let (width, height) = image.dimensions(); - let width = width as i32; - let height = height as i32; - let center_x = center_x as i32; - let center_y = center_y as i32; - let stroke = Stroke::new(1.0, Color32::from_rgba_unmultiplied(0, 0, 0, 140)); - let grid_stroke = Stroke::new(1.0, Color32::from_rgba_unmultiplied(255, 255, 255, 26)); - - for dy in -LOUPE_RADIUS_PX..=LOUPE_RADIUS_PX { - for dx in -LOUPE_RADIUS_PX..=LOUPE_RADIUS_PX { - let x = center_x + dx; - let y = center_y + dy; - let cell_x = dx + LOUPE_RADIUS_PX; - let cell_y = dy + LOUPE_RADIUS_PX; - let cell_min = Pos2::new( - rect.min.x + (cell_x as f32) * cell, - rect.min.y + (cell_y as f32) * cell, - ); - let cell_rect = Rect::from_min_size(cell_min, Vec2::splat(cell)); - let fill = if x < 0 || y < 0 || x >= width || y >= height { - Color32::from_rgba_unmultiplied(0, 0, 0, 0) - } else { - let pixel = - image.get_pixel_checked(x as u32, y as u32).expect("pixel bounds checked"); - - Color32::from_rgb(pixel.0[0], pixel.0[1], pixel.0[2]) - }; - - ui.painter().rect_filled(cell_rect, 0.0, fill); - } - } - for i in 0..=LOUPE_SIDE_PX { - let x = rect.min.x + (i as f32) * cell; - let y = rect.min.y + (i as f32) * cell; - - ui.painter() - .line_segment([Pos2::new(x, rect.min.y), Pos2::new(x, rect.max.y)], grid_stroke); - ui.painter() - .line_segment([Pos2::new(rect.min.x, y), Pos2::new(rect.max.x, y)], grid_stroke); - } - - ui.painter().rect_stroke(rect, 3.0, stroke, StrokeKind::Outside); - - let center_min = Pos2::new( - rect.min.x + (LOUPE_RADIUS_PX as f32) * cell, - rect.min.y + (LOUPE_RADIUS_PX as f32) * cell, - ); - let center_rect = Rect::from_min_size(center_min, Vec2::splat(cell)); - - ui.painter().rect_stroke( - center_rect, - 0.0, - Stroke::new(2.0, Color32::from_rgba_unmultiplied(255, 255, 255, 180)), - StrokeKind::Inside, - ); - } } diff --git a/packages/rsnap-overlay/src/overlay/tests.rs b/packages/rsnap-overlay/src/overlay/tests.rs index 754df1e1..105f55ca 100644 --- a/packages/rsnap-overlay/src/overlay/tests.rs +++ b/packages/rsnap-overlay/src/overlay/tests.rs @@ -1807,32 +1807,6 @@ fn toolbar_window_stays_visible_while_final_capture_is_pending() { assert!(!session.should_hide_toolbar_window(monitor)); } -#[test] -fn force_pending_hud_and_loupe_moves_only_during_frozen_transition() { - let monitor = test_monitor(); - let mut session = OverlaySession::new(); - - assert!(!session.should_force_pending_hud_and_loupe_moves()); - - session.state.begin_freeze(monitor); - - assert!(session.should_force_pending_hud_and_loupe_moves()); - - session.state.finish_freeze(monitor, test_frozen_image()); - - session.authoritative_frozen_capture_ready = true; - - assert!(!session.should_force_pending_hud_and_loupe_moves()); - - session.inflight_freeze_capture = Some(monitor); - - assert!(session.should_force_pending_hud_and_loupe_moves()); - - session.state.mode = OverlayMode::Live; - - assert!(!session.should_force_pending_hud_and_loupe_moves()); -} - #[test] fn tinted_hud_body_fill_amount_zero_keeps_base_fill() { for theme in [HudTheme::Dark, HudTheme::Light] { diff --git a/packages/rsnap-overlay/src/overlay/tests/live_runtime.rs b/packages/rsnap-overlay/src/overlay/tests/live_runtime.rs index 5912f048..07908dff 100644 --- a/packages/rsnap-overlay/src/overlay/tests/live_runtime.rs +++ b/packages/rsnap-overlay/src/overlay/tests/live_runtime.rs @@ -4,11 +4,12 @@ use image::RgbaImage; use crate::live_frame_stream_macos::MacLiveFrameStream; #[cfg(target_os = "macos")] use crate::overlay::DeviceCursorPointSource; +use crate::overlay::OverlayControl; #[allow(unused_imports)] use crate::overlay::tests::{ - self, Duration, GlobalPoint, HudRedrawSummary, LoupeSample, MonitorRect, MonitorRectPoints, - OverlayMode, OverlaySession, OverlayState, Pos2, Rect, RectPoints, Rgb, Vec2, WindowRenderer, - hud_helpers, overlay, + self, Duration, GlobalPoint, HudRedrawSummary, Instant, LoupeSample, MonitorRect, + MonitorRectPoints, OverlayMode, OverlaySession, OverlayState, Pos2, Rect, RectPoints, Rgb, + Vec2, WindowRenderer, hud_helpers, overlay, }; #[cfg(target_os = "macos")] #[allow(unused_imports)] @@ -52,6 +53,62 @@ fn apply_live_cursor_sample_updates_rgb_and_loupe_state() { ); } +#[test] +fn frozen_toolbar_cursor_event_updates_frozen_cursor_context() { + let monitor = MonitorRect { + id: 1, + origin: GlobalPoint::new(0, 0), + width: 1_000, + height: 800, + scale_factor_x1000: 1_000, + }; + let cursor = GlobalPoint::new(120, 180); + let patch = RgbaImage::from_pixel(400, 300, crate::overlay::tests::Rgba([10, 20, 30, 255])); + let mut session = OverlaySession::new(); + + session.state.mode = OverlayMode::Frozen; + session.state.monitor = Some(monitor); + session.state.frozen_image = Some(patch.clone()); + session.state.alt_held = true; + + session.note_frozen_toolbar_cursor_event(monitor, cursor); + + assert_eq!(session.last_event_cursor, Some((monitor, cursor))); + assert_eq!(session.state.cursor, Some(cursor)); + assert_eq!(session.state.rgb, None); + assert!(session.state.loupe.is_none()); +} + +#[test] +fn frozen_cursor_tracking_keeps_toolbar_hover_cursor_without_resampling_device_position() { + let monitor = MonitorRect { + id: 1, + origin: GlobalPoint::new(0, 0), + width: 1_000, + height: 800, + scale_factor_x1000: 1_000, + }; + let expected_cursor = GlobalPoint::new(540, 420); + let stale_cursor = GlobalPoint::new(7, 8); + let mut session = OverlaySession::new(); + + session.session_active = true; + session.state.mode = OverlayMode::Frozen; + session.state.monitor = Some(monitor); + session.toolbar_state.visible = true; + session.toolbar_pointer_local = Some(Pos2::new(12.0, 10.0)); + session.state.cursor = Some(stale_cursor); + session.cursor_monitor = Some(monitor); + session.last_event_cursor = Some((monitor, expected_cursor)); + session.last_event_cursor_at = Some(Instant::now() - Duration::from_millis(500)); + session.last_frozen_cursor_poll_at = Instant::now() - Duration::from_secs(1); + + session.maybe_tick_frozen_cursor_tracking(); + + assert_eq!(session.state.cursor, Some(expected_cursor)); + assert_eq!(session.cursor_monitor, Some(monitor)); +} + #[cfg(target_os = "macos")] #[test] fn apply_live_cursor_sample_detail_keeps_overlay_redraw_narrow_for_rgb_and_loupe_updates() { @@ -180,6 +237,33 @@ fn clear_loupe_activation_on_focus_loss_releases_toggle_press_without_toggling_o assert!(session.plain_character_shortcut_available()); } +#[cfg(target_os = "macos")] +#[test] +fn apply_loupe_activation_key_event_ignores_frozen_mode() { + let mut session = OverlaySession::new(); + + session.state.mode = OverlayMode::Frozen; + + assert!(!session.apply_loupe_activation_key_event(true, false)); + assert!(!session.state.alt_held); + assert!(!session.loupe_activation_key_down); +} + +#[test] +fn live_drag_alt_activation_does_not_reopen_loupe() { + let mut session = OverlaySession::new(); + + session.state.mode = OverlayMode::Live; + session.state.drag_rect = + Some(MonitorRectPoints { monitor_id: 1, rect: RectPoints::new(100, 120, 240, 320) }); + + session.set_alt_held(true); + + assert!(session.state.alt_held); + assert!(!session.loupe_window_visible); + assert!(session.state.loupe.is_none()); +} + #[cfg(target_os = "macos")] #[test] fn loupe_activation_shortcut_available_requires_plain_tab() { @@ -341,6 +425,22 @@ fn live_alt_loupe_window_redraw_is_not_skipped() { session.state.alt_held = false; assert!(session.should_skip_loupe_redraw()); + + session.state.alt_held = true; + session.state.drag_rect = + Some(MonitorRectPoints { monitor_id: 1, rect: RectPoints::new(100, 120, 240, 320) }); + + assert!(session.should_skip_loupe_redraw()); +} + +#[test] +fn frozen_loupe_window_redraw_is_skipped() { + let mut session = OverlaySession::new(); + + session.state.mode = OverlayMode::Frozen; + session.state.alt_held = true; + + assert!(session.should_skip_loupe_redraw()); } #[test] @@ -417,6 +517,39 @@ fn live_drag_focus_rect_uses_large_drag_on_active_monitor() { assert_eq!(WindowRenderer::live_drag_focus_rect(&state, monitor, screen_rect), None); } +#[test] +fn live_drag_rect_activation_hides_auxiliary_windows() { + let monitor = MonitorRect { + id: 1, + origin: GlobalPoint::new(0, 0), + width: 1_000, + height: 800, + scale_factor_x1000: 1_000, + }; + let start = GlobalPoint::new(120, 180); + let end = GlobalPoint::new(280, 360); + let mut session = OverlaySession::new(); + + session.state.mode = OverlayMode::Live; + session.left_mouse_button_down = true; + session.left_mouse_button_down_monitor = Some(monitor); + session.left_mouse_button_down_global = Some(start); + session.hud_window_visible = true; + session.loupe_window_visible = true; + + session.update_live_drag_rect(monitor, end); + + assert_eq!( + session.state.drag_rect, + Some(MonitorRectPoints { + monitor_id: monitor.id, + rect: RectPoints::new(120, 180, 160, 180), + }) + ); + assert!(!session.hud_window_visible); + assert!(!session.loupe_window_visible); +} + #[cfg(target_os = "macos")] #[test] fn sync_live_sample_attempt_does_not_leave_pending_request() { @@ -705,6 +838,82 @@ fn frozen_hud_redraw_does_not_consume_pending_move_without_size_change() { })); } +#[test] +fn hidden_hud_redraw_forces_pending_move_before_show() { + let mut session = OverlaySession::new(); + + session.hud_window_visible = false; + session.pending_hud_outer_pos = Some(GlobalPoint::new(120, 180)); + + assert!(session.should_force_pending_hud_window_move_before_redraw()); + + session.hud_window_visible = true; + + assert!(!session.should_force_pending_hud_window_move_before_redraw()); + + session.hud_window_visible = false; + session.pending_hud_outer_pos = None; + + assert!(!session.should_force_pending_hud_window_move_before_redraw()); +} + +#[cfg(not(target_os = "macos"))] +#[test] +fn capture_windows_hidden_skips_hud_redraw() { + let mut session = OverlaySession::new(); + + session.hud_window_visible = true; + session.capture_windows_hidden = true; + + assert!(matches!(session.maybe_skip_hud_redraw(), Some(OverlayControl::Continue))); + assert!(!session.hud_window_visible); +} + +#[cfg(target_os = "macos")] +#[test] +fn capture_windows_hidden_allows_hud_redraw_for_error_message() { + let mut session = OverlaySession::new(); + + session.capture_windows_hidden = true; + + session.state.set_error("Preparing capture..."); + + assert!(session.maybe_skip_hud_redraw().is_none()); +} + +#[test] +fn live_drag_skips_hud_redraw() { + let monitor = MonitorRect { + id: 1, + origin: GlobalPoint::new(0, 0), + width: 1_000, + height: 800, + scale_factor_x1000: 1_000, + }; + let mut session = OverlaySession::new(); + + session.state.mode = OverlayMode::Live; + session.state.drag_rect = Some(MonitorRectPoints { + monitor_id: monitor.id, + rect: RectPoints::new(100, 120, 240, 320), + }); + session.hud_window_visible = true; + + assert!(matches!(session.maybe_skip_hud_redraw(), Some(OverlayControl::Continue))); + assert!(!session.hud_window_visible); +} + +#[test] +fn frozen_hud_redraw_skips_without_error_message() { + let mut session = OverlaySession::new(); + + session.state.mode = OverlayMode::Frozen; + session.hud_window_visible = true; + + assert!(matches!(session.maybe_skip_hud_redraw(), Some(OverlayControl::Continue))); + assert!(!session.hud_window_visible); +} + #[test] fn live_cursor_update_tries_pending_follow_window_moves() { let mut session = OverlaySession::new(); diff --git a/packages/rsnap-overlay/src/overlay/tests/rendering_behaviors.rs b/packages/rsnap-overlay/src/overlay/tests/rendering_behaviors.rs index dfe7ca6f..6bcfdb65 100644 --- a/packages/rsnap-overlay/src/overlay/tests/rendering_behaviors.rs +++ b/packages/rsnap-overlay/src/overlay/tests/rendering_behaviors.rs @@ -478,6 +478,68 @@ fn toolbar_position_update_queues_pending_move_without_window() { assert_eq!(session.pending_toolbar_outer_pos, Some(GlobalPoint::new(120, 160))); } +#[test] +fn toolbar_cursor_global_position_from_outer_uses_cached_toolbar_origin() { + let outer_position = GlobalPoint::new(220, 260); + let cursor_local = Pos2::new(18.25, 12.75); + + assert_eq!( + OverlaySession::toolbar_cursor_global_position_from_outer(outer_position, cursor_local), + GlobalPoint::new(238, 273) + ); +} + +#[test] +fn toolbar_event_outer_position_prefers_window_position_over_cached_position() { + let monitor = tests::test_monitor(); + let window_outer_pos = Some(GlobalPoint::new(220, 260)); + let cached_outer_pos = Some(GlobalPoint::new(340, 420)); + let floating_position = Some(Pos2::new(80.0, 90.0)); + + assert_eq!( + OverlaySession::toolbar_event_outer_position_from_sources( + monitor, + window_outer_pos, + cached_outer_pos, + floating_position, + ), + window_outer_pos + ); +} + +#[test] +fn toolbar_event_outer_position_falls_back_to_cached_position() { + let monitor = tests::test_monitor(); + let cached_outer_pos = Some(GlobalPoint::new(340, 420)); + let floating_position = Some(Pos2::new(80.0, 90.0)); + + assert_eq!( + OverlaySession::toolbar_event_outer_position_from_sources( + monitor, + None, + cached_outer_pos, + floating_position, + ), + cached_outer_pos + ); +} + +#[test] +fn toolbar_event_outer_position_falls_back_to_floating_position() { + let monitor = tests::test_monitor(); + let floating_position = Some(Pos2::new(80.4, 90.6)); + + assert_eq!( + OverlaySession::toolbar_event_outer_position_from_sources( + monitor, + None, + None, + floating_position, + ), + Some(GlobalPoint::new(80, 91)) + ); +} + #[test] fn frozen_selection_resize_preserves_handle_press_offset() { let monitor = tests::test_monitor(); diff --git a/packages/rsnap-overlay/src/overlay/toolbar_runtime.rs b/packages/rsnap-overlay/src/overlay/toolbar_runtime.rs index 1cffe63b..7a5ea45e 100644 --- a/packages/rsnap-overlay/src/overlay/toolbar_runtime.rs +++ b/packages/rsnap-overlay/src/overlay/toolbar_runtime.rs @@ -11,6 +11,30 @@ use crate::overlay::{ }; impl OverlaySession { + pub(super) fn note_frozen_toolbar_cursor_event( + &mut self, + monitor: MonitorRect, + global_cursor: GlobalPoint, + ) { + let old_monitor = self.active_cursor_monitor(); + let old_cursor = self.state.cursor; + + self.last_event_cursor = Some((monitor, global_cursor)); + self.last_event_cursor_at = Some(Instant::now()); + + if old_monitor == Some(monitor) && old_cursor == Some(global_cursor) { + return; + } + + self.update_cursor_state(monitor, global_cursor); + + if let Some(old_monitor) = old_monitor + && old_monitor != monitor + { + self.request_redraw_for_monitor(old_monitor); + } + } + pub(super) fn handle_toolbar_cursor_moved( &mut self, window_id: WindowId, @@ -32,10 +56,23 @@ impl OverlaySession { self.toolbar_pointer_local = Some(cursor_local); + let cached_toolbar_outer_pos = self.toolbar_outer_pos; + let window_toolbar_outer_pos = Self::toolbar_window_outer_position(toolbar_window); + let monitor = match self.state.monitor.or_else(|| self.active_cursor_monitor()) { + Some(monitor) => monitor, + None => return OverlayControl::Continue, + }; + let toolbar_outer_pos = Self::toolbar_event_outer_position_from_sources( + monitor, + window_toolbar_outer_pos, + cached_toolbar_outer_pos, + self.toolbar_state.floating_position, + ); + let global_cursor = toolbar_outer_pos + .map(|outer| Self::toolbar_cursor_global_position_from_outer(outer, cursor_local)); + if self.frozen_selection_drag.active { - if let Some(global_cursor) = - self.toolbar_cursor_global_position(toolbar_window, cursor_local) - { + if let Some(global_cursor) = global_cursor { self.update_frozen_selection_drag_rect(global_cursor); self.update_frozen_mosaic_drag_rect(global_cursor); } @@ -43,20 +80,25 @@ impl OverlaySession { return OverlayControl::Continue; } if self.frozen_mosaic_drag.active { - if let Some(global_cursor) = - self.toolbar_cursor_global_position(toolbar_window, cursor_local) - { + if let Some(global_cursor) = global_cursor { self.update_frozen_mosaic_drag_rect(global_cursor); } return OverlayControl::Continue; } - let monitor = match self.state.monitor.or_else(|| self.active_cursor_monitor()) { - Some(monitor) => monitor, - None => return OverlayControl::Continue, - }; - let global_cursor = self.toolbar_cursor_global_position(toolbar_window, cursor_local); + if let Some(global_cursor) = global_cursor { + self.maybe_log_suspicious_toolbar_cursor_translation( + monitor, + self.state.cursor, + cursor_local, + global_cursor, + cached_toolbar_outer_pos, + window_toolbar_outer_pos, + ); + self.note_frozen_toolbar_cursor_event(monitor, global_cursor); + } + let drag_monitor = global_cursor.and_then(|cursor| self.monitor_at(cursor)).unwrap_or(monitor); let mut mouse_drag = self.toolbar_left_button_down && self.toolbar_state.dragging; @@ -69,27 +111,17 @@ impl OverlaySession { let dy = cursor_local.y - drag_anchor.y; let threshold_sq = TOOLBAR_DRAG_START_THRESHOLD_PX * TOOLBAR_DRAG_START_THRESHOLD_PX; - if dx * dx + dy * dy >= threshold_sq { - let toolbar_outer_pos = self.toolbar_outer_pos.or_else(|| { - self.toolbar_state.floating_position.map(|floating_position| { - GlobalPoint::new( - monitor.origin.x.saturating_add(floating_position.x.round() as i32), - monitor.origin.y.saturating_add(floating_position.y.round() as i32), - ) - }) - }); - - if let (Some(global_cursor), Some(toolbar_outer_pos)) = + if dx * dx + dy * dy >= threshold_sq + && let (Some(global_cursor), Some(toolbar_outer_pos)) = (global_cursor, toolbar_outer_pos) - { - self.toolbar_state.drag_offset = Vec2::new( - global_cursor.x as f32 - toolbar_outer_pos.x as f32, - global_cursor.y as f32 - toolbar_outer_pos.y as f32, - ); - self.toolbar_state.dragging = true; - self.toolbar_state.drag_anchor = None; - mouse_drag = true; - } + { + self.toolbar_state.drag_offset = Vec2::new( + global_cursor.x as f32 - toolbar_outer_pos.x as f32, + global_cursor.y as f32 - toolbar_outer_pos.y as f32, + ); + self.toolbar_state.dragging = true; + self.toolbar_state.drag_anchor = None; + mouse_drag = true; } } if mouse_drag && global_cursor.is_none() { @@ -112,19 +144,97 @@ impl OverlaySession { OverlayControl::Continue } - pub(super) fn toolbar_cursor_global_position( - &self, + pub(super) fn toolbar_event_outer_position_from_sources( + monitor: MonitorRect, + window_toolbar_outer_pos: Option, + cached_toolbar_outer_pos: Option, + floating_position: Option, + ) -> Option { + window_toolbar_outer_pos.or(cached_toolbar_outer_pos).or_else(|| { + floating_position.map(|floating_position| { + GlobalPoint::new( + monitor.origin.x.saturating_add(floating_position.x.round() as i32), + monitor.origin.y.saturating_add(floating_position.y.round() as i32), + ) + }) + }) + } + + pub(super) fn toolbar_window_outer_position( toolbar_window: &HudOverlayWindow, - cursor_local: Pos2, ) -> Option { let toolbar_scale = toolbar_window.window.scale_factor().max(1.0); let outer_position = toolbar_window.window.outer_position().ok()?; + + Some(GlobalPoint::new( + (outer_position.x as f64 / toolbar_scale).round() as i32, + (outer_position.y as f64 / toolbar_scale).round() as i32, + )) + } + + pub(super) fn toolbar_cursor_global_position_from_outer( + outer_position: GlobalPoint, + cursor_local: Pos2, + ) -> GlobalPoint { let global_cursor = Pos2::new( - (outer_position.x as f64 / toolbar_scale) as f32 + cursor_local.x, - (outer_position.y as f64 / toolbar_scale) as f32 + cursor_local.y, + outer_position.x as f32 + cursor_local.x, + outer_position.y as f32 + cursor_local.y, ); - Some(GlobalPoint::new(global_cursor.x.round() as i32, global_cursor.y.round() as i32)) + GlobalPoint::new(global_cursor.x.round() as i32, global_cursor.y.round() as i32) + } + + fn toolbar_cursor_translation_suspicious( + monitor: MonitorRect, + old_cursor: Option, + global_cursor: GlobalPoint, + ) -> bool { + if !monitor.contains(global_cursor) { + return true; + } + + let Some(old_cursor) = old_cursor else { + return false; + }; + let delta_x = old_cursor.x.abs_diff(global_cursor.x); + let delta_y = old_cursor.y.abs_diff(global_cursor.y); + let jumps_far = delta_x > 160 || delta_y > 160; + let snaps_to_origin = global_cursor.x <= monitor.origin.x + 8 + && global_cursor.y <= monitor.origin.y + 8 + && (old_cursor.x > monitor.origin.x + 32 || old_cursor.y > monitor.origin.y + 32); + + jumps_far || snaps_to_origin + } + + fn maybe_log_suspicious_toolbar_cursor_translation( + &self, + monitor: MonitorRect, + old_cursor: Option, + cursor_local: Pos2, + global_cursor: GlobalPoint, + cached_toolbar_outer_pos: Option, + window_toolbar_outer_pos: Option, + ) { + if self.frozen_selection_drag.active + || self.frozen_mosaic_drag.active + || self.toolbar_state.dragging + || !Self::toolbar_cursor_translation_suspicious(monitor, old_cursor, global_cursor) + { + return; + } + + tracing::warn!( + op = "overlay.toolbar_cursor_translation_suspicious", + monitor_id = monitor.id, + old_cursor = ?old_cursor, + cursor_local = ?cursor_local, + global_cursor = ?global_cursor, + cached_toolbar_outer_pos = ?cached_toolbar_outer_pos, + window_toolbar_outer_pos = ?window_toolbar_outer_pos, + pending_toolbar_outer_pos = ?self.pending_toolbar_outer_pos, + toolbar_floating_position = ?self.toolbar_state.floating_position, + "Toolbar cursor translation jumped unexpectedly." + ); } pub(super) fn handle_toolbar_window_resized( diff --git a/packages/rsnap-overlay/src/overlay/window_runtime.rs b/packages/rsnap-overlay/src/overlay/window_runtime.rs index 3cbc0c53..ded0033e 100644 --- a/packages/rsnap-overlay/src/overlay/window_runtime.rs +++ b/packages/rsnap-overlay/src/overlay/window_runtime.rs @@ -313,7 +313,7 @@ impl OverlaySession { self.complete_startup_aux_window_creation(created_aux_windows); - if self.state.alt_held { + if self.state.alt_held && matches!(self.state.mode, OverlayMode::Live) { self.set_alt_loupe_window_visible(self.active_cursor_monitor(), true); } if self.toolbar_state.visible { @@ -833,8 +833,13 @@ impl OverlaySession { } let hide_auxiliary_windows = self.frozen_selection_drag_hides_auxiliary_windows(); - let request_hud_window = !hide_auxiliary_windows && self.hud_window.is_some(); - let request_loupe_window = !hide_auxiliary_windows && self.loupe_window.is_some(); + let hide_live_drag_auxiliary_windows = self.live_drag_hides_auxiliary_windows(); + let request_hud_window = !hide_auxiliary_windows + && !hide_live_drag_auxiliary_windows + && self.hud_window.is_some(); + let request_loupe_window = !hide_auxiliary_windows + && !hide_live_drag_auxiliary_windows + && self.loupe_window.is_some(); let request_toolbar_window = !hide_auxiliary_windows && cfg!(target_os = "macos") && matches!(self.state.mode, OverlayMode::Frozen) @@ -888,7 +893,9 @@ impl OverlaySession { } pub(super) fn request_redraw_hud_window(&self) { - if self.frozen_selection_drag_hides_auxiliary_windows() { + if self.frozen_selection_drag_hides_auxiliary_windows() + || self.live_drag_hides_auxiliary_windows() + { return; } @@ -908,7 +915,9 @@ impl OverlaySession { } pub(super) fn request_redraw_loupe_window(&self) { - if self.frozen_selection_drag_hides_auxiliary_windows() { + if self.frozen_selection_drag_hides_auxiliary_windows() + || self.live_drag_hides_auxiliary_windows() + { return; }