focus_tracker/
focus_tracker.rs1use crate::{
2 FocusTrackerConfig, FocusTrackerResult, FocusedWindow,
3 platform::impl_focus_tracker::ImplFocusTracker,
4};
5use std::sync::{atomic::AtomicBool, mpsc};
6
7#[cfg(feature = "async")]
8use std::future::Future;
9
10#[derive(Debug, Clone)]
11pub struct FocusTracker {
12 impl_focus_tracker: ImplFocusTracker,
13 config: FocusTrackerConfig,
14}
15
16impl FocusTracker {
17 pub fn new() -> Self {
18 Self::with_config(FocusTrackerConfig::default())
19 }
20
21 pub fn with_config(config: FocusTrackerConfig) -> Self {
22 Self {
23 impl_focus_tracker: ImplFocusTracker::new(),
24 config,
25 }
26 }
27}
28
29impl Default for FocusTracker {
30 fn default() -> Self {
31 Self::new()
32 }
33}
34
35impl FocusTracker {
36 pub fn track_focus<F>(&self, on_focus: F) -> FocusTrackerResult<()>
37 where
38 F: FnMut(FocusedWindow) -> FocusTrackerResult<()>,
39 {
40 self.impl_focus_tracker.track_focus(on_focus, &self.config)
41 }
42
43 pub fn track_focus_with_stop<F>(
44 &self,
45 on_focus: F,
46 stop_signal: &AtomicBool,
47 ) -> FocusTrackerResult<()>
48 where
49 F: FnMut(FocusedWindow) -> FocusTrackerResult<()>,
50 {
51 self.impl_focus_tracker
52 .track_focus_with_stop(on_focus, stop_signal, &self.config)
53 }
54
55 #[cfg(feature = "async")]
57 pub async fn track_focus_async<F, Fut>(&self, on_focus: F) -> FocusTrackerResult<()>
58 where
59 F: FnMut(FocusedWindow) -> Fut,
60 Fut: Future<Output = FocusTrackerResult<()>>,
61 {
62 self.impl_focus_tracker
63 .track_focus_async(on_focus, &self.config)
64 .await
65 }
66
67 #[cfg(feature = "async")]
69 pub async fn track_focus_async_with_stop<F, Fut>(
70 &self,
71 on_focus: F,
72 stop_signal: &AtomicBool,
73 ) -> FocusTrackerResult<()>
74 where
75 F: FnMut(FocusedWindow) -> Fut,
76 Fut: Future<Output = FocusTrackerResult<()>>,
77 {
78 self.impl_focus_tracker
79 .track_focus_async_with_stop(on_focus, stop_signal, &self.config)
80 .await
81 }
82
83 pub fn subscribe_focus_changes(&self) -> FocusTrackerResult<mpsc::Receiver<FocusedWindow>> {
85 let (sender, receiver) = mpsc::channel();
86 let stop_signal = AtomicBool::new(false);
87
88 let tracker = self.clone();
90
91 std::thread::spawn(move || {
93 let _ = tracker.track_focus_with_stop(
94 move |window: FocusedWindow| -> FocusTrackerResult<()> {
95 if sender.send(window).is_err() {
96 return Err(crate::FocusTrackerError::Error(
98 "Receiver dropped".to_string(),
99 ));
100 }
101 Ok(())
102 },
103 &stop_signal,
104 );
105 });
106
107 Ok(receiver)
108 }
109}