use std::sync::{Arc, RwLock};
use log::{debug, trace};
use crate::error::WinshiftError;
#[cfg(target_os = "linux")]
use crate::linux::HookStopHandle as PlatformStopHandle;
#[cfg(target_os = "macos")]
use crate::macos::HookStopHandle as PlatformStopHandle;
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
#[derive(Clone, Default)]
struct PlatformStopHandle;
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
impl PlatformStopHandle {
fn stop(&self) -> Result<(), WinshiftError> {
Err(WinshiftError::Platform(
"Unsupported platform: stop not implemented".to_string(),
))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MonitoringMode {
Combined,
AppOnly,
WindowOnly,
}
impl Default for MonitoringMode {
fn default() -> Self {
Self::Combined
}
}
pub trait FocusChangeHandler: Send + Sync {
fn on_app_change(&self, pid: i32, app_name: String);
fn on_window_change(&self, window_title: String);
#[cfg(target_os = "macos")]
fn on_app_change_info(&self, _info: crate::ActiveWindowInfo) {}
#[cfg(target_os = "macos")]
fn on_window_change_info(&self, _info: crate::ActiveWindowInfo) {}
}
#[derive(Debug, Clone, Default)]
pub struct WindowHookConfig {
pub monitoring_mode: MonitoringMode,
pub embed_active_info: bool,
}
pub struct WindowFocusHook {
handler: Arc<RwLock<dyn FocusChangeHandler>>,
config: WindowHookConfig,
stop_handle: PlatformStopHandle,
}
impl WindowFocusHook {
pub fn new<H: FocusChangeHandler + 'static>(handler: H) -> Self {
debug!("Creating new WindowFocusHook");
Self {
handler: Arc::new(RwLock::new(handler)),
config: WindowHookConfig::default(),
stop_handle: PlatformStopHandle::default(),
}
}
pub fn with_config<H: FocusChangeHandler + 'static>(
handler: H,
config: WindowHookConfig,
) -> Self {
debug!(
"Creating new WindowFocusHook with custom config: {:?}",
config
);
Self {
handler: Arc::new(RwLock::new(handler)),
config,
stop_handle: PlatformStopHandle::default(),
}
}
pub fn app_only<H: FocusChangeHandler + 'static>(handler: H) -> Self {
let config = WindowHookConfig {
monitoring_mode: MonitoringMode::AppOnly,
embed_active_info: false,
};
Self::with_config(handler, config)
}
pub fn window_only<H: FocusChangeHandler + 'static>(handler: H) -> Self {
let config = WindowHookConfig {
monitoring_mode: MonitoringMode::WindowOnly,
embed_active_info: false,
};
Self::with_config(handler, config)
}
pub fn run(&self) -> Result<(), WinshiftError> {
debug!("Running WindowFocusHook");
#[cfg(target_os = "windows")]
{
trace!("Running on Windows platform");
crate::windows::run_hook_with_config(self.handler.clone(), &self.config)
}
#[cfg(target_os = "linux")]
{
trace!("Running on Linux platform");
crate::linux::run_hook_with_config(
self.handler.clone(),
&self.config,
self.stop_handle.clone(),
)
}
#[cfg(target_os = "macos")]
{
trace!("Running on macOS platform");
crate::macos::run_hook_with_config(
self.handler.clone(),
&self.config,
self.stop_handle.clone(),
)
}
#[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
{
error!("Unsupported platform");
Err(WinshiftError::Platform("Unsupported platform".to_string()))
}
}
pub fn stop(&self) -> Result<(), WinshiftError> {
debug!("Stopping WindowFocusHook instance");
self.stop_handle.stop()
}
}