diff --git a/Cargo.lock b/Cargo.lock index cde4f5e..d153cab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -301,6 +301,21 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "colouncher" +version = "0.1.0" +dependencies = [ + "env_logger", + "eyre", + "freedesktop-file-parser", + "freedesktop-icons", + "image", + "log", + "palette", + "smithay-client-toolkit", + "wayland-client", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -1514,21 +1529,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "wallpapersc" -version = "0.1.0" -dependencies = [ - "env_logger", - "eyre", - "freedesktop-file-parser", - "freedesktop-icons", - "image", - "log", - "palette", - "smithay-client-toolkit", - "wayland-client", -] - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 6545c30..5a677da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "wallpapersc" +name = "colouncher" version = "0.1.0" edition = "2024" diff --git a/default.nix b/default.nix index 8b981f5..aab735f 100644 --- a/default.nix +++ b/default.nix @@ -1,5 +1,5 @@ { pkgs ? import { } }: pkgs.rustPlatform.buildRustPackage { - pname = "wallpapersc"; + pname = "colouncher"; version = "0.1.0"; src = pkgs.lib.cleanSource ./.; @@ -10,4 +10,8 @@ wayland libxkbcommon ]; + + meta = { + mainProgram = "colouncher"; + }; } diff --git a/src/desktop.rs b/src/desktop.rs index 31590de..c1fe8b9 100644 --- a/src/desktop.rs +++ b/src/desktop.rs @@ -1,12 +1,7 @@ use eyre::{Context, Result}; use freedesktop_file_parser::{DesktopFile, EntryType}; use palette::{IntoColor, Oklab, Oklaba}; -use std::{ - collections::HashMap, - ffi::OsStr, - fs::DirEntry, - path::{Path, PathBuf}, -}; +use std::{collections::HashMap, ffi::OsStr, fs::DirEntry, path::Path}; fn walkdir(path: &Path, f: &mut impl FnMut(&DirEntry) -> Result<()>) -> Result<()> { for entry in path.read_dir()? { @@ -22,7 +17,7 @@ fn walkdir(path: &Path, f: &mut impl FnMut(&DirEntry) -> Result<()>) -> Result<( pub(crate) fn find_desktop_files() -> Result> { // https://specifications.freedesktop.org/desktop-entry/latest/file-naming.html let paths = std::env::var("XDG_DATA_DIRS").unwrap_or("/usr/local/share/:/usr/share/".into()); - let paths = std::env::split_paths(&paths).map(PathBuf::from); + let paths = std::env::split_paths(&paths); let mut results = HashMap::new(); for data_dir in paths { @@ -47,21 +42,20 @@ pub(crate) fn find_desktop_files() -> Result> { let file = freedesktop_file_parser::parse(&contents).wrap_err("parsing .desktop file")?; - if !results.contains_key(&id) { - if file.entry.no_display != Some(true) - && file.entry.hidden != Some(true) - && let EntryType::Application(_) = file.entry.entry_type - && let Some(icon) = &file.entry.icon - && let Some(icon) = icon.get_icon_path() - && icon.extension() != Some(OsStr::new("svg")) - { dbg!(path); - let icon: image::DynamicImage = image::ImageReader::open(&icon) - .wrap_err_with(|| format!("{}", icon.display()))? - .decode() - .wrap_err_with(|| format!("decoding {}", icon.display()))?; - let color = average_color(&icon); - results.insert(id, (file, color)); - } + if !results.contains_key(&id) + && file.entry.no_display != Some(true) + && file.entry.hidden != Some(true) + && let EntryType::Application(_) = file.entry.entry_type + && let Some(icon) = &file.entry.icon + && let Some(icon) = icon.get_icon_path() + && icon.extension() != Some(OsStr::new("svg")) + { + let icon: image::DynamicImage = image::ImageReader::open(&icon) + .wrap_err_with(|| format!("{}", icon.display()))? + .decode() + .wrap_err_with(|| format!("decoding {}", icon.display()))?; + let color = average_color(&icon); + results.insert(id, (file, color)); } Ok(()) diff --git a/src/main.rs b/src/main.rs index d34a485..8bf1e2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -232,8 +232,15 @@ impl LayerShellHandler for App { &mut self, _conn: &Connection, _qh: &QueueHandle, - _layer: &smithay_client_toolkit::shell::wlr_layer::LayerSurface, + layer: &smithay_client_toolkit::shell::wlr_layer::LayerSurface, ) { + if let Some(surface_idx) = self + .layer_surfaces + .iter() + .position(|surface| surface.layer_surface == *layer) + { + self.layer_surfaces.swap_remove(surface_idx); + } } fn configure( @@ -370,51 +377,50 @@ impl PointerHandler for App { events: &[smithay_client_toolkit::seat::pointer::PointerEvent], ) { for event in events { - match event.kind { - PointerEventKind::Release { - button: BTN_LEFT, .. - } => { - let Some(surface) = self - .layer_surfaces - .iter() - .find(|surface| *surface.layer_surface.wl_surface() == event.surface) - else { + if let PointerEventKind::Release { + button: BTN_LEFT, .. + } = event.kind + { + let Some(surface) = self + .layer_surfaces + .iter() + .find(|surface| *surface.layer_surface.wl_surface() == event.surface) + else { + return; + }; + + let srgb = color_for_pixel( + event.position.0 as u32, + event.position.1 as u32, + surface.width, + surface.height, + ); + + let oklab: Oklab = srgb.into_format::().into_color(); + + let best_match = self + .desktop_files + .iter() + .min_by_key(|(_, icon_color)| (oklab.distance(*icon_color) * 1000000.0) as u32); + + if let Some(best_match) = best_match + && let EntryType::Application(app) = &best_match.0.entry.entry_type + && let Some(exec) = &app.exec + { + // lol terrible implementation that works well enough + // https://specifications.freedesktop.org/desktop-entry/latest/exec-variables.html + let exec = exec.replace("%U", "").replace("%F", ""); + if exec.contains("%") { + warn!( + "Trying to execute insuffiently substituded command-line, refusing: {}", + exec + ); return; - }; - - let srgb = color_for_pixel( - event.position.0 as u32, - event.position.1 as u32, - surface.width, - surface.height, - ); - - let oklab: Oklab = srgb.into_format::().into_color(); - - let best_match = self.desktop_files.iter().min_by_key(|(_, icon_color)| { - (oklab.distance(*icon_color) * 1000000.0) as u32 - }); - - if let Some(best_match) = best_match - && let EntryType::Application(app) = &best_match.0.entry.entry_type - && let Some(exec) = &app.exec - { - // lol terrible implementation that works well enough - // https://specifications.freedesktop.org/desktop-entry/latest/exec-variables.html - let exec = exec.replace("%U", "").replace("%F", ""); - if exec.contains("%") { - warn!( - "Trying to execute insuffiently substituded command-line, refusing: {}", - exec - ); - return; - } - if let Err(err) = spawn(&exec) { - error!("Failed to spawn program: {}: {:?}", exec, err); - } + } + if let Err(err) = spawn(&exec) { + error!("Failed to spawn program: {}: {:?}", exec, err); } } - _ => {} } } }