use focus_tracker::{
FocusTracker, FocusTrackerConfig, FocusTrackerResult, FocusedWindow, IconConfig, IgnoreRule,
WindowTitleMatch,
};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
fn save_icon_to_file(
icon_data: &image::RgbaImage,
filename: &str,
) -> Result<(), Box<dyn std::error::Error>> {
icon_data.save(filename)?;
println!("💾 Icon saved: {}", filename);
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.init();
println!("🚀 Starting ADVANCED focus tracking example!");
println!(" This demo showcases all configuration options and features.");
println!(" Icons will be saved to examples/recorded_icons/");
println!(" Press Ctrl+C for graceful shutdown.");
println!();
let config = FocusTrackerConfig::builder()
.poll_interval(std::time::Duration::from_millis(50))?
.icon(IconConfig::builder().size(64)?.build())
.windows_ignore_rules([
IgnoreRule::builder()
.process_name("Explorer.EXE")
.window_title(WindowTitleMatch::Exact("Task Switching".into()))
.build(),
IgnoreRule::builder()
.process_name("Explorer.EXE")
.window_title(WindowTitleMatch::Missing)
.build(),
])
.build();
println!("⚙️ Configuration:");
println!(" Poll interval: {:?}", config.poll_interval);
println!(
" Icon size: {}x{}",
config.icon.get_size_or_default(),
config.icon.get_size_or_default()
);
println!();
let tracker = FocusTracker::builder().config(config).build();
let stop_signal = Arc::new(AtomicBool::new(false));
let stop_signal_clone = stop_signal.clone();
ctrlc::set_handler(move || {
println!("\n🛑 Interrupt signal received, initiating graceful shutdown...");
stop_signal_clone.store(true, Ordering::SeqCst);
})?;
let mut event_count = 0u64;
let mut icons_saved = 0u64;
let mut unique_processes = std::collections::HashSet::new();
let start_time = std::time::Instant::now();
println!("🎯 Focus tracking active! Switch between applications...");
println!();
let result = tracker
.track_focus()
.on_focus(|window: FocusedWindow| {
event_count += 1;
let count = event_count;
let window_title = window
.window_title
.as_deref()
.unwrap_or("Unknown")
.to_string();
let process_name = window.process_name.clone();
unique_processes.insert(process_name.clone());
let icon_result: FocusTrackerResult<()> = {
println!("🔄 Focus Event #{}", count);
println!(" 📋 Title: {}", window_title);
println!(
" ⚙️ Process: {} (PID: {:?})",
process_name, window.process_id
);
if let Some(icon) = &window.icon {
let (width, height) = (icon.width(), icon.height());
println!(" 🖼️ Icon: {}x{} pixels", width, height);
icons_saved += 1;
let saved = icons_saved;
let filename = format!(
"examples/recorded_icons/advanced_{:03}_{}.png",
saved,
process_name.replace("/", "_").replace(" ", "_")
);
match save_icon_to_file(icon, &filename) {
Ok(_) => println!(" ✅ Icon saved successfully"),
Err(e) => println!(" ❌ Failed to save icon: {}", e),
}
} else {
println!(" 🚫 No icon available");
}
println!(" ⏱️ Uptime: {:?}", start_time.elapsed());
println!();
Ok(())
};
async move { icon_result }
})
.stop_signal(&stop_signal)
.call()
.await;
match result {
Ok(_) => println!("✅ Focus tracking completed successfully"),
Err(e) => println!("❌ Focus tracking error: {}", e),
}
println!();
println!("📊 SESSION STATISTICS:");
println!(" Total events: {}", event_count);
println!(" Icons saved: {}", icons_saved);
println!(" Unique processes: {}", unique_processes.len());
println!(" Session duration: {:?}", start_time.elapsed());
println!(
" Average events/min: {:.1}",
event_count as f64 / start_time.elapsed().as_secs_f64() * 60.0
);
if !unique_processes.is_empty() {
println!(" Processes seen:");
for (i, process) in unique_processes.iter().enumerate() {
println!(" {}. {}", i + 1, process);
}
}
println!();
println!("🎉 Advanced example completed!");
println!(" Check examples/recorded_icons/ for saved icons");
Ok(())
}