diff --git a/packages/desktop/src/providers/focused_window/focused_window_provider.rs b/packages/desktop/src/providers/focused_window/focused_window_provider.rs index d241b76d..035764b9 100644 --- a/packages/desktop/src/providers/focused_window/focused_window_provider.rs +++ b/packages/desktop/src/providers/focused_window/focused_window_provider.rs @@ -1,13 +1,9 @@ -use std::{ffi::c_void, io::Cursor, sync::OnceLock}; +use std::{ffi::c_void, io::Cursor}; use async_trait::async_trait; use base64::{prelude::BASE64_STANDARD, Engine as _}; use image::{ImageBuffer, ImageFormat, Rgba}; use serde::{Deserialize, Serialize}; -use tokio::{ - sync::mpsc::{self, Sender}, - task, -}; use windows::{ core::{Error, Interface, HSTRING, PWSTR}, Win32::{ @@ -40,12 +36,11 @@ use windows::{ }, }; -use crate::providers::{Provider, ProviderOutput, ProviderResult}; - -static PROVIDER_TX: OnceLock> = - OnceLock::new(); +use crate::providers::{ + CommonProviderState, Provider, ProviderEmitter, RuntimeType, +}; -// This doesn't always work.. +// This doesn't always work.. const ICON_SIZE: i32 = 32; #[derive(Deserialize, Debug)] @@ -60,31 +55,15 @@ pub struct FocusedWindowOutput { } pub struct FocusedWindowProvider { - _config: FocusedWindowProviderConfig, -} - -#[async_trait] -impl Provider for FocusedWindowProvider { - async fn run(&self, emit_result_tx: Sender) { - PROVIDER_TX - .set(emit_result_tx.clone()) - .expect("Error setting provider tx in focused window provider"); - - task::spawn_blocking(move || { - if let Err(err) = Self::create_focused_window_hook() { - emit_result_tx - .blocking_send(Err(err).into()) - .expect("Error with focused window provider"); - } - }); - } + common: CommonProviderState, } impl FocusedWindowProvider { pub fn new( - config: FocusedWindowProviderConfig, + _config: FocusedWindowProviderConfig, + common: CommonProviderState, ) -> FocusedWindowProvider { - FocusedWindowProvider { _config: config } + FocusedWindowProvider { common } } unsafe fn get_foreground_window_icon( @@ -287,30 +266,34 @@ impl FocusedWindowProvider { Some(BASE64_STANDARD.encode(&png_data)) } - unsafe fn emit_window_info(hwnd: HWND) { + unsafe fn emit_window_info(hwnd: HWND, emitter: &ProviderEmitter) { + println!("Emitting window info"); if !IsWindow(hwnd).as_bool() { return; } + let output = Self::focused_window_output(hwnd); + emitter.emit_output(output); + } + unsafe fn focused_window_output( + hwnd: HWND, + ) -> anyhow::Result { if let Some(title) = Self::get_foreground_window_title(hwnd) { if title.trim().is_empty() { - return; + return Err(anyhow::Error::msg("Empty title")); } if let Ok(icon) = Self::get_foreground_window_icon(hwnd) { - if let Some(tx) = PROVIDER_TX.get() { - let output = FocusedWindowOutput { title, icon }; - if let Err(err) = tx.blocking_send( - Ok(ProviderOutput::FocusedWindow(output)).into(), - ) { - println!("Error sending result: {:?}", err); - } - } + Ok(FocusedWindowOutput { title, icon }) + } else { + Err(anyhow::Error::msg("Failed to extract icon")) } + } else { + Err(anyhow::Error::msg("Failed to get window title")) } } - fn create_focused_window_hook() -> anyhow::Result<()> { + fn create_focused_window_hook(&self) -> anyhow::Result<()> { unsafe { let focus_hook = SetWinEventHook( EVENT_SYSTEM_FOREGROUND, @@ -352,21 +335,15 @@ impl FocusedWindowProvider { WINEVENT_OUTOFCONTEXT, ); - if focus_hook.is_invalid() - || title_hook.is_invalid() - || create_hook.is_invalid() - || switch_hook.is_invalid() - { + if focus_hook.is_invalid() || title_hook.is_invalid() { return Err(anyhow::Error::msg("Failed to set event hooks")); } // Initialize with current foreground window if let Some(current_hwnd) = Some(GetForegroundWindow()) { - Self::emit_window_info(current_hwnd); + Self::emit_window_info(current_hwnd, &self.common.emitter); } - println!("Monitoring window focus, creation, and title changes..."); - let mut msg = MSG::default(); while GetMessageW(&mut msg, HWND::default(), 0, 0).as_bool() { let _ = TranslateMessage(&msg); @@ -390,26 +367,25 @@ unsafe extern "system" fn win_event_proc( if !IsWindow(hwnd).as_bool() { return; } - match event { EVENT_SYSTEM_FOREGROUND => { - FocusedWindowProvider::emit_window_info(hwnd); + FocusedWindowProvider::emit_window_info(hwnd, emitter); } EVENT_OBJECT_CREATE => { let foreground = GetForegroundWindow(); if hwnd == foreground { - FocusedWindowProvider::emit_window_info(hwnd); + FocusedWindowProvider::emit_window_info(hwnd, emitter); } } EVENT_OBJECT_NAMECHANGE => { if id_object == 0 && hwnd == GetForegroundWindow() { - FocusedWindowProvider::emit_window_info(hwnd); + FocusedWindowProvider::emit_window_info(hwnd, emitter); } } EVENT_SYSTEM_SWITCHSTART => { - let foreground = GetForegroundWindow(); - if !foreground.is_invalid() { - FocusedWindowProvider::emit_window_info(foreground); + let hwnd = GetForegroundWindow(); + if !hwnd.is_invalid() { + FocusedWindowProvider::emit_window_info(hwnd, emitter); } } _ => {} @@ -448,3 +424,19 @@ unsafe extern "system" fn enum_child_proc( } BOOL(1) } + +#[async_trait] +impl Provider for FocusedWindowProvider { + fn runtime_type(&self) -> RuntimeType { + RuntimeType::Sync + } + + fn start_sync(&mut self) { + if let Err(err) = self.create_focused_window_hook() { + self + .common + .emitter + .emit_output::(Err(err)); + } + } +} diff --git a/packages/desktop/src/providers/provider_manager.rs b/packages/desktop/src/providers/provider_manager.rs index 67aa541d..e888f218 100644 --- a/packages/desktop/src/providers/provider_manager.rs +++ b/packages/desktop/src/providers/provider_manager.rs @@ -11,8 +11,9 @@ use tracing::info; #[cfg(windows)] use super::{ - audio::AudioProvider, keyboard::KeyboardProvider, - komorebi::KomorebiProvider, media::MediaProvider, + audio::AudioProvider, focused_window::FocusedWindowProvider, + keyboard::KeyboardProvider, komorebi::KomorebiProvider, + media::MediaProvider, }; use super::{ battery::BatteryProvider, cpu::CpuProvider, disk::DiskProvider, @@ -227,6 +228,10 @@ impl ProviderManager { ProviderConfig::Cpu(config) => { Box::new(CpuProvider::new(config, common)) } + #[cfg(windows)] + ProviderConfig::FocusedWindow(config) => { + Box::new(FocusedWindowProvider::new(config, common)) + } ProviderConfig::Host(config) => { Box::new(HostProvider::new(config, common)) } diff --git a/packages/desktop/src/providers/provider_output.rs b/packages/desktop/src/providers/provider_output.rs index 6aeb3d02..da772c01 100644 --- a/packages/desktop/src/providers/provider_output.rs +++ b/packages/desktop/src/providers/provider_output.rs @@ -2,13 +2,12 @@ use serde::Serialize; #[cfg(windows)] use super::{ - audio::AudioOutput, keyboard::KeyboardOutput, komorebi::KomorebiOutput, - media::MediaOutput, + audio::AudioOutput, focused_window::FocusedWindowOutput, + keyboard::KeyboardOutput, komorebi::KomorebiOutput, media::MediaOutput, }; use super::{ battery::BatteryOutput, cpu::CpuOutput, disk::DiskOutput, - - focused_window::FocusedWindowOutput, host::HostOutput, ip::IpOutput, memory::MemoryOutput, + host::HostOutput, ip::IpOutput, memory::MemoryOutput, network::NetworkOutput, weather::WeatherOutput, }; @@ -32,6 +31,7 @@ pub enum ProviderOutput { Audio(AudioOutput), Battery(BatteryOutput), Cpu(CpuOutput), + #[cfg(windows)] FocusedWindow(FocusedWindowOutput), Host(HostOutput), Ip(IpOutput), @@ -61,6 +61,7 @@ impl_provider_output! { #[cfg(windows)] impl_provider_output! { Audio(AudioOutput), + FocusedWindow(FocusedWindowOutput), Komorebi(KomorebiOutput), Media(MediaOutput), Keyboard(KeyboardOutput)