diff --git a/waycast-core/src/cache/mod.rs b/waycast-core/src/cache/mod.rs index 177438f..81b77f0 100644 --- a/waycast-core/src/cache/mod.rs +++ b/waycast-core/src/cache/mod.rs @@ -2,11 +2,25 @@ pub mod errors; use redb::{Database, ReadableDatabase, ReadableTable, TableDefinition}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::path::Path; +use std::sync::OnceLock; use std::time::{Duration, SystemTime}; use crate::cache::errors::CacheError; const CACHE_TABLE: TableDefinition<&str, &[u8]> = TableDefinition::new("cache"); +static CACHE_SINGLETON: OnceLock = OnceLock::new(); + +pub struct CacheTTL {} + +impl CacheTTL { + pub fn hours(hours: u64) -> Option { + return Some(Duration::from_secs(hours * 60 * 60)); + } + + pub fn minutes(minutes: u64) -> Option { + return Some(Duration::from_secs(minutes * 60)); + } +} #[derive(Serialize, Deserialize)] struct CacheEntry { @@ -18,7 +32,13 @@ pub struct Cache { db: Database, } -pub fn new>(db_path: P) -> Result { +pub fn get() -> &'static Cache { + CACHE_SINGLETON.get_or_init(|| new("waycast_cache").expect("Failed to initialize cache :(")) +} + +// Get an existing cache at the given path or +// create it if it doesn't exist +fn new>(db_path: P) -> Result { let db = Database::create(db_path)?; // Initialize the table if it doesn't exist @@ -47,7 +67,6 @@ impl Cache { // Check if entry has expired if let Some(expires_at) = entry.expires_at { if SystemTime::now() < expires_at { - println!("Cache hit"); return Ok(entry.data); } // Entry has expired, continue to recompute @@ -57,8 +76,6 @@ impl Cache { } } - println!("Cache miss"); - // Not in cache or expired, compute the value let data = compute(); let expires_at = ttl.map(|duration| SystemTime::now() + duration); diff --git a/waycast-gtk/src/main.rs b/waycast-gtk/src/main.rs index 6326fab..2cbbca0 100644 --- a/waycast-gtk/src/main.rs +++ b/waycast-gtk/src/main.rs @@ -1,70 +1,50 @@ -use std::time::Duration; +mod ui; +mod util; -use waycast_core::cache::Cache; +use gtk::prelude::*; +use gtk::Application; +use ui::gtk::GtkLauncherUI; +use waycast_core::WaycastLauncher; fn main() { - let cache: Cache; - if let Ok(db) = waycast_core::cache::new("waycast_cache") { - cache = db; - } else { - panic!("Failed to open database"); - } + let app = Application::builder() + .application_id("dev.thegrind.waycast") + .build(); - let result = cache.remember_with_ttl("test_key", Some(Duration::from_secs(10)), || { - String::from("my cool string value") + app.connect_activate(|app| { + let mut file_search_plugin = waycast_plugins::file_search::new(); + + if let Err(e) = file_search_plugin.add_search_path("/home/javi/working-files/DJ Music/") { + eprintln!("{}", e) + } + + let mut project_plugin = waycast_plugins::projects::new(); + if let Err(e) = project_plugin.add_search_path("/home/javi/projects") { + eprintln!("{}", e) + } + + // Create the core launcher + let launcher = WaycastLauncher::new() + .add_plugin(Box::new(waycast_plugins::drun::new())) + .add_plugin(Box::new(file_search_plugin)) + .add_plugin(Box::new(project_plugin)) + .init(); + + // Create and show the GTK UI + let ui = GtkLauncherUI::new(app, launcher); + + // Apply built-in default styles + if let Err(e) = ui.apply_default_css() { + eprintln!("Warning: Could not apply default styles: {}", e); + } + + // Optionally apply user CSS overrides + // if let Err(_) = ui.apply_css("waycast.css") { + // // Silently ignore if user hasn't provided custom CSS + // } + + ui.show(); }); - if let Ok(val) = result { - println!("{}", val); - } + app.run(); } -// mod ui; -// mod util; - -// use gtk::prelude::*; -// use gtk::Application; -// use ui::gtk::GtkLauncherUI; -// use waycast_core::WaycastLauncher; - -// fn main() { -// let app = Application::builder() -// .application_id("dev.thegrind.waycast") -// .build(); - -// app.connect_activate(|app| { -// let mut file_search_plugin = waycast_plugins::file_search::new(); - -// if let Err(e) = file_search_plugin.add_search_path("/home/javi/working-files/DJ Music/") { -// eprintln!("{}", e) -// } - -// let mut project_plugin = waycast_plugins::projects::new(); -// if let Err(e) = project_plugin.add_search_path("/home/javi/projects") { -// eprintln!("{}", e) -// } - -// // Create the core launcher -// let launcher = WaycastLauncher::new() -// .add_plugin(Box::new(waycast_plugins::drun::new())) -// .add_plugin(Box::new(file_search_plugin)) -// .add_plugin(Box::new(project_plugin)) -// .init(); - -// // Create and show the GTK UI -// let ui = GtkLauncherUI::new(app, launcher); - -// // Apply built-in default styles -// if let Err(e) = ui.apply_default_css() { -// eprintln!("Warning: Could not apply default styles: {}", e); -// } - -// // Optionally apply user CSS overrides -// // if let Err(_) = ui.apply_css("waycast.css") { -// // // Silently ignore if user hasn't provided custom CSS -// // } - -// ui.show(); -// }); - -// app.run(); -// } diff --git a/waycast-gtk/src/ui/gtk/mod.rs b/waycast-gtk/src/ui/gtk/mod.rs index 669d1ea..dfa027a 100644 --- a/waycast-gtk/src/ui/gtk/mod.rs +++ b/waycast-gtk/src/ui/gtk/mod.rs @@ -13,6 +13,7 @@ use layerShell::LayerShell; use std::cell::RefCell; use std::path::{Path, PathBuf}; use std::rc::Rc; +use waycast_core::cache::CacheTTL; use waycast_core::WaycastLauncher; // GObject wrapper to store LauncherListItem in GTK's model system @@ -402,6 +403,25 @@ fn find_icon_file( icon_name: &str, size: &str, icon_theme: &IconTheme, +) -> Option { + let cache_key = format!("icon:{}:{}", icon_name, size); + let cache = waycast_core::cache::get(); + + let result = cache.remember_with_ttl(&cache_key, CacheTTL::hours(24), || { + search_for_icon(icon_name, size, icon_theme) + }); + + if let Ok(opt_path) = result { + return opt_path; + } + + search_for_icon(icon_name, size, icon_theme) +} + +fn search_for_icon( + icon_name: &str, + size: &str, + icon_theme: &IconTheme, ) -> Option { let pixmap_paths: Vec = icon_theme .search_path() @@ -439,6 +459,7 @@ fn find_icon_file( } } } + for base in &search_paths { for size in sizes { for cat in &categories {