mod callbacks; mod config; mod input; mod timers; use crate::callbacks::register_callbacks; use crate::config::Config; use crate::timers::register_timers; use anyhow::Context; use i_slint_core::model::VecModel; use magick_rust::magick_wand_genesis; use slint::ModelRc; use std::rc::Rc; use std::sync::Once; slint::include_modules!(); static START: Once = Once::new(); use log::{debug, error, info}; use pretty_env_logger::env_logger::Target; #[cfg(debug_assertions)] fn start_debug_greetd_stub() { use libgreetd_stub::SessionOptions; let opts = SessionOptions { username: { std::env::var("CKGREETER_STUB_USER") .unwrap_or_else(|_| "debug-user".to_string()) }, password: std::env::var("CKGREETER_STUB_PASSWORD") .unwrap_or_else(|_| "debug-password".to_string()), mfa: false, }; debug!(target: "ckgreeter::init_greetd_stub", "Using username: {}", opts.username); debug!(target: "ckgreeter::init_greetd_stub", "Using password: {}", opts.password); debug!(target: "ckgreeter::init_greetd_stub", "Using MFA: {}", opts.mfa); let socket_path = std::env::var("CKGREETER_STUB_SOCKET") .unwrap_or_else(|_| "/tmp/greetd-stub.sock".to_string()); debug!(target: "ckgreeter::init_greetd_stub", "Using socket path: {}", socket_path); let stub_socket_path = socket_path.clone(); let _stub_task = tokio::task::spawn(async move { libgreetd_stub::start(&stub_socket_path, &opts).await }); debug!(target: "ckgreeter::init_greetd_stub", "Stub started"); debug!(target: "ckgreeter::init_greetd_stub", "GREETD_SOCK set to {}", socket_path); unsafe {std::env::set_var("GREETD_SOCK", socket_path)}; } #[tokio::main] async fn main() -> anyhow::Result<()> { #[cfg(debug_assertions)] pretty_env_logger::formatted_timed_builder() .target(Target::Stdout) .parse_filters("ckgreeter=debug") .parse_filters(std::env::var("RUST_LOG").unwrap_or_else(|_| "".to_string()).as_str()) .init(); #[cfg(not(debug_assertions))] pretty_env_logger::formatted_timed_builder() .target(Target::Stdout) .parse_filters("ckgreeter=info") .init(); info!(target: "ckgreeter::init", "Initializing..."); START.call_once(|| { magick_wand_genesis(); }); info!(target: "ckgreeter::init", "ImageMagick initialized"); #[cfg(debug_assertions)] { start_debug_greetd_stub(); info!(target: "ckgreeter::init", "Debug greetd stub started"); } const CONFIG_PATH: &str = "/etc/ckgreeter/config.toml"; let config_path = std::env::var("CKGREETER_CONFIG").unwrap_or_else(|_| CONFIG_PATH.to_string()); if !std::fs::exists(&config_path)? { error!(target: "ckgreeter::init", "Config file not found at {}", config_path); return Err(anyhow::anyhow!("Config file not found at {}", config_path)); } info!(target: "ckgreeter::init", "Loading config from {}", config_path); let config_data = std::fs::read(&config_path) .with_context(|| format!("Failed to read config file at {}", config_path))?; info!(target: "ckgreeter::init", "Config loaded"); let mut config: Config = toml::from_slice(&config_data) .with_context(|| format!("Failed to parse config file at {}", config_path))?; debug!(target: "ckgreeter::init", "Config parsed"); let display = GreeterDisplay::new()?; let data = display.global::(); let (tiles, default_tile) = config.get_tiles()?; let cache_dir = &config.background_cache_directory; info!(target: "ckgreeter::init", "Using cache directory: {}", cache_dir.display()); std::fs::create_dir_all(cache_dir) .with_context(|| format!("Failed to create cache directory: {}", cache_dir.display()))?; if tiles.len() == 0 { error!(target: "ckgreeter::init", "No tiles found in config"); return Err(anyhow::anyhow!("No tiles found in config")); } debug!(target: "ckgreeter::init", "Got tiles from config"); if let Some(default_tile) = default_tile { debug!(target: "ckgreeter::init", "Default tile: '{}', index: {}", tiles[default_tile].name, default_tile); data.set_selected_index(default_tile as i32); } let tiles = Rc::new(VecModel::from(tiles)); info!(target: "ckgreeter::init", "Registering callbacks and timers..."); register_callbacks(&display, &data, tiles.clone(), cache_dir.into(), &config); info!(target: "ckgreeter::init", "Callbacks registered"); let _timers = register_timers(&display, &data, &config); info!(target: "ckgreeter::init", "Timers registered"); match config.default_username { Some(username) => { display.set_default_username(username.into()); data.set_has_default_username(true); } None => { data.set_has_default_username(false); } } info!(target: "ckgreeter::init", "Setting up display..."); display.set_tiles(ModelRc::from(tiles)); debug!(target: "ckgreeter::init", "Tiles set"); data.set_wallpaper_cooldown(config.background_delay.max(5)); debug!(target: "ckgreeter::init", "Wallpaper cooldown set"); data.invoke_get_new_wallpaper(); debug!(target: "ckgreeter::init", "Wallpaper fetch invoked"); data.invoke_check_lock_states(); debug!(target: "ckgreeter::init", "Lock state check invoked"); info!(target: "ckgreeter::init", "Display setup complete"); display.show()?; tokio::task::block_in_place(slint::run_event_loop)?; display.hide()?; Ok(()) }