focus_tracker/
focus_tracker.rs

1use 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    /// Async version of track_focus - requires the "async" feature
56    #[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    /// Async version of track_focus_with_stop - requires the "async" feature
68    #[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    /// Subscribe to focus changes and receive them via a channel
84    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        // Clone the tracker for the background thread
89        let tracker = self.clone();
90
91        // Spawn a background thread to track focus changes
92        std::thread::spawn(move || {
93            let _ = tracker.track_focus_with_stop(
94                move |window: FocusedWindow| -> FocusTrackerResult<()> {
95                    if sender.send(window).is_err() {
96                        // Receiver has been dropped, stop tracking
97                        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}