CKGreeter/src/main.rs
CanadianBaconBoi 66d90100df Add License and README, and add XDG session detection
- Updated dependencies in cargo.toml
- Added wayland-sessions and xsessions support
- Added better error handling for image and config loading
- Added some example configs
- Add FSL-1.1-MIT License
Note: All unlicensed commits prior to this commit on 17.06.2026 are considered All Rights Reserved.
2026-06-17 09:34:37 +02:00

161 lines
5.5 KiB
Rust

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::<GreeterData>();
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(())
}