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
16 changes: 9 additions & 7 deletions apps/rsnap/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
mod capture;
#[cfg(target_os = "macos")]
mod capture_host_macos;
mod hotkeys;
mod runtime;
#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -41,9 +43,9 @@ use self::scroll_input_macos::SharedScrollInputState;
use crate::permissions_macos;
use crate::settings::AppSettings;
use crate::settings_window::{SettingsWindow, SettingsWindowEntry};
#[cfg(target_os = "macos")]
use rsnap_overlay::FrozenGlobalHotkey;
use rsnap_overlay::OverlaySession;
#[cfg(target_os = "macos")]
use rsnap_overlay::{FrozenGlobalHotkey, MacOSCaptureHost, MacOSNativeCaptureInputEvent};

pub(crate) enum UserEvent {
TrayIcon,
Expand All @@ -58,7 +60,7 @@ pub(crate) enum UserEvent {
#[cfg(target_os = "macos")]
OverlayWorkerResponse,
#[cfg(target_os = "macos")]
OverlayNativeCaptureInput,
OverlayNativeCaptureInput(u64, MacOSNativeCaptureInputEvent),
}

#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -141,6 +143,8 @@ struct App {
menubar_quit_menu_id: Option<MenuId>,
overlay_session: Option<OverlaySession>,
#[cfg(target_os = "macos")]
overlay_capture_host: Option<MacOSCaptureHost>,
#[cfg(target_os = "macos")]
prewarmed_overlay_session: Option<OverlaySession>,
settings_window: Option<SettingsWindow>,
settings_window_capture_window_id: Option<u32>,
Expand All @@ -156,8 +160,6 @@ struct App {
#[cfg(target_os = "macos")]
overlay_stream_event_pending: Arc<AtomicBool>,
#[cfg(target_os = "macos")]
overlay_native_capture_input_event_pending: Arc<AtomicBool>,
#[cfg(target_os = "macos")]
latest_deferred_ocr_generation: Arc<AtomicU64>,
#[cfg(target_os = "macos")]
pending_deferred_ocr_generation: Arc<AtomicU64>,
Expand Down Expand Up @@ -261,6 +263,8 @@ impl App {
menubar_quit_menu_id: None,
overlay_session: None,
#[cfg(target_os = "macos")]
overlay_capture_host: None,
#[cfg(target_os = "macos")]
prewarmed_overlay_session: None,
settings_window: None,
settings_window_capture_window_id: None,
Expand All @@ -276,8 +280,6 @@ impl App {
#[cfg(target_os = "macos")]
overlay_stream_event_pending: Arc::new(AtomicBool::new(false)),
#[cfg(target_os = "macos")]
overlay_native_capture_input_event_pending: Arc::new(AtomicBool::new(false)),
#[cfg(target_os = "macos")]
latest_deferred_ocr_generation: Arc::new(AtomicU64::new(0)),
#[cfg(target_os = "macos")]
pending_deferred_ocr_generation: Arc::new(AtomicU64::new(0)),
Expand Down
89 changes: 57 additions & 32 deletions apps/rsnap/src/app/capture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use crate::app::scroll_input_macos::{
#[cfg(target_os = "macos")]
use crate::permissions_macos;
#[cfg(target_os = "macos")]
use rsnap_overlay::DeferredTextRecognitionRequest;
use rsnap_overlay::{DeferredTextRecognitionRequest, MacOSCaptureHost};
use rsnap_overlay::{HudAnchor, OverlayConfig, OverlayControl, OverlayExit, OverlaySession};

#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -412,7 +412,6 @@ impl App {
self.overlay_session_prewarm_retry_not_before = None;
self.overlay_session_generation = self.overlay_session_generation.wrapping_add(1);

self.overlay_native_capture_input_event_pending.store(false, Ordering::Release);
self.pending_deferred_ocr_generation
.store(self.overlay_session_generation, Ordering::Release);
}
Expand All @@ -424,6 +423,8 @@ impl App {

let hook_wiring_ms = hook_wiring_started_at.elapsed().as_millis();
let overlay_start_started_at = Instant::now();
#[cfg(target_os = "macos")]
let mut overlay_capture_host = self.begin_overlay_capture_host_session();

match overlay_session.start(event_loop) {
Ok(()) => {
Expand Down Expand Up @@ -458,20 +459,21 @@ impl App {

self.overlay_session = Some(overlay_session);

#[cfg(target_os = "macos")]
if !self.attach_overlay_capture_host_after_start(overlay_capture_host) {
return;
}

#[cfg(target_os = "macos")]
self.sync_overlay_hotkey_registrations();
},
Err(err) => {
let overlay_start_ms = overlay_start_started_at.elapsed().as_millis();

#[cfg(target_os = "macos")]
self.pending_deferred_ocr_generation.store(0, Ordering::Release);
overlay_capture_host.cancel_session_start();
#[cfg(target_os = "macos")]
{
self.scroll_input_shared_state.set_enabled(false);
self.scroll_input_shared_state.set_event_waker(None);
self.scroll_input_shared_state.clear();
}
self.reset_capture_start_after_failure();

tracing::warn!(
op = "capture.start_phase_timing",
Expand All @@ -488,14 +490,48 @@ impl App {
"Failed to start overlay session."
);

#[cfg(target_os = "macos")]
{
self.overlay_session_prewarm_requested = true;
}
self.note_capture_start_failure_for_prewarm();
},
}
}

#[cfg(target_os = "macos")]
fn begin_overlay_capture_host_session(&self) -> MacOSCaptureHost {
let mut overlay_capture_host = self.build_overlay_capture_host();

overlay_capture_host.begin_session();

overlay_capture_host
}

#[cfg(target_os = "macos")]
fn attach_overlay_capture_host_after_start(
&mut self,
overlay_capture_host: MacOSCaptureHost,
) -> bool {
self.overlay_capture_host = Some(overlay_capture_host);

self.sync_overlay_capture_host();

self.overlay_session.is_some()
}

#[cfg(target_os = "macos")]
fn reset_capture_start_after_failure(&mut self) {
self.pending_deferred_ocr_generation.store(0, Ordering::Release);
self.scroll_input_shared_state.set_enabled(false);
self.scroll_input_shared_state.set_event_waker(None);
self.scroll_input_shared_state.clear();
}

#[cfg(target_os = "macos")]
fn note_capture_start_failure_for_prewarm(&mut self) {
self.overlay_session_prewarm_requested = true;
}

#[cfg(not(target_os = "macos"))]
fn note_capture_start_failure_for_prewarm(&mut self) {}

#[cfg(target_os = "macos")]
fn take_overlay_session_for_capture_start(&mut self) -> (&'static str, OverlaySession) {
if let Some(overlay_session) = self.prewarmed_overlay_session.take() {
Expand Down Expand Up @@ -650,22 +686,6 @@ impl App {
let _ = overlay_proxy.send_event(UserEvent::OverlayWorkerResponse);
}
}));
overlay_session.set_native_capture_input_waker(Arc::new({
let overlay_proxy = self.overlay_proxy.clone();
let native_input_pending =
Arc::clone(&self.overlay_native_capture_input_event_pending);

move || {
if native_input_pending
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
.is_ok() && overlay_proxy
.send_event(UserEvent::OverlayNativeCaptureInput)
.is_err()
{
native_input_pending.store(false, Ordering::Release);
}
}
}));
overlay_session.set_external_scroll_input_drain_reader(Arc::new({
let shared_state = Arc::clone(&self.scroll_input_shared_state);

Expand Down Expand Up @@ -709,19 +729,22 @@ impl App {
}

pub(super) fn end_overlay_session(&mut self, exit: OverlayExit) {
let Some(_session) = self.overlay_session.take() else {
if self.overlay_session.is_none() {
return;
};
}

#[cfg(target_os = "macos")]
self.overlay_native_capture_input_event_pending.store(false, Ordering::Release);
#[cfg(target_os = "macos")]
{
self.teardown_overlay_capture_host();
self.unregister_overlay_cancel_hotkey();
self.unregister_overlay_loupe_hotkey();
self.unregister_overlay_frozen_hotkeys();
}

let Some(_session) = self.overlay_session.take() else {
return;
};

#[cfg(target_os = "macos")]
{
self.prewarmed_overlay_session = None;
Expand Down Expand Up @@ -936,6 +959,8 @@ impl App {

#[cfg(target_os = "macos")]
self.sync_overlay_hotkey_registrations();
#[cfg(target_os = "macos")]
self.sync_overlay_capture_host();
}
}

Expand Down
38 changes: 38 additions & 0 deletions apps/rsnap/src/app/capture_host_macos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use std::sync::Arc;

use crate::app::{App, UserEvent};
use rsnap_overlay::{MacOSCaptureHost, OverlayExit};

impl App {
pub(super) fn build_overlay_capture_host(&self) -> MacOSCaptureHost {
let overlay_proxy = self.overlay_proxy.clone();
let generation = self.overlay_session_generation;

MacOSCaptureHost::new(Arc::new(move |event| {
let _ =
overlay_proxy.send_event(UserEvent::OverlayNativeCaptureInput(generation, event));
Comment thread
yvette-carlisle marked this conversation as resolved.
}))
}

pub(super) fn sync_overlay_capture_host(&mut self) {
let sync_result = match (self.overlay_session.as_mut(), self.overlay_capture_host.as_mut())
{
(Some(session), Some(host)) => session.sync_macos_capture_host(host),
_ => return,
};

if let Err(err) = sync_result {
self.end_overlay_session(OverlayExit::Error(err));
}
}

pub(super) fn teardown_overlay_capture_host(&mut self) {
if let (Some(session), Some(host)) =
(self.overlay_session.as_mut(), self.overlay_capture_host.as_mut())
{
session.teardown_macos_capture_host(host);
}

self.overlay_capture_host = None;
}
}
12 changes: 8 additions & 4 deletions apps/rsnap/src/app/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::VecDeque;
#[cfg(target_os = "macos")]
use std::sync::{Arc, atomic::Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};

use color_eyre::eyre;
Expand Down Expand Up @@ -53,6 +53,8 @@ impl ApplicationHandler<UserEvent> for App {
&& let Err(err) = session.finish_startup_aux_window_creation(event_loop)
{
self.end_overlay_session(OverlayExit::Error(err));
} else {
self.sync_overlay_capture_host();
}
},
#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -82,11 +84,13 @@ impl ApplicationHandler<UserEvent> for App {
}
},
#[cfg(target_os = "macos")]
UserEvent::OverlayNativeCaptureInput => {
self.overlay_native_capture_input_event_pending.store(false, Ordering::Release);
UserEvent::OverlayNativeCaptureInput(generation, event) => {
if generation != self.overlay_session_generation {
return;
}

if let Some(session) = self.overlay_session.as_mut() {
let control = session.handle_native_capture_input_ready();
let control = session.handle_native_capture_input_event(event);

self.handle_overlay_control(control);
}
Expand Down
23 changes: 13 additions & 10 deletions apps/rsnap/src/settings_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ use egui_wgpu::Renderer;
use global_hotkey::hotkey::HotKey;
use wgpu::Surface;
use wgpu::SurfaceConfiguration;
use winit::event::ElementState;
use winit::event::WindowEvent;
use winit::event::{ElementState, KeyEvent, WindowEvent};
use winit::event_loop::ActiveEventLoop;
use winit::keyboard::ModifiersState;
use winit::window::Theme;
Expand Down Expand Up @@ -228,19 +227,15 @@ impl SettingsWindow {

self.window.request_redraw();
},
WindowEvent::KeyboardInput { event, .. } if self.capture_hotkey_recording => {
if event.state == ElementState::Pressed {
self.handle_capture_hotkey_recording_input(event);
}
WindowEvent::KeyboardInput { event, .. } if self.should_record_hotkey(event) => {
self.handle_capture_hotkey_recording_input(event);
},
WindowEvent::ThemeChanged(_) => {
// Follow system theme changes when ThemeMode::System is active.
self.window.request_redraw();
},
WindowEvent::KeyboardInput { event, .. } => {
if platform::should_close_from_keyboard(self.modifiers, event) {
return SettingsControl::CloseRequested;
}
WindowEvent::KeyboardInput { event, .. } if self.should_close_from_keyboard(event) => {
return SettingsControl::CloseRequested;
},
WindowEvent::Resized(size) => self.resize(*size),
WindowEvent::ScaleFactorChanged { .. } => self.resize(self.window.inner_size()),
Expand All @@ -254,6 +249,14 @@ impl SettingsWindow {
SettingsControl::Continue
}

fn should_record_hotkey(&self, event: &KeyEvent) -> bool {
self.capture_hotkey_recording && event.state == ElementState::Pressed
}

fn should_close_from_keyboard(&self, event: &KeyEvent) -> bool {
platform::should_close_from_keyboard(self.modifiers, event)
}

pub fn drain_actions(&mut self) -> VecDeque<SettingsWindowAction> {
mem::take(&mut self.action_queue)
}
Expand Down
7 changes: 6 additions & 1 deletion packages/rsnap-overlay/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ pub use crate::deferred_text_recognition::{
};
pub use crate::overlay::{
AltActivationMode, FrozenGlobalHotkey, HudAnchor, OutputNaming, OverlayConfig, OverlayControl,
OverlayExit, OverlaySession, ThemeMode, ToolbarPlacement, WindowCaptureAlphaMode,
OverlayExit, OverlayKeyboardInputEvent, OverlaySession, ThemeMode, ToolbarPlacement,
WindowCaptureAlphaMode,
};
#[cfg(target_os = "macos")]
pub use crate::overlay::{
MacOSCaptureHost, MacOSNativeCaptureInputEvent, MacOSNativeCaptureScrollDelta,
};
pub use crate::state::{
GlobalPoint, LiveCursorSample, MonitorImageSnapshot, MonitorRect, RectPoints, Rgb, WindowHit,
Expand Down
Loading
Loading