From 4f2902a847eed56ad1a8463f96797df631a1b115 Mon Sep 17 00:00:00 2001 From: CanadianBaconBoi Date: Tue, 16 Jun 2026 19:39:32 +0200 Subject: [PATCH] REFACTOR REFACTOR REFACTOR Added logging Improved control flow Stopped blocking the goddamn runtime with my background code Got rid of a potential double free --- Cargo.toml | 3 + src/callbacks.rs | 490 ++++++++++++++++++++++++++++------------------- src/config.rs | 9 +- src/main.rs | 67 ++++++- src/timers.rs | 4 + ui/data.slint | 1 - ui/window.slint | 12 +- 7 files changed, 370 insertions(+), 216 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bbc450a..6db412d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,9 @@ tokio-stream = {version = "0.1.18", features = ["fs"]} greetd-stub = "0.3.0" chrono = "0.4.44" +pretty_env_logger = "0.5.0" +log = {version = "0.4.32", features = ["kv"]} + pexels-api = { git = "https://github.com/houseme/pexels", rev = "b0b692a" } reqwest = { version = "0.13.3", features = ["json", "default-tls"] } diff --git a/src/callbacks.rs b/src/callbacks.rs index b1152a3..6d13aec 100644 --- a/src/callbacks.rs +++ b/src/callbacks.rs @@ -1,85 +1,91 @@ -use std::collections::VecDeque; -use std::path::{Path, PathBuf}; -use std::rc::Rc; -use std::sync::Arc; -use anyhow::{anyhow, Context}; -use greetd_ipc::{AuthMessageType, ErrorType, Request, Response}; +use crate::config::Config; +use crate::input::KeyboardLockStates; +use crate::{GreeterData, GreeterDisplay, LoginOptionTileData}; +use anyhow::{Context, anyhow}; use greetd_ipc::codec::TokioCodec; +use greetd_ipc::{AuthMessageType, ErrorType, Request, Response}; use i_slint_core::api::{ComponentHandle, Global, Image, Rgba8Pixel, SharedPixelBuffer, Weak}; use i_slint_core::model::{Model, VecModel}; +use log::{debug, error, info, trace}; use magick_rust::MagickWand; use pexels_api::{PexelsClient, SearchParams}; use rand::seq::SliceRandom; +use std::collections::VecDeque; +use std::fmt::Display; +use std::path::{Path, PathBuf}; +use std::rc::Rc; +use std::sync::Arc; use tokio::fs::File; use tokio::io::{AsyncBufReadExt, BufReader, Lines}; use tokio::net::UnixStream; -use crate::{GreeterData, GreeterDisplay, LoginOptionTileData}; -use crate::config::Config; -use crate::input::KeyboardLockStates; -#[cfg(not(debug_assertions))] -use zbus::{Connection, proxy}; #[cfg(not(debug_assertions))] use slint::SharedString; use tokio_stream::StreamExt; use tokio_stream::wrappers::ReadDirStream; +#[cfg(not(debug_assertions))] +use zbus::{Connection, proxy}; -pub fn register_login_callback(data: &GreeterData, display_weak: Weak, tiles: Rc>) { +pub fn register_login_callback( + data: &GreeterData, + display_weak: Weak, + tiles: Rc>, +) { data.on_login({ let tiles = tiles.clone(); let display_weak = display_weak.clone(); move |username, password| { + debug!(target: "ckgreeter::callbacks::login", "----- Login callback called"); let tiles = tiles.clone(); let display_weak = display_weak.clone(); + debug!(target: "ckgreeter::callbacks::login", "spawning slint thread"); slint::spawn_local(async move { + debug!(target: "ckgreeter::callbacks::login", "spawned slint thread"); let display = display_weak.unwrap(); let username = username.to_string(); let password = password.to_string(); + debug!(target: "ckgreeter::callbacks::login", "username: {username:?}"); + let index = display.get_selected_index(); let tile = &tiles.row_data(index as usize); let tile = match tile { - Some(tile) => {tile} + Some(tile) => tile, None => { display.invoke_set_error("Failed to login: Invalid index for tile".into()); + error!("Failed to login: Invalid index for tile: {index}"); return; } }; - match login( - username.as_str(), - password.as_str(), - tile.command.as_str(), - ) - .await - { + match login(username.as_str(), password.as_str(), tile.command.as_str()).await { Ok(successful) => { if !successful { display.invoke_set_error("Failed to login: Bad Login".into()); + error!("Failed to login: Bad Login"); return; } if let Err(err) = slint::quit_event_loop() { - display.invoke_set_error(format!("Failed to exit greeter: {err}").into()); + display + .invoke_set_error(format!("Failed to exit greeter: {err}").into()); + error!("Failed to exit greeter: {err}"); } } Err(err) => { - display.invoke_set_error(format!("Failed to login: {}", err).into()); + display.invoke_set_error(format!("Failed to login: {err}").into()); + error!("Failed to login: {err}"); return; } }; }) - .unwrap(); + .unwrap(); } }); - async fn login( - username: &str, - password: &str, - cmd: &str, - ) -> anyhow::Result { + async fn login(username: &str, password: &str, cmd: &str) -> anyhow::Result { if username.trim().is_empty() { return Err(anyhow::anyhow!("Username is required")); } @@ -88,12 +94,21 @@ pub fn register_login_callback(data: &GreeterData, display_weak: Weak None, }; + trace!(target: "ckgreeter::callbacks::login", "sending request: {next_request:?}"); next_request = Request::PostAuthMessageResponse { response }; } Response::Success => { if starting { + debug!(target: "ckgreeter::callbacks::login", "starting session"); return Ok(true); } else { starting = true; + trace!(target: "ckgreeter::callbacks::login", "sending request: {next_request:?}"); next_request = Request::StartSession { env: vec![], cmd: vec![cmd.to_string()], @@ -133,6 +151,7 @@ pub fn register_login_callback(data: &GreeterData, display_weak: Weak { + debug!(target: "ckgreeter::callbacks::login", "error logging in"); Request::CancelSession.write_to(&mut stream).await?; return match error_type { ErrorType::AuthError => Ok(false), @@ -145,22 +164,28 @@ pub fn register_login_callback(data: &GreeterData, display_weak: Weak anyhow::Result<()> { - let connection = Connection::system().await?; - let proxy = PowerManagerProxy::new(&connection).await?; + debug!(target: "ckgreeter::callbacks::power", "command: {command:?}"); + trace!(target: "ckgreeter::callbacks::power", "connecting to dbus"); + let connection = Connection::system().await?; + trace!(target: "ckgreeter::callbacks::power", "connected to dbus"); + trace!(target: "ckgreeter::callbacks::power", "getting power manager proxy"); + let proxy = PowerManagerProxy::new(&connection).await?; + trace!(target: "ckgreeter::callbacks::power", "got power manager proxy"); + + debug!(target: "ckgreeter::callbacks::power", "running power command: {command}"); match command { "suspend" => proxy.suspend(&false).await?, "poweroff" => proxy.power_off(&false).await?, @@ -189,34 +214,43 @@ pub fn register_lock_state_callback(data: &GreeterData, data_weak: Weak, data_weak: Weak>, cache_dir: PathBuf, config: &Config) { //TODO: Seperate this out into seperate methods, cleanup!!! - const MAX_RECENT_WALLPAPERS: usize = 10; +pub fn register_wallpaper_callback( + data: &GreeterData, + display_weak: Weak, + data_weak: Weak>, + cache_dir: PathBuf, + config: &Config, +) { + //TODO: Seperate this out into seperate methods, cleanup!!! + const MAX_RECENT_WALLPAPERS: usize = 25; async fn read_lines

(filename: P) -> std::io::Result>> where - P: AsRef, + P: AsRef + std::fmt::Debug, { + debug!(target: "ckgreeter::callbacks::wallpaper::read_lines", "reading lines from file: {:?}", filename); let file = File::open(filename).await?; Ok(BufReader::new(file).lines()) } - async fn write_lines

( - filename: P, - lines: VecDeque, - ) -> std::io::Result<()> + async fn write_lines

(filename: &P, lines: VecDeque) -> std::io::Result<()> where - P: AsRef, + P: AsRef + std::fmt::Debug, { let mut contents = String::new(); @@ -225,6 +259,7 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak::clone_from_slice( - pixels, w, h - ))); + data.set_wallpaper_image(Image::from_rgba8( + SharedPixelBuffer::::clone_from_slice(pixels, w, h), + )); + trace!(target: "ckgreeter::callbacks::wallpaper::set_background_image", "set background image 1"); drop(old); } else { + trace!(target: "ckgreeter::callbacks::wallpaper::set_background_image", "setting background image 2"); let old = data.get_wallpaper_image_1(); - data.set_wallpaper_image_1(Image::from_rgba8(SharedPixelBuffer::< - Rgba8Pixel, - >::clone_from_slice( - pixels, w, h - ))); + data.set_wallpaper_image_1(Image::from_rgba8( + SharedPixelBuffer::::clone_from_slice(pixels, w, h), + )); + trace!(target: "ckgreeter::callbacks::wallpaper::set_background_image", "set background image 2"); drop(old); } } fn export_wand_rgba(wand: &MagickWand) -> anyhow::Result<(u32, u32, Vec)> { + trace!(target: "ckgreeter::callbacks::wallpaper::export_wand_rgba", "exporting wand"); let pixels = wand .export_image_pixels( 0, @@ -265,6 +302,7 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak client, Err(err) => { eprintln!("Failed to create reqwest client: {err}"); return; } }; + debug!(target: "ckgreeter::callbacks::wallpaper", "reqwest client created"); if let Some(pexels_api_key) = config.pexels_api_key.clone() { + info!(target: "ckgreeter::callbacks::wallpaper", "Using pexels api"); + debug!(target: "ckgreeter::callbacks::wallpaper", "pexels api key found"); let pexels_client = Arc::new(PexelsClient::new(pexels_api_key)); let pexels_query = config .pexels_query .clone() .unwrap_or_else(|| String::from("nature")); + debug!(target: "ckgreeter::callbacks::wallpaper", "pexels query: {pexels_query}"); + info!(target: "ckgreeter::callbacks::wallpaper", "Registering wallpaper callback"); data.on_get_new_wallpaper({ let data_weak = data_weak.clone(); let display_weak = display_weak.clone(); move || { + debug!(target: "ckgreeter::callbacks::wallpaper", "----- wallpaper callback called"); let pexels_client = pexels_client.clone(); let reqwest_client = reqwest_client.clone(); let cache_dir = cache_dir.clone(); @@ -302,89 +347,128 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak anyhow::Result<()> { - let data = data_weak.unwrap(); - let display = display_weak.unwrap(); - - let last_used_log = cache_dir.join("last_used_log.txt"); - if !tokio::fs::try_exists(&last_used_log).await? { - File::create(&last_used_log).await?; + slint::spawn_local(async move { + trait ResultExt { + fn wpaper_err(self, data: &GreeterData) -> Result; + } + impl ResultExt for Result { + fn wpaper_err(self, data: &GreeterData) -> Result { + self.inspect_err(|e| { + error!(target: "ckgreeter::callbacks::wallpaper", "Failed to get wallpaper: {e}"); + data.set_wallpaper_author("Error".into()); + data.set_wallpaper_alt(e.to_string().into()); + data.set_wallpaper_url("Failed to get wallpaper".into()); + }) } + } - let mut file_lines = tokio::time::timeout(std::time::Duration::from_secs(5), read_lines(&last_used_log)).await??; - let mut idx = 0; - let mut last_used_lines = VecDeque::with_capacity(MAX_RECENT_WALLPAPERS); - while let Some(line) = file_lines.next_line().await? { - last_used_lines.push_back(line); - idx += 1; - if idx >= MAX_RECENT_WALLPAPERS { - break; - } + let data = data_weak.unwrap(); + let display = display_weak.unwrap(); + + let last_used_log = cache_dir.join("last_used_log.txt"); + debug!(target: "ckgreeter::callbacks::wallpaper", "last used log: {:?}", last_used_log); + if !tokio::fs::try_exists(&last_used_log).await.wpaper_err(&data)? { + File::create(&last_used_log).await.wpaper_err(&data)?; + debug!(target: "ckgreeter::callbacks::wallpaper", "created last used log"); + } + + let mut file_lines = tokio::time::timeout( + std::time::Duration::from_secs(5), + read_lines(&last_used_log), + ) + .await.wpaper_err(&data)?.wpaper_err(&data)?; + debug!(target: "ckgreeter::callbacks::wallpaper", "read last used log"); + + let mut idx = 0; + let mut last_used_lines = VecDeque::with_capacity(MAX_RECENT_WALLPAPERS); + while let Some(line) = file_lines.next_line().await.wpaper_err(&data)? { + last_used_lines.push_back(line); + idx += 1; + if idx > MAX_RECENT_WALLPAPERS { + last_used_lines.pop_front(); } - drop(file_lines); + } + drop(file_lines); + let mut page = 0; + + loop { + debug!(target: "ckgreeter::callbacks::wallpaper", "fetched photos list from pexels api"); + let mut is_photo_set: bool = false; + let mut found_photo: bool = false; match pexels_client .search_photos( pexels_query.as_str(), &SearchParams::new() - .page(1) - .per_page(11) + .page(page) + .per_page(10) .size(pexels_api::Size::Medium) - .orientation(pexels_api::Orientation::Landscape) - ).await + .orientation(pexels_api::Orientation::Landscape), + ) + .await { Ok(photos) => { if photos.total_results > 0 { + found_photo = true; + debug!(target: "ckgreeter::callbacks::wallpaper", "got photos from pexels api"); for photo in photos.photos { let string_id = photo.id.to_string(); + trace!(target: "ckgreeter::callbacks::wallpaper", "pexels photo id: {}", string_id); if last_used_lines.contains(&string_id) { + trace!(target: "ckgreeter::callbacks::wallpaper", "pexels photo id already used recently"); continue; } + is_photo_set = true; last_used_lines.push_back(string_id); if last_used_lines.len() > MAX_RECENT_WALLPAPERS { last_used_lines.pop_front(); } - let image_path = - cache_dir.join(format!("{}.png", photo.id)); + let image_path = cache_dir.join(format!("{}.png", photo.id)); + trace!(target: "ckgreeter::callbacks::wallpaper", "pexels photo image path: {:?}", image_path); - let _ = if !tokio::fs::try_exists(&image_path).await? { + let _ = if !tokio::fs::try_exists(&image_path).await.wpaper_err(&data)? { + debug!(target: "ckgreeter::callbacks::wallpaper", "pexels photo image not found, downloading"); let response = reqwest_client .get(photo.src.large2x.clone()) // TODO: determine which photo src size is best, maybe determine based on the monitor size to reduce memory pressure .send() - .await?; - let image_bytes = response.bytes().await?; + .await.wpaper_err(&data)?; + let image_bytes = response.bytes().await.wpaper_err(&data)?; + debug!(target: "ckgreeter::callbacks::wallpaper", "pexels photo image downloaded"); let size = display.window().size(); - let (w, h, pixels) = tokio::task::spawn_blocking(move || { - let wand = MagickWand::new(); + debug!(target: "ckgreeter::callbacks::wallpaper", "resizing image with ImageMagick"); + let (w, h, pixels) = + tokio::task::spawn_blocking(move || { + let wand = MagickWand::new(); - wand.read_image_blob(&image_bytes)?; - drop(image_bytes); + wand.read_image_blob(&image_bytes)?; + drop(image_bytes); - if size.width >= size.height { - wand.fit( - size.width as usize, - size.width as usize, - ); - } else { - wand.fit( - size.height as usize, - size.height as usize, - ); - } + if size.width >= size.height { + wand.fit( + size.width as usize, + size.width as usize, + ); + } else { + wand.fit( + size.height as usize, + size.height as usize, + ); + } - let png_data = wand.write_image_blob("png")?; - std::fs::write(image_path, png_data)?; + trace!(target: "ckgreeter::callbacks::wallpaper", "exporting png data"); + let png_data = wand.write_image_blob("png")?; + std::fs::write(image_path, png_data)?; + trace!(target: "ckgreeter::callbacks::wallpaper", "exported png data to disk"); - export_wand_rgba(&wand) - }).await??; + export_wand_rgba(&wand) + }) + .await.wpaper_err(&data)?.wpaper_err(&data)?; + debug!(target: "ckgreeter::callbacks::wallpaper", "image resized with ImageMagick"); set_background_image( &display, &data, @@ -392,24 +476,24 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak { - eprintln!("Failed to fetch online images, using cached. {err}"); - let mut photos = ReadDirStream::new(tokio::fs::read_dir(cache_dir).await?).filter(|de| match de { - Ok(de) => { - de.path().is_file() - && de.path().extension() - == Some(std::ffi::OsStr::new("png")) - } - Err(_) => false, - }).collect::>().await; + error!("Failed to fetch online images, using cached. {err}"); + debug!(target: "ckgreeter::callbacks::wallpaper", "getting cached wallpaper images from disk"); + let mut photos = + ReadDirStream::new(tokio::fs::read_dir(&cache_dir).await.wpaper_err(&data)?) + .filter(|de| match de { + Ok(de) => { + de.path().is_file() + && de.path().extension() + == Some(std::ffi::OsStr::new("png")) + } + Err(_) => false, + }) + .collect::>() + .await; + debug!(target: "ckgreeter::callbacks::wallpaper", "got cached wallpaper images from disk"); photos.shuffle(&mut rand::rng()); + debug!(target: "ckgreeter::callbacks::wallpaper", "shuffled cached wallpaper images"); let mut photos = tokio_stream::iter(photos); @@ -456,9 +550,16 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak { let photo_path = photo.path(); - let string_id = photo_path.file_prefix().context("failed to get filename")?.to_string_lossy().to_string(); + let string_id = photo_path + .file_prefix() + .context("failed to get filename").wpaper_err(&data)? + .to_string_lossy() + .to_string(); - if last_used_lines.front().is_some_and(|last| last == &string_id) { + if last_used_lines + .front() + .is_some_and(|first| first == &string_id) + { continue; } @@ -467,12 +568,21 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak { @@ -500,64 +613,36 @@ pub fn register_wallpaper_callback(data: &GreeterData, display_weak: Weak {} - Err(e) => { - let data = data_weak.unwrap(); - report_wallpaper_error(&data, e.to_string()); - } - }; + if is_photo_set || !found_photo { + break; + } + + page += 1; } - }) { - Ok(_) => {} - Err(e) => { - let data = data_weak.unwrap(); - report_wallpaper_error(&data, e.to_string()); - } - } + + tokio::time::timeout( + std::time::Duration::from_secs(5), + write_lines(&last_used_log, last_used_lines), + ) + .await + .context("timed out while writing wallpaper log").wpaper_err(&data)?.wpaper_err(&data)?; + return anyhow::Ok(()); + }).unwrap(); } }); - - fn report_wallpaper_error(data: &GreeterData, error: String) { - data.set_wallpaper_author("Error".into()); - data.set_wallpaper_alt(error.into()); - data.set_wallpaper_url("Failed to get wallpaper".into()); - } } } -pub fn register_clean_inactive_wallpaper_callback(data: &GreeterData, display_weak: Weak, data_weak: Weak>) { - data.on_clear_inactive_wallpaper({ - let display_weak = display_weak.clone(); - let data_weak = data_weak.clone(); - move || { - let display = display_weak.unwrap(); - let data = data_weak.unwrap(); - - if !display.get_background_toggle() { - let old = data.get_wallpaper_image(); - data.set_wallpaper_image(Image::default()); - drop(old); - } else { - let old = data.get_wallpaper_image_1(); - data.set_wallpaper_image_1(Image::default()); - drop(old); - } - } - }) -} pub fn register_get_default_font_size(data: &GreeterData, display_weak: Weak) { data.on_get_default_font_size(move || { + debug!(target: "ckgreeter::callbacks::font_size", "----- get default font size callback called"); let display = display_weak.unwrap(); let size = display.window().size(); - ((size.width as f32).min(size.height as f32)) * 0.01 + trace!(target: "ckgreeter::callbacks::font_size", "window size: {:?}", size); + let font_size = ((size.width as f32).min(size.height as f32)) * 0.01; + trace!(target: "ckgreeter::callbacks::font_size", "font size: {}", font_size); + font_size }); } @@ -571,10 +656,21 @@ pub fn register_callbacks( let display_weak = display.as_weak(); let data_weak = data.as_weak(); + debug!(target: "ckgreeter::callbacks", "Registering callbacks"); register_login_callback(data, display_weak.clone(), tiles); + debug!(target: "ckgreeter::callbacks", "Registered login callback"); register_power_callback(data); + debug!(target: "ckgreeter::callbacks", "Registered power callback"); register_lock_state_callback(data, data_weak.clone()); - register_wallpaper_callback(data, display_weak.clone(), data_weak.clone(), cache_dir, config); - register_clean_inactive_wallpaper_callback(data, display_weak.clone(), data_weak.clone()); + debug!(target: "ckgreeter::callbacks", "Registered lock state callback"); + register_wallpaper_callback( + data, + display_weak.clone(), + data_weak.clone(), + cache_dir, + config, + ); + debug!(target: "ckgreeter::callbacks", "Registered clean inactive wallpaper callback"); register_get_default_font_size(data, display_weak.clone()); -} \ No newline at end of file + debug!(target: "ckgreeter::callbacks", "Registered get default font size callback"); +} diff --git a/src/config.rs b/src/config.rs index 0332731..167be88 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,11 +2,12 @@ use std::collections::HashMap; use std::path::PathBuf; use anyhow::{anyhow, Context}; use i_slint_core::api::{Image, ToSharedString}; +use log::{debug, trace}; use serde::Deserialize; use serde_aux::prelude::*; use crate::LoginOptionTileData; -#[derive(Deserialize)] +#[derive(Deserialize, Debug)] pub struct LoginOptionTileConfig { pub(crate) image_path: PathBuf, pub(crate) command: String, @@ -26,6 +27,7 @@ pub fn default_cache_dir() -> PathBuf { #[derive(Deserialize)] pub struct Config { pub(crate) default_username: Option, + #[serde(default)] pub(crate) environments: HashMap, pub(crate) pexels_api_key: Option, pub(crate) pexels_query: Option, @@ -37,11 +39,13 @@ pub struct Config { impl Config { pub fn get_tiles(&self) -> anyhow::Result<(Vec, Option)> { + debug!(target: "ckgreeter::config_get_tiles", "Getting tiles from config"); let mut ordered = self .environments .iter() .collect::>(); + debug!(target: "ckgreeter::config_get_tiles", "Sorting tiles"); ordered.sort_by_key(|(name, env)| { let index = if env.index >= 0 { env.index } else { i32::MAX }; (index, name.as_str()) @@ -53,6 +57,8 @@ impl Config { let mut seen_indexes = std::collections::HashSet::new(); for (name, tile_config) in ordered { + debug!(target: "ckgreeter::config_get_tiles", "Adding tile `{}`", name); + trace!(target: "ckgreeter::config_get_tiles", "Tile config: {:#?}", tile_config); if tile_config.index >= 0 && !seen_indexes.insert(tile_config.index) { return Err(anyhow!( "Duplicate login option index `{}` found near `{}`", @@ -64,6 +70,7 @@ impl Config { if default.is_some() { return Err(anyhow!("There can only be one default login option...")); } + debug!(target: "ckgreeter::config_get_tiles", "Setting default tile to `{}`", name); default = Some(tiles.len()); } tiles.push(LoginOptionTileData { diff --git a/src/main.rs b/src/main.rs index 40f73a0..5045b20 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,46 +18,82 @@ 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()), + 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") + .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(); + { + start_debug_greetd_stub(); + info!(target: "ckgreeter::init", "Debug greetd stub started"); + } + const CONFIG_PATH: &str = "/etc/ckgreeter/config.toml"; - let config_data = std::fs::read(CONFIG_PATH) - .with_context(|| format!("Failed to read config file at {}", CONFIG_PATH))?; + let config_path = std::env::var("CKGREETER_CONFIG").unwrap_or_else(|_| CONFIG_PATH.to_string()); + + 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 config: Config = toml::from_slice(&config_data) - .with_context(|| format!("Failed to parse config file at {}", CONFIG_PATH))?; + .with_context(|| format!("Failed to parse config file at {}", config_path))?; + debug!(target: "ckgreeter::init", "Config parsed"); 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()))?; @@ -66,14 +102,25 @@ async fn main() -> anyhow::Result<()> { let (tiles, default_tile) = config.get_tiles()?; + 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) => { @@ -85,12 +132,20 @@ async fn main() -> anyhow::Result<()> { } } + 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()?; diff --git a/src/timers.rs b/src/timers.rs index 80f22ec..7195e8e 100644 --- a/src/timers.rs +++ b/src/timers.rs @@ -1,5 +1,6 @@ use chrono::Datelike; use i_slint_core::api::Global; +use log::debug; use crate::{GreeterData, GreeterDisplay}; use crate::config::Config; @@ -8,6 +9,7 @@ pub fn register_timers( data: &GreeterData, _config: &Config, ) -> slint::Timer { + debug!(target: "ckgreeter::timers", "Registering timers..."); let data_weak = data.as_weak(); let timer = slint::Timer::default(); @@ -28,5 +30,7 @@ pub fn register_timers( }, ); + debug!(target: "ckgreeter::timers", "Clock timer started"); + timer } \ No newline at end of file diff --git a/ui/data.slint b/ui/data.slint index 65e8f39..fd1e96b 100644 --- a/ui/data.slint +++ b/ui/data.slint @@ -12,7 +12,6 @@ export global Data { callback check-lock-states(); callback get-new-wallpaper(); - callback clear-inactive-wallpaper(); in property wallpaper-url; diff --git a/ui/window.slint b/ui/window.slint index 4c048f5..1c7b8aa 100644 --- a/ui/window.slint +++ b/ui/window.slint @@ -45,9 +45,7 @@ export component GreeterDisplay inherits Window { public function switch_background() { background-toggle = !background-toggle; background_timer.start(); - clear_inactive_wallpaper_timer.start(); background_timer.restart(); - clear_inactive_wallpaper_timer.restart(); } full-screen: true; @@ -85,15 +83,6 @@ export component GreeterDisplay inherits Window { self.running = false; } } - - clear_inactive_wallpaper_timer := Timer { - interval: 1200ms; - running: false; - triggered() => { - Data.clear-inactive-wallpaper(); - self.running = false; - } - } } background_1 := Image { // Background (secondary), needed for smooth opacity transitions @@ -307,6 +296,7 @@ export component GreeterDisplay inherits Window { has_focus: environment_selector.has-focus; on_click => { Data.selected_index = self.index; + environment_selector.focus() } } }