From 9add5c827f36281d8ce690c766e90c745f195d02 Mon Sep 17 00:00:00 2001 From: Penelope Gwen Date: Wed, 17 Sep 2025 00:07:21 -0700 Subject: [PATCH] approaching first major release --- src/config.rs | 51 +++++++++++++++-------------- src/lib/lock.rs | 74 ++++++++++++++++++++++++++++++++++++++++++- src/lib/windows.rs | 7 ++-- src/lib/workspaces.rs | 10 ++++-- src/main.rs | 73 +++++++++++++++++++++++++++--------------- 5 files changed, 159 insertions(+), 56 deletions(-) diff --git a/src/config.rs b/src/config.rs index fc23579..1ce7407 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,31 +1,34 @@ -use std::fs::File; -//use std::io::{Write, Error}; -use xdg::BaseDirectories; -use config_file::FromConfigFile; -use serde::Deserialize; +use std::collections::HashMap; +use serde::{Deserialize, Serialize}; -#[derive(Deserialize,Clone)] +#[derive(Serialize,Deserialize,Clone)] pub struct WindowIcon { pub icon: String, pub substring: String } -#[derive(Deserialize, Default)] +#[derive(Serialize,Deserialize,Clone,Debug)] +pub struct BrowserConf { + pub profile: String, + pub startpage: String +} +#[derive(Serialize,Deserialize,Clone,Debug)] +pub struct Profile { + pub name: String, + pub icon: String, + pub browser: BrowserConf, + pub directory: String +} +#[derive(Serialize,Deserialize,Clone,Debug)] +pub struct Programs { + pub name: String, + pub command: String, + pub arguments: Vec +} +#[derive(Serialize,Deserialize,Default)] pub struct Config { pub title_length: usize, - pub window_icons: Vec -} - -pub fn parse_config() -> Config { - let xdg_dirs = BaseDirectories::with_prefix("sway-profiles-rs"); - let config_path = xdg_dirs - .place_config_file("config.toml") - .expect("cannot create configuration directory"); -// println!("{}",config_path.exists()); - if !config_path.exists() { - let _ = File::create(&config_path); -// let config_file = File::create(&config_path); -// write!(&mut config_file, "title_length = 20"); - } - Config::from_config_file(config_path).unwrap() -} - + pub window_icons: Vec, + pub wallpaper_path: String, + pub programs: HashMap, + pub profiles: HashMap +} \ No newline at end of file diff --git a/src/lib/lock.rs b/src/lib/lock.rs index 414b33f..3838679 100644 --- a/src/lib/lock.rs +++ b/src/lib/lock.rs @@ -1 +1,73 @@ -use \ No newline at end of file +use std::{env::consts, fs::{self, exists}, io, ops::Sub, path::{Path, PathBuf}}; +use walkdir::WalkDir; + +use image::imageops::GaussianBlurParameters; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use sha2::{Sha256, Digest}; +use swayipc::Connection; +use xdg::BaseDirectories; +use shellexpand::tilde; + +use crate::config::Config; + +#[derive(Serialize,Deserialize,Debug)] +pub struct WallpaperCache { + pub display: String, + pub hash: String +} + +pub fn lock_screen(config: &Config, mut sway_connection: Connection) { + let wallpaper_root_path = tilde(&config.wallpaper_path).to_string(); + let wallpaper_root_path = Path::new(&wallpaper_root_path); + let cache_dir = BaseDirectories::with_prefix("sway-profiles-rs").cache_home; + let wp_cache_dir = cache_dir.clone().unwrap().join("sway-profiles-rs/lock/"); + + let mut wp_hash_json: Vec = vec![]; + let hashes_json_path = wp_cache_dir.join("hashes.json"); + if exists(&hashes_json_path).unwrap() { + let file = fs::File::open(&hashes_json_path).unwrap(); + wp_hash_json = serde_json::from_reader(file).unwrap(); + } + + let mut wp_hash_array: Vec = vec![]; + for output in sway_connection.get_outputs().unwrap() { + let sway_workspaces = sway_connection.get_workspaces().unwrap().clone(); + let output_ws_num = format!("{:0>2}",sway_workspaces.iter().find(|x|x.name == output.current_workspace + .clone().unwrap()).unwrap().num.sub(1)).chars().next().unwrap(); + let image_path = wallpaper_root_path.join(output.name.clone()).join(format!("p_{}.jpg",output_ws_num)); + + let mut img_file_data = fs::File::open(&image_path).unwrap(); + let mut sha256 = Sha256::new(); + let _ = io::copy(&mut img_file_data, &mut sha256); + let hash = format!("{:x}",sha256.finalize()); + wp_hash_array.push(WallpaperCache { display: output.name.clone(), hash: hash.clone() }); + + if let Some(output_saved_hash) = wp_hash_json.iter().find(|x|x.display == output.name) && output_saved_hash.hash.ne(&hash) { + let img_data = image::open(image_path).unwrap(); + let blurred_img_data = img_data + .resize((img_data.width() as f64 * 0.75) as u32, (img_data.height() as f64 * 0.75) as u32, image::imageops::FilterType::Nearest) + .blur_advanced(GaussianBlurParameters::new_from_sigma(10.0)); + let blurred_image_path = cache_dir.clone().unwrap().join(format!("sway-profiles-rs/lock/{}.jpg",output.name)); + let _ = blurred_img_data.save(blurred_image_path); + } + } + let gtklock_modules_dir = "/usr/lib/".to_owned() + consts::ARCH + "-linux-gnu/gtklock/"; + let gktlock_modules_path = Path::new(>klock_modules_dir); + let mut gtklock_args: Vec = vec![]; + for file in WalkDir::new(gktlock_modules_path).into_iter() {//.find(|x|x.as_ref().unwrap().file_name().to_str().unwrap().ends_with("-module.so")) { + + if let Some(f) = file.iter().find(|&x|x.path().to_str().unwrap().ends_with("-module.so")) { + gtklock_args.push("-m".to_owned()); + gtklock_args.push(f.path().to_str().unwrap().to_string()); + } + } + let new_json = json!(wp_hash_array); + let _ = std::fs::write::(hashes_json_path, new_json.to_string()); + let mut gtklock_command = "exec gtklock".to_owned(); + for a in gtklock_args { + gtklock_command = gtklock_command + " " + &a; + } + println!("{:?}",gtklock_command); + let _ = sway_connection.run_command(gtklock_command); +} \ No newline at end of file diff --git a/src/lib/windows.rs b/src/lib/windows.rs index 4d10234..3694024 100644 --- a/src/lib/windows.rs +++ b/src/lib/windows.rs @@ -3,9 +3,10 @@ use serde_json::json; use swayipc::Node; use crate::{config::Config, Cli}; -//#[path = "../results.rs"] -mod results; -use results::WindowInfo; +#[derive(serde::Serialize)] +pub struct WindowInfo { + pub title: String +} pub fn print_window_title(window_node: Node,cli: &Cli,config: &Config) { let mut window_title_display: String = window_node.name.unwrap(); diff --git a/src/lib/workspaces.rs b/src/lib/workspaces.rs index 9f3f440..4a7dda5 100644 --- a/src/lib/workspaces.rs +++ b/src/lib/workspaces.rs @@ -1,9 +1,13 @@ use serde_json::json; use swayipc::Workspace; -//#[path = "../results.rs"] -mod results; -use results::WorkspaceInfo; +#[derive(serde::Serialize)] +pub struct WorkspaceInfo { + pub num: i32, + pub name: String, + pub is_focused: bool, + pub position: char +} pub fn print_workspace_array(workspaces: Vec) { let current_ws = workspaces.iter().find(|&x| x.focused).unwrap().num; diff --git a/src/main.rs b/src/main.rs index 6fbad1a..9cdd764 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,10 @@ use std::process::exit; + + use clap::{Parser,Subcommand,ArgAction}; use swayipc::{Connection, Event, EventType, Fallible}; - mod config; #[path = "lib/windows.rs"] mod windows; @@ -11,9 +12,11 @@ use windows::print_window_title; #[path = "lib/workspaces.rs"] mod workspaces; use workspaces::print_workspace_array; +#[path = "lib/lock.rs"] +mod lock; +use lock::lock_screen; -use crate::config::Config; -mod monitor; +use config::Config; #[derive(Parser)] @@ -43,12 +46,16 @@ pub struct Cli { enum Commands { /// Prints the Currently Active Window Title Windows, - // Prints the Currently Active Workspace layout + /// Prints the Currently Active Workspace layout Workspaces, - // Launch Program with Current Profile's Configuration - Launch, + /// Launch Program with Current Workspace's Profile Configuration + Launch { + #[arg(short, long)] + program: String + }, + /// Set up blurred wallpaper for screen lock, and load gtklock modules Lock, - Rename, + //Rename, Profile, Shortcuts { #[arg(short, long, action = ArgAction::SetTrue)] @@ -73,35 +80,52 @@ enum MonitorTypes { } fn main() -> Fallible<()> { + //let xdg_dirs = BaseDirectories::with_prefix("sway-profiles-rs"); let cli = Cli::parse(); - let config = config::parse_config(); - if let Some(no_truncate_title) = cli.no_truncate_title { - println!("Value for no_truncate_title: {no_truncate_title}"); - } +// let config = config::parse_config(); + let config = confy::load("sway-profiles-rs", "config").unwrap(); + let mut sway_connection = Connection::new()?; match &cli.command { Commands::Windows => { - print_window_title(sway_connection.get_tree().iter().find(|&x | x.focused).unwrap().clone(), &cli, &config); + print_window_title(sway_connection.get_tree().unwrap().iter().find(|&x | x.focused).unwrap().clone(), &cli, &config); if cli.monitor.unwrap() { - let _ = monitor_events(EventType::Window, cli, config); + monitor_events(EventType::Window, cli, config); } } Commands::Workspaces => { print_workspace_array(sway_connection.get_workspaces().unwrap()); if cli.monitor.unwrap() { - let _ = monitor_events(EventType::Workspace, cli, config); + monitor_events(EventType::Workspace, cli, config); } } - Commands::Launch => todo!(), - Commands::Lock => todo!(), - Commands::Rename => todo!(), - Commands::Profile => todo!(), - Commands::Shortcuts { global } => todo!(), + Commands::Launch { program } => { + if let Some(launch_program) = config.programs.iter().find(|x|x.0 == program) { + println!("found: {:#?} {:?}",launch_program.1.command, launch_program.1.arguments); + let mut swaymsg_command = "exec ".to_owned() + &launch_program.1.command; + for a in &launch_program.1.arguments { + swaymsg_command = swaymsg_command + " " + a; + } + println!("{:#?}",swaymsg_command); + let _ = sway_connection.run_command(swaymsg_command); + } + }, + Commands::Lock => { + lock_screen(&config, sway_connection); + }, + //Commands::Rename => todo!(), + Commands::Profile => { + println!("{:?}", config.profiles.len()); + for p in config.profiles { + println!("{:?} {:?}",p.0, p.1.name ) + } + }, + Commands::Shortcuts { global: _ } => todo!(), } exit(0); } -pub fn monitor_events(event_type: EventType, cli: Cli, config: Config) -> Fallible<()> { +pub fn monitor_events(event_type: EventType, cli: Cli, config: Config) { /* let subs = [ // Valid EventTypes: Workspace, Output, Input, Tick, Shutdown, Mode, Window, BarStateUpdate, BarConfigUpdate, Binding //EventType::Workspace, @@ -109,14 +133,14 @@ pub fn monitor_events(event_type: EventType, cli: Cli, config: Config) -> Fallib //EventType::Window, event_type ]; */ - let sway_connection = Connection::new()?; - for event in sway_connection.subscribe([event_type])? { - let e = event?; + let sway_connection = Connection::new().unwrap(); + for event in sway_connection.subscribe([event_type]).unwrap() { + let e = event.unwrap(); match e { Event::Window(w) => { print_window_title(w.container, &cli, &config); }, - Event::Workspace(w) => { + Event::Workspace(_) => { print_workspace_array(self::Connection::get_workspaces(&mut self::Connection::new().unwrap()).unwrap()); }, Event::Tick(w) => { @@ -125,5 +149,4 @@ pub fn monitor_events(event_type: EventType, cli: Cli, config: Config) -> Fallib _ => unreachable!(), } } - Ok(()) } \ No newline at end of file