window_observer/
lib.rs

1#![doc = include_str!("../README.md")]
2
3pub use window_getter;
4
5pub mod platform_impl;
6pub mod window;
7
8pub use ::tokio;
9pub use window::{Position, Size, Window};
10
11use crate::platform_impl::PlatformWindowObserver;
12
13/// Represents errors that can occur in the library.
14#[non_exhaustive]
15#[derive(Debug, thiserror::Error)]
16pub enum Error {
17    /// The process ID is invalid for observing windows.
18    ///
19    /// # Platform-specific
20    /// - **Windows:** This occurs when the process ID is zero.
21    /// - **macOS:** This does not occur on macOS.
22    #[error("The process ID is invalid: {0}")]
23    InvalidProcessId(u32),
24    /// This occurs when the application is not ready yet.
25    /// This also occurs when the application that has given PID is not found.
26    ///
27    /// # Platform-specific
28    /// - **Windows:** This does not occur on windows.
29    #[error("Something went wrong")]
30    SomethingWentWrong,
31    /// The application does not support observing window events.
32    ///
33    /// # Platform-specific
34    /// - **Windows:** This does not occur on windows.
35    #[error("The application does not support observing window")]
36    NotSupported,
37    /// Permission denied error. This error only occurs on macOS.
38    #[error("Permission denied.")]
39    PermissionDenied,
40    /// A platform-specific error occurred.
41    #[error("A platform-specific error occurred: {0:?}")]
42    PlatformSpecificError(#[from] platform_impl::PlatformError),
43}
44
45/// Represents a filter for window events.
46#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
47pub struct EventFilter {
48    /// Whether to observe [`Event::Foregrounded`] events.
49    pub foregrounded: bool,
50    /// Whether to observe [`Event::Backgrounded`] events.
51    pub backgrounded: bool,
52    /// Whether to observe [`Event::Focused`] events.
53    pub focused: bool,
54    /// Whether to observe [`Event::Unfocused`] events.
55    pub unfocused: bool,
56    /// Whether to observe [`Event::Created`] events.
57    pub created: bool,
58    /// Whether to observe [`Event::Resized`] events.
59    pub resized: bool,
60    /// Whether to observe [`Event::Moved`] events.
61    pub moved: bool,
62    /// Whether to observe [`Event::Hidden`] events.
63    pub hidden: bool,
64    /// Whether to observe [`Event::Showed`] events.
65    pub showed: bool,
66    /// Whether to observe [`Event::Closed`] events.
67    pub closed: bool,
68}
69
70impl EventFilter {
71    /// Creates a new `EventFilter` with all events enabled.
72    pub fn all() -> Self {
73        Self {
74            foregrounded: true,
75            backgrounded: true,
76            focused: true,
77            unfocused: true,
78            created: true,
79            resized: true,
80            moved: true,
81            hidden: true,
82            showed: true,
83            closed: true,
84        }
85    }
86
87    /// Creates a new `EventFilter` with no events enabled.
88    pub fn empty() -> Self {
89        Default::default()
90    }
91
92    pub(crate) fn should_dispatch(&self, event: &Event) -> bool {
93        matches!(event, Event::Foregrounded) && self.foregrounded
94            || matches!(event, Event::Backgrounded) && self.backgrounded
95            || matches!(event, Event::Focused) && self.focused
96            || matches!(event, Event::Unfocused) && self.unfocused
97            || matches!(event, Event::Created) && self.created
98            || matches!(event, Event::Resized) && self.resized
99            || matches!(event, Event::Moved) && self.moved
100            || matches!(event, Event::Hidden) && self.hidden
101            || matches!(event, Event::Showed) && self.showed
102            || matches!(event, Event::Closed { .. }) && self.closed
103    }
104}
105
106/// Represents events that can be observed on a window.
107#[non_exhaustive]
108#[derive(Debug, Clone, PartialEq)]
109pub enum Event {
110    /// The window was created.
111    Created,
112    /// The window was resized.
113    Resized,
114    /// The window was moved.
115    Moved,
116    /// The window was brought to the foreground.
117    /// This event does not mean the window has gained input focus.
118    Foregrounded,
119    /// The window was backgrounded. It is opposite of [`Event::Foregrounded`].
120    Backgrounded,
121    /// The window was focused.
122    ///
123    /// # Platform-specific
124    /// - **Windows:** This event is same as [`Event::Foregrounded`].
125    ///   So this event and `Foregrounded` event are always dispatched together.
126    /// - **macOS:** On macOS, a window does not lose focus even when miniaturized.
127    ///   Therefore, this event will not be dispatched when the window is deminiaturized.
128    Focused,
129    /// The window was unfocused.
130    ///
131    /// # Platform-specific
132    /// - **Windows:** This event is same as [`Event::Backgrounded`].
133    ///   So this event and `Backgrounded` event are always dispatched together.
134    /// - **macOS:** On macOS, a window does not lose focus even when miniaturized.
135    ///   Therefore, this event will not be dispatched when the window is miniaturized
136    Unfocused,
137    /// The window was hidden.
138    Hidden,
139    /// The window was showed.
140    Showed,
141    /// The window was closed.
142    Closed { window_id: window_getter::WindowId },
143}
144
145/// Represents a window that may or may not be available.
146#[derive(Debug, Clone, PartialEq)]
147pub enum MaybeWindowAvailable {
148    /// The window is available.
149    Available { window: Window, event: Event },
150    /// The window is not available.
151    /// This can happen when the window is closed.
152    NotAvailable { event: Event },
153}
154
155/// A type alias for the result of an event.
156/// `Err` means that the event could not be processed, and `Ok` contains the event.
157pub type EventResult = Result<MaybeWindowAvailable, platform_impl::PlatformError>;
158/// A type alias for the window event transmission channel.
159pub type EventTx = tokio::sync::mpsc::UnboundedSender<EventResult>;
160/// A type alias for the window event reception channel.
161pub type EventRx = tokio::sync::mpsc::UnboundedReceiver<EventResult>;
162
163/// Observes window events.
164pub struct WindowObserver(PlatformWindowObserver);
165
166impl WindowObserver {
167    /// Creates a new [`WindowObserver`] for a given process ID and event channel
168    /// and start the observer.
169    pub async fn start(
170        pid: u32,
171        event_tx: EventTx,
172        event_filter: EventFilter,
173    ) -> Result<Self, Error> {
174        #[cfg(target_os = "macos")]
175        let pid = pid as i32;
176
177        Ok(Self(
178            PlatformWindowObserver::start(pid, event_tx, event_filter).await?,
179        ))
180    }
181
182    /// Stops the observer and cleans up resources.
183    ///
184    /// # Notes
185    /// If you don't call this method, the observer will continue to run until droped.
186    ///
187    /// # Platform-specific
188    /// - **macOS:** It will always return [`Ok`].
189    pub async fn stop(self) -> Result<(), Error> {
190        #[cfg(target_os = "macos")]
191        self.0.stop().await;
192        #[cfg(target_os = "windows")]
193        self.0.stop().await?;
194
195        Ok(())
196    }
197
198    /// Returns underlying platform-specific observer.
199    pub fn inner(&self) -> &PlatformWindowObserver {
200        &self.0
201    }
202}