#![cfg(feature = "events")]
use lighty_event::{Event, EventBus, InstanceWindowAppearedEvent};
use crate::instance::INSTANCE_MANAGER;
pub(crate) async fn detect_window_appearance(
pid: u32,
instance_name: String,
version: String,
event_bus: EventBus,
) {
#[cfg(windows)]
{
use std::time::Duration;
let max_attempts = 300;
let check_interval = Duration::from_millis(100);
for _ in 0..max_attempts {
if !INSTANCE_MANAGER.is_alive(pid) {
lighty_core::trace_debug!(
"[Launch] Window watcher aborted: PID {} exited",
pid
);
return;
}
if has_visible_window(pid) {
lighty_core::trace_info!("[Launch] Window appeared for PID: {}", pid);
event_bus.emit(Event::InstanceWindowAppeared(InstanceWindowAppearedEvent {
pid,
instance_name,
version,
timestamp: std::time::SystemTime::now(),
}));
return;
}
tokio::time::sleep(check_interval).await;
}
lighty_core::trace_warn!("[Launch] Window detection timed out for PID: {}", pid);
}
#[cfg(not(windows))]
{
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
if !INSTANCE_MANAGER.is_alive(pid) {
lighty_core::trace_debug!(
"[Launch] Window watcher aborted: PID {} exited",
pid
);
return;
}
lighty_core::trace_info!(
"[Launch] Assuming window appeared for PID: {} (non-Windows platform)",
pid
);
event_bus.emit(Event::InstanceWindowAppeared(InstanceWindowAppearedEvent {
pid,
instance_name,
version,
timestamp: std::time::SystemTime::now(),
}));
}
}
#[cfg(windows)]
fn has_visible_window(pid: u32) -> bool {
use windows::Win32::Foundation::{BOOL, HWND, LPARAM};
use windows::Win32::UI::WindowsAndMessaging::{
EnumWindows, GetWindowThreadProcessId, IsWindowVisible,
};
struct EnumData {
target_pid: u32,
found: bool,
}
unsafe extern "system" fn enum_window_callback(hwnd: HWND, lparam: LPARAM) -> BOOL {
let data = &mut *(lparam.0 as *mut EnumData);
if IsWindowVisible(hwnd).as_bool() {
let mut window_pid: u32 = 0;
GetWindowThreadProcessId(hwnd, Some(&mut window_pid));
if window_pid == data.target_pid {
data.found = true;
return BOOL(0); }
}
BOOL(1) }
let mut data = EnumData {
target_pid: pid,
found: false,
};
unsafe {
let _ = EnumWindows(
Some(enum_window_callback),
LPARAM(&mut data as *mut _ as isize),
);
}
data.found
}