From c63ff80087918395065bd80865a5e4fad217889d Mon Sep 17 00:00:00 2001 From: Enrico Stemmer Date: Thu, 6 Feb 2025 08:25:33 +0100 Subject: [PATCH 1/3] fix: fix memory leak https://github.com/H3rmt/hyprswitch/discussions/137 Signed-off-by: Enrico Stemmer --- src/daemon/gui/icon.rs | 71 +++++++++++++++++++++--------------------- src/daemon/gui/maps.rs | 22 ++++++++++++- src/daemon/gui/mod.rs | 6 ++++ 3 files changed, 62 insertions(+), 37 deletions(-) diff --git a/src/daemon/gui/icon.rs b/src/daemon/gui/icon.rs index f454592..264e502 100644 --- a/src/daemon/gui/icon.rs +++ b/src/daemon/gui/icon.rs @@ -1,14 +1,12 @@ -use crate::daemon::gui::maps::{add_path_for_icon, get_icon_path_by_name, Source}; -use gtk4::IconTheme; -use gtk4::{glib, Image}; +use crate::daemon::gui::maps::{add_path_for_icon, get_icon_path_by_name, icon_has_name, Source}; +use gtk4::{Image}; use std::fs; use std::path::Path; use tracing::{span, trace, warn, Level}; pub fn load_icon_from_cache(name: &str, pic: &Image) -> Option> { - let theme = IconTheme::new(); // check if the icon is in theme and apply it - if theme.has_icon(name) { + if icon_has_name(name) { pic.set_icon_name(Some(name)); Some(Box::from(name)) } else { @@ -22,7 +20,8 @@ pub fn load_icon_from_cache(name: &str, pic: &Image) -> Option> { } Some(path) } else { - trace!("Icon for {name} not found in theme or cache"); + trace!("Icon for {name} not found in theme or cache, just trying to set it, maybe the cache is not up to date"); + pic.set_icon_name(Some(name)); None } } @@ -31,38 +30,38 @@ pub fn load_icon_from_cache(name: &str, pic: &Image) -> Option> { pub fn set_icon(class: &str, pid: i32, image: &Image) { let class = class.to_string(); let image = image.clone(); - glib::spawn_future_local(async move { - let _span = span!(Level::TRACE, "icon", class = class).entered(); + // glib::spawn_future_local(async move { + let _span = span!(Level::TRACE, "icon", class = class).entered(); - if load_icon_from_cache(&class, &image).is_some() { - return; - } + if load_icon_from_cache(&class, &image).is_some() { + return; + } - if let Ok(cmdline) = fs::read_to_string(format!("/proc/{}/cmdline", pid)) { - // convert x00 to space - trace!("No Icon found for {class}, using Icon by cmdline {cmdline} by PID ({pid})"); - let cmd = cmdline - .split('\x00') - .next() - .unwrap_or_default() - .split('/') - .last() - .unwrap_or_default(); - if cmd.is_empty() { - warn!("Failed to read cmdline for PID {}", pid); - } else { - trace!("Icon by cmdline {cmd} for {class} by PID ({pid})"); - if let Some(icon_path) = load_icon_from_cache(cmd, &image) { - // add the icon path back into cache - // to directly link class name to icon without checking pid again - add_path_for_icon(&class, &icon_path, Source::ByPidExec); - return; - } - } - } else { + if let Ok(cmdline) = fs::read_to_string(format!("/proc/{}/cmdline", pid)) { + // convert x00 to space + trace!("No Icon found for {class}, using Icon by cmdline {cmdline} by PID ({pid})"); + let cmd = cmdline + .split('\x00') + .next() + .unwrap_or_default() + .split('/') + .last() + .unwrap_or_default(); + if cmd.is_empty() { warn!("Failed to read cmdline for PID {}", pid); - }; + } else { + trace!("Icon by cmdline {cmd} for {class} by PID ({pid})"); + if let Some(icon_path) = load_icon_from_cache(cmd, &image) { + // add the icon path back into cache + // to directly link class name to icon without checking pid again + add_path_for_icon(&class, &icon_path, Source::ByPidExec); + return; + } + } + } else { + warn!("Failed to read cmdline for PID {}", pid); + }; - image.set_icon_name(Some("application-x-executable")); - }); + image.set_icon_name(Some("application-x-executable")); + // }); } diff --git a/src/daemon/gui/maps.rs b/src/daemon/gui/maps.rs index 3854df5..f76d706 100644 --- a/src/daemon/gui/maps.rs +++ b/src/daemon/gui/maps.rs @@ -1,5 +1,6 @@ use crate::Warn; -use std::collections::HashMap; +use gtk4::IconTheme; +use std::collections::{BTreeSet, HashMap}; use std::path::Path; use std::sync::{Mutex, MutexGuard}; use std::time::Instant; @@ -25,6 +26,25 @@ type DesktopFileMap = Vec<( Box, )>; +fn get_icon_map() -> &'static Mutex>> { + static MAP_LOCK: OnceLock>>> = OnceLock::new(); + MAP_LOCK.get_or_init(|| Mutex::new(BTreeSet::new())) +} + +pub fn init_icon_map() { + let theme = IconTheme::new(); + let mut map = get_icon_map().lock().expect("Failed to lock icon map"); + for icon in theme.icon_names() { + map.insert(Box::from(icon)); + } +} + +/// https://github.com/H3rmt/hyprswitch/discussions/137 +pub fn icon_has_name(name: &str) -> bool { + let map = get_icon_map().lock().expect("Failed to lock icon map"); + map.contains(&Box::from(name)) +} + fn get_icon_path_map() -> &'static Mutex { static MAP_LOCK: OnceLock> = OnceLock::new(); MAP_LOCK.get_or_init(|| Mutex::new(HashMap::new())) diff --git a/src/daemon/gui/mod.rs b/src/daemon/gui/mod.rs index 8af5a26..606acb8 100644 --- a/src/daemon/gui/mod.rs +++ b/src/daemon/gui/mod.rs @@ -33,6 +33,7 @@ mod maps; mod windows; pub use launcher::show_launch_spawn; +use crate::daemon::gui::maps::init_icon_map; pub(super) fn start_gui_blocking( share: Share, @@ -53,8 +54,13 @@ pub(super) fn start_gui_blocking( trace!("start connect_activate"); check_themes(); + // load all installed icons + // https://github.com/H3rmt/hyprswitch/discussions/137 + init_icon_map(); + apply_css(init_config.custom_css.as_ref()); + let (visibility_sender, visibility_receiver) = async_channel::unbounded(); let monitor_data_list: Rc>> = Rc::new(Mutex::new(HashMap::new())); From 68963cd592463ca6af94c86804ac0b8fe3ea7d66 Mon Sep 17 00:00:00 2001 From: Enrico Stemmer Date: Thu, 6 Feb 2025 08:25:33 +0100 Subject: [PATCH 2/3] chore: clippy Signed-off-by: Enrico Stemmer --- src/daemon/gui/launcher/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/daemon/gui/launcher/mod.rs b/src/daemon/gui/launcher/mod.rs index 3e5015b..b10259d 100644 --- a/src/daemon/gui/launcher/mod.rs +++ b/src/daemon/gui/launcher/mod.rs @@ -215,7 +215,7 @@ fn create_launch_widget( if icon_path.contains('/') { icon.set_from_file(Some(Path::new(&**icon_path))); } else { - icon.set_icon_name(Some(&*icon_path)); + icon.set_icon_name(Some(icon_path)); } } } From 1099503572628d90e2e6b282e2b7cdffaaa98725 Mon Sep 17 00:00:00 2001 From: Enrico Stemmer Date: Thu, 6 Feb 2025 08:37:50 +0100 Subject: [PATCH 3/3] chore(main): release 3.3.2 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- PKGBUILD | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 0befe35..00cff7c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.3.1" + ".": "3.3.2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0062971..8a809b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [3.3.2](https://github.com/H3rmt/hyprswitch/compare/v3.3.1...v3.3.2) (2025-02-06) + + +### Bug Fixes + +* fix memory leak https://github.com/H3rmt/hyprswitch/discussions/137 ([c63ff80](https://github.com/H3rmt/hyprswitch/commit/c63ff80087918395065bd80865a5e4fad217889d)) +* fix release pr creation ([21894b2](https://github.com/H3rmt/hyprswitch/commit/21894b291fe433452f2ad424dd3f27b822afd7fe)) + ## [3.3.1](https://github.com/H3rmt/hyprswitch/compare/v3.3.0...v3.3.1) (2025-02-02) diff --git a/Cargo.lock b/Cargo.lock index 90b9028..6ff819b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1011,7 +1011,7 @@ dependencies = [ [[package]] name = "hyprswitch" -version = "3.3.1" +version = "3.3.2" dependencies = [ "anyhow", "async-channel", diff --git a/Cargo.toml b/Cargo.toml index d3cd135..e21e4d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "hyprswitch" description = "A CLI/GUI that allows switching between windows in Hyprland" -version = "3.3.1" +version = "3.3.2" edition = "2021" license = "MIT" readme = "README.md" diff --git a/PKGBUILD b/PKGBUILD index 10b5e8e..ed2fecc 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,6 +1,6 @@ pkgname=hyprswitch # x-release-please-start-version -pkgver=3.3.1 +pkgver=3.3.2 # x-release-please-end pkgrel=1 pkgdesc="A CLI/GUI that allows switching between windows in Hyprland"