From 72440e69c9e665f3e82e569e770747fc63765b53 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Sun, 25 Feb 2024 17:13:28 +0000 Subject: [PATCH 01/24] feat(tray): icon size setting --- docs/modules/Tray.md | 7 ++++--- src/modules/tray/icon.rs | 29 +++++++++++++++++++++-------- src/modules/tray/mod.rs | 20 ++++++++++++++------ 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/docs/modules/Tray.md b/docs/modules/Tray.md index a80c48e..1924440 100644 --- a/docs/modules/Tray.md +++ b/docs/modules/Tray.md @@ -7,9 +7,10 @@ Displays a fully interactive icon tray using the KDE `libappindicator` protocol. > Type: `tray` -| Name | Type | Default | Description | -|-------------|----------|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------| -| `direction` | `string` | `left_to_right` if bar is horizontal, `top_to_bottom` otherwise | Direction to display the tray items. Possible values: `top_to_bottom`, `bottom_to_top`, `left_to_right`, `right_to_left` | +| Name | Type | Default | Description | +|-------------|-----------|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------| +| `direction` | `string` | `left_to_right` if bar is horizontal, `top_to_bottom` otherwise | Direction to display the tray items. Possible values: `top_to_bottom`, `bottom_to_top`, `left_to_right`, `right_to_left` | +| `icon_size` | `integer` | `16` | Size in pixels to display tray icons as |
JSON diff --git a/src/modules/tray/icon.rs b/src/modules/tray/icon.rs index 850137f..3592941 100644 --- a/src/modules/tray/icon.rs +++ b/src/modules/tray/icon.rs @@ -1,3 +1,5 @@ +use crate::image::ImageProvider; +use color_eyre::{Report, Result}; use glib::ffi::g_strfreev; use glib::translate::ToGlibPtr; use gtk::ffi::gtk_icon_theme_get_search_path; @@ -36,29 +38,40 @@ fn get_icon_theme_search_paths(icon_theme: &IconTheme) -> HashSet { paths } +pub fn get_image(item: &StatusNotifierItem, icon_theme: &IconTheme, size: u32) -> Result { + get_image_from_icon_name(item, icon_theme, size) + .or_else(|_| get_image_from_pixmap(item, size)) +} + /// Attempts to get a GTK `Image` component /// for the status notifier item's icon. -pub(crate) fn get_image_from_icon_name( +fn get_image_from_icon_name( item: &StatusNotifierItem, icon_theme: &IconTheme, -) -> Option { + size: u32, +) -> Result { if let Some(path) = item.icon_theme_path.as_ref() { if !path.is_empty() && !get_icon_theme_search_paths(icon_theme).contains(path) { icon_theme.append_search_path(path); } } - item.icon_name.as_ref().and_then(|icon_name| { - let icon_info = icon_theme.lookup_icon(icon_name, 16, IconLookupFlags::empty()); - icon_info.map(|icon_info| Image::from_pixbuf(icon_info.load_icon().ok().as_ref())) - }) + let icon_info = item.icon_name.as_ref().and_then(|icon_name| { + icon_theme.lookup_icon(icon_name, size as i32, IconLookupFlags::empty()) + }); + + let pixbuf = icon_info.unwrap().load_icon()?; + + let image = Image::new(); + ImageProvider::create_and_load_surface(&pixbuf, &image)?; + Ok(image) } /// Attempts to get an image from the item pixmap. /// /// The pixmap is supplied in ARGB32 format, /// which has 8 bits per sample and a bit stride of `4*width`. -pub(crate) fn get_image_from_pixmap(item: &StatusNotifierItem) -> Option { +fn get_image_from_pixmap(item: &StatusNotifierItem, size: u32) -> Result { const BITS_PER_SAMPLE: i32 = 8; let pixmap = item @@ -80,7 +93,7 @@ pub(crate) fn get_image_from_pixmap(item: &StatusNotifierItem) -> Option ); let pixbuf = pixbuf - .scale_simple(16, 16, InterpType::Bilinear) + .scale_simple(size as i32, size as i32, InterpType::Bilinear) .unwrap_or(pixbuf); Some(Image::from_pixbuf(Some(&pixbuf))) } diff --git a/src/modules/tray/mod.rs b/src/modules/tray/mod.rs index cf4a2ff..d64654a 100644 --- a/src/modules/tray/mod.rs +++ b/src/modules/tray/mod.rs @@ -18,12 +18,20 @@ use tokio::sync::mpsc; #[derive(Debug, Deserialize, Clone)] pub struct TrayModule { + #[serde(default = "default_icon_size")] + icon_size: u32, + #[serde(default, deserialize_with = "deserialize_orientation")] - pub direction: Option, + direction: Option, + #[serde(flatten)] pub common: Option, } +const fn default_icon_size() -> u32 { + 16 +} + fn deserialize_orientation<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, @@ -106,7 +114,7 @@ impl Module for TrayModule { // listen for UI updates glib_recv!(context.subscribe(), update => - on_update(update, &container, &mut menus, &icon_theme, &context.controller_tx) + on_update(update, &container, &mut menus, &icon_theme, self.icon_size, &context.controller_tx) ); }; @@ -124,6 +132,7 @@ fn on_update( container: &MenuBar, menus: &mut HashMap, TrayMenu>, icon_theme: &IconTheme, + icon_size: u32, tx: &mpsc::Sender, ) { match update { @@ -148,11 +157,10 @@ fn on_update( } if item.icon_name.as_ref() != menu_item.icon_name() { - match icon::get_image_from_icon_name(&item, icon_theme) - .or_else(|| icon::get_image_from_pixmap(&item)) + match icon::get_image(&item, icon_theme, icon_size) { - Some(image) => menu_item.set_image(&image), - None => menu_item.set_label(label), + Ok(image) => menu_item.set_image(&image), + Err(_) => menu_item.set_label(label), }; } From 0675b917f2beeed3e6b626dad8fe34b8063d9c83 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Sun, 25 Feb 2024 17:13:43 +0000 Subject: [PATCH 02/24] fix(tray): icons ignoring scaling --- src/image/provider.rs | 13 ++++++++----- src/modules/tray/icon.rs | 13 ++++++++----- src/modules/tray/mod.rs | 3 +-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/image/provider.rs b/src/image/provider.rs index a23debf..1f3b646 100644 --- a/src/image/provider.rs +++ b/src/image/provider.rs @@ -171,7 +171,7 @@ impl<'a> ImageProvider<'a> { ); // Different error types makes this a bit awkward - match pixbuf.map(|pixbuf| Self::create_and_load_surface(&pixbuf, &image, scale)) + match pixbuf.map(|pixbuf| Self::create_and_load_surface(&pixbuf, &image)) { Ok(Err(err)) => error!("{err:?}"), Err(err) => error!("{err:?}"), @@ -202,7 +202,7 @@ impl<'a> ImageProvider<'a> { _ => unreachable!(), // handled above }?; - Self::create_and_load_surface(&pixbuf, image, scale) + Self::create_and_load_surface(&pixbuf, image) } /// Attempts to create a Cairo surface from the provided `Pixbuf`, @@ -210,10 +210,13 @@ impl<'a> ImageProvider<'a> { /// The surface is then loaded into the provided image. /// /// This is necessary for HiDPI since `Pixbuf`s are always treated as scale factor 1. - fn create_and_load_surface(pixbuf: &Pixbuf, image: >k::Image, scale: i32) -> Result<()> { + pub fn create_and_load_surface(pixbuf: &Pixbuf, image: >k::Image) -> Result<()> { let surface = unsafe { - let ptr = - gdk_cairo_surface_create_from_pixbuf(pixbuf.as_ptr(), scale, std::ptr::null_mut()); + let ptr = gdk_cairo_surface_create_from_pixbuf( + pixbuf.as_ptr(), + image.scale_factor(), + std::ptr::null_mut(), + ); Surface::from_raw_full(ptr) }?; diff --git a/src/modules/tray/icon.rs b/src/modules/tray/icon.rs index 3592941..7cf442e 100644 --- a/src/modules/tray/icon.rs +++ b/src/modules/tray/icon.rs @@ -39,8 +39,7 @@ fn get_icon_theme_search_paths(icon_theme: &IconTheme) -> HashSet { } pub fn get_image(item: &StatusNotifierItem, icon_theme: &IconTheme, size: u32) -> Result { - get_image_from_icon_name(item, icon_theme, size) - .or_else(|_| get_image_from_pixmap(item, size)) + get_image_from_icon_name(item, icon_theme, size).or_else(|_| get_image_from_pixmap(item, size)) } /// Attempts to get a GTK `Image` component @@ -77,10 +76,11 @@ fn get_image_from_pixmap(item: &StatusNotifierItem, size: u32) -> Result let pixmap = item .icon_pixmap .as_ref() - .and_then(|pixmap| pixmap.first())?; + .and_then(|pixmap| pixmap.first()) + .ok_or_else(|| Report::msg("Failed to get pixmap from tray icon"))?; let bytes = glib::Bytes::from(&pixmap.pixels); - let row_stride = pixmap.width * 4; // + let row_stride = pixmap.width * 4; let pixbuf = gdk_pixbuf::Pixbuf::from_bytes( &bytes, @@ -95,5 +95,8 @@ fn get_image_from_pixmap(item: &StatusNotifierItem, size: u32) -> Result let pixbuf = pixbuf .scale_simple(size as i32, size as i32, InterpType::Bilinear) .unwrap_or(pixbuf); - Some(Image::from_pixbuf(Some(&pixbuf))) + + let image = Image::new(); + ImageProvider::create_and_load_surface(&pixbuf, &image)?; + Ok(image) } diff --git a/src/modules/tray/mod.rs b/src/modules/tray/mod.rs index d64654a..d0f85e4 100644 --- a/src/modules/tray/mod.rs +++ b/src/modules/tray/mod.rs @@ -157,8 +157,7 @@ fn on_update( } if item.icon_name.as_ref() != menu_item.icon_name() { - match icon::get_image(&item, icon_theme, icon_size) - { + match icon::get_image(&item, icon_theme, icon_size) { Ok(image) => menu_item.set_image(&image), Err(_) => menu_item.set_label(label), }; From c62d47555ec31baa1a7094491e2977a832f4cfcc Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Sun, 25 Feb 2024 17:59:03 +0000 Subject: [PATCH 03/24] fix(tray): submenus not working Fixes a regression from previous tray fixes that caused submenus within the main tray menu to never show. Fixes #455 --- src/modules/tray/interface.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/modules/tray/interface.rs b/src/modules/tray/interface.rs index 3b9d988..d35a1bf 100644 --- a/src/modules/tray/interface.rs +++ b/src/modules/tray/interface.rs @@ -188,8 +188,23 @@ enum TrayMenuWidget { impl TrayMenuItem { fn new(info: &MenuItemInfo, tx: mpsc::Sender) -> Self { + let mut submenu = HashMap::new(); let menu = Menu::new(); + macro_rules! add_submenu { + ($menu:expr, $widget:expr) => { + if !info.submenu.is_empty() { + for sub_item in &info.submenu { + let sub_item = TrayMenuItem::new(sub_item, tx.clone()); + call!($menu, add, sub_item.widget); + submenu.insert(sub_item.id, sub_item); + } + + $widget.set_submenu(Some(&menu)); + } + }; + } + let widget = match (info.menu_type, info.toggle_type) { (MenuType::Separator, _) => TrayMenuWidget::Separator(SeparatorMenuItem::new()), (MenuType::Standard, ToggleType::Checkmark) => { @@ -200,6 +215,8 @@ impl TrayMenuItem { .active(info.toggle_state == ToggleState::On) .build(); + add_submenu!(menu, widget); + { let tx = tx.clone(); let id = info.id; @@ -212,12 +229,13 @@ impl TrayMenuItem { TrayMenuWidget::Checkbox(widget) } (MenuType::Standard, _) => { - let builder = MenuItem::builder() + let widget = MenuItem::builder() .label(&info.label) .visible(info.visible) - .sensitive(info.enabled); + .sensitive(info.enabled) + .build(); - let widget = builder.build(); + add_submenu!(menu, widget); { let tx = tx.clone(); @@ -236,7 +254,7 @@ impl TrayMenuItem { id: info.id, widget, menu_widget: menu, - submenu: HashMap::new(), + submenu, tx, } } From 86c5b69f18356201db5c3a314f36e0f68e74c357 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Thu, 14 Mar 2024 22:35:55 +0000 Subject: [PATCH 04/24] refactor(tray): tidy imports --- src/modules/tray/icon.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/tray/icon.rs b/src/modules/tray/icon.rs index 850137f..55f09fc 100644 --- a/src/modules/tray/icon.rs +++ b/src/modules/tray/icon.rs @@ -1,9 +1,9 @@ use glib::ffi::g_strfreev; use glib::translate::ToGlibPtr; use gtk::ffi::gtk_icon_theme_get_search_path; -use gtk::gdk_pixbuf::{Colorspace, InterpType}; +use gtk::gdk_pixbuf::{Colorspace, InterpType, Pixbuf}; use gtk::prelude::IconThemeExt; -use gtk::{gdk_pixbuf, IconLookupFlags, IconTheme, Image}; +use gtk::{IconLookupFlags, IconTheme, Image}; use std::collections::HashSet; use std::ffi::CStr; use std::os::raw::{c_char, c_int}; @@ -69,7 +69,7 @@ pub(crate) fn get_image_from_pixmap(item: &StatusNotifierItem) -> Option let bytes = glib::Bytes::from(&pixmap.pixels); let row_stride = pixmap.width * 4; // - let pixbuf = gdk_pixbuf::Pixbuf::from_bytes( + let pixbuf = Pixbuf::from_bytes( &bytes, Colorspace::Rgb, true, From 00a6a84ca6af6f3c64183ec08fdff7430770d39b Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Thu, 14 Mar 2024 22:36:20 +0000 Subject: [PATCH 05/24] refactor(upower): cheaper string building --- src/modules/upower.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/upower.rs b/src/modules/upower.rs index 0019a65..f2b976a 100644 --- a/src/modules/upower.rs +++ b/src/modules/upower.rs @@ -199,7 +199,9 @@ impl Module for UpowerModule { let format = format.replace("{percentage}", &properties.percentage.to_string()) .replace("{time_remaining}", &time_remaining) .replace("{state}", battery_state_to_string(state)); - let icon_name = String::from("icon:") + &properties.icon_name; + + let mut icon_name = String::from("icon:"); + icon_name.push_str(&properties.icon_name); ImageProvider::parse(&icon_name, &icon_theme, false, self.icon_size) .map(|provider| provider.load_into_image(icon.clone())); From b912619d61a74921c854ea6464e0922e5c107a27 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Thu, 14 Mar 2024 22:36:30 +0000 Subject: [PATCH 06/24] refactor(image): add debug logging --- src/image/provider.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/image/provider.rs b/src/image/provider.rs index a23debf..6003a14 100644 --- a/src/image/provider.rs +++ b/src/image/provider.rs @@ -11,7 +11,7 @@ use gtk::{IconLookupFlags, IconTheme}; use std::path::{Path, PathBuf}; #[cfg(feature = "http")] use tokio::sync::mpsc; -use tracing::warn; +use tracing::{debug, warn}; cfg_if!( if #[cfg(feature = "http")] { @@ -45,6 +45,7 @@ impl<'a> ImageProvider<'a> { /// but no other check is performed. pub fn parse(input: &str, theme: &'a IconTheme, use_fallback: bool, size: i32) -> Option { let location = Self::get_location(input, theme, size, use_fallback, 0)?; + debug!("Resolved {input} --> {location:?} (size: {size})"); Some(Self { location, size }) } From 6b2494ded0670c067622e8248f593f838a6f91e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 14:37:50 +0000 Subject: [PATCH 07/24] build(deps): bump futures-lite from 2.2.0 to 2.3.0 Bumps [futures-lite](https://github.com/smol-rs/futures-lite) from 2.2.0 to 2.3.0. - [Release notes](https://github.com/smol-rs/futures-lite/releases) - [Changelog](https://github.com/smol-rs/futures-lite/blob/master/CHANGELOG.md) - [Commits](https://github.com/smol-rs/futures-lite/compare/v2.2.0...v2.3.0) --- updated-dependencies: - dependency-name: futures-lite dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61e928e..82d0289 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1043,9 +1043,9 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ "fastrand 2.0.1", "futures-core", @@ -1643,7 +1643,7 @@ dependencies = [ "color-eyre", "ctrlc", "dirs", - "futures-lite 2.2.0", + "futures-lite 2.3.0", "futures-util", "glib", "gtk", diff --git a/Cargo.toml b/Cargo.toml index 717759b..068514b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -135,7 +135,7 @@ system-tray = { version = "0.1.5", optional = true } # upower upower_dbus = { version = "0.3.2", optional = true } -futures-lite = { version = "2.2.0", optional = true } +futures-lite = { version = "2.3.0", optional = true } # volume libpulse-binding = { version = "2.28.1", optional = true } From 4eed3e2c76cf4f5127d2fc6134d05bae5df58a80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 14:38:00 +0000 Subject: [PATCH 08/24] build(deps): bump reqwest from 0.11.25 to 0.11.26 Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.11.25 to 0.11.26. - [Release notes](https://github.com/seanmonstar/reqwest/releases) - [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md) - [Commits](https://github.com/seanmonstar/reqwest/compare/v0.11.25...v0.11.26) --- updated-dependencies: - dependency-name: reqwest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 14 +++++++------- Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61e928e..c160bd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2528,9 +2528,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.25" +version = "0.11.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eea5a9eb898d3783f17c6407670e3592fd174cb81a10e51d4c37f49450b9946" +checksum = "78bf93c4af7a8bb7d879d51cebe797356ff10ae8516ace542b5182d9dcac10b2" dependencies = [ "base64 0.21.0", "bytes", @@ -3030,20 +3030,20 @@ dependencies = [ [[package]] name = "system-configuration" -version = "0.6.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bc6ee10a9b4fcf576e9b0819d95ec16f4d2c02d39fd83ac1c8789785c4a42" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ - "bitflags 2.4.0", + "bitflags 1.3.2", "core-foundation", "system-configuration-sys", ] [[package]] name = "system-configuration-sys" -version = "0.6.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" dependencies = [ "core-foundation-sys", "libc", diff --git a/Cargo.toml b/Cargo.toml index 717759b..f054126 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -115,7 +115,7 @@ clap = { version = "4.5.2", optional = true, features = ["derive"] } serde_json = { version = "1.0.114", optional = true } # http -reqwest = { version = "0.11.25", optional = true } +reqwest = { version = "0.11.26", optional = true } # clipboard nix = { version = "0.27.1", optional = true, features = ["event"] } From e0c1f950f27ff3c6447ce15a78f8c5830c25f5a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 17:28:10 +0000 Subject: [PATCH 09/24] build(deps): bump color-eyre from 0.6.2 to 0.6.3 Bumps [color-eyre](https://github.com/eyre-rs/eyre) from 0.6.2 to 0.6.3. - [Commits](https://github.com/eyre-rs/eyre/compare/v0.6.2...color-eyre-v0.6.3) --- updated-dependencies: - dependency-name: color-eyre dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99db08e..79c0d42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -494,9 +494,9 @@ dependencies = [ [[package]] name = "color-eyre" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" dependencies = [ "backtrace", "color-spantrace", @@ -2078,9 +2078,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" diff --git a/Cargo.toml b/Cargo.toml index bf533ac..87a85f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,7 +92,7 @@ tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } tracing-error = "0.2.0" tracing-appender = "0.2.3" strip-ansi-escapes = "0.2.0" -color-eyre = "0.6.2" +color-eyre = "0.6.3" serde = { version = "1.0.197", features = ["derive"] } indexmap = "2.2.5" dirs = "5.0.1" From 6ea7f57f805561bfb8a1b37bac7a2457ab3e827d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 17:30:39 +0000 Subject: [PATCH 10/24] build(deps): bump clap from 4.5.2 to 4.5.3 Bumps [clap](https://github.com/clap-rs/clap) from 4.5.2 to 4.5.3. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v4.5.2...v4.5.3) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 16 +++++++++++----- Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99db08e..92e3f16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -444,9 +444,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.2" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" +checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" dependencies = [ "clap_builder", "clap_derive", @@ -466,11 +466,11 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote 1.0.35", "syn 2.0.48", @@ -1396,6 +1396,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.2.6" diff --git a/Cargo.toml b/Cargo.toml index bf533ac..97d1167 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,7 +109,7 @@ ctrlc = "3.4.2" cfg-if = "1.0.0" # cli -clap = { version = "4.5.2", optional = true, features = ["derive"] } +clap = { version = "4.5.3", optional = true, features = ["derive"] } # ipc serde_json = { version = "1.0.114", optional = true } From 180f8748bbe52affbbfe8c5ec045c753e63d554d Mon Sep 17 00:00:00 2001 From: slowsage <84777606+slowsage@users.noreply.github.com> Date: Sun, 3 Mar 2024 19:23:39 -0500 Subject: [PATCH 11/24] fix(music): Handle NoActivePlayer (playerctld) , NoReply, NoMethod, ServiceUnknown DBus errors in mpris. --- src/clients/music/mod.rs | 7 ++- src/clients/music/mpris.rs | 121 ++++++++++++++++++++++++------------- 2 files changed, 83 insertions(+), 45 deletions(-) diff --git a/src/clients/music/mod.rs b/src/clients/music/mod.rs index 4269f81..e42b60f 100644 --- a/src/clients/music/mod.rs +++ b/src/clients/music/mod.rs @@ -34,14 +34,15 @@ pub struct Track { pub cover_path: Option, } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub enum PlayerState { + #[default] + Stopped, Playing, Paused, - Stopped, } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Status { pub state: PlayerState, pub volume_percent: Option, diff --git a/src/clients/music/mpris.rs b/src/clients/music/mpris.rs index f6eae4c..d505560 100644 --- a/src/clients/music/mpris.rs +++ b/src/clients/music/mpris.rs @@ -18,6 +18,11 @@ pub struct Client { _rx: broadcast::Receiver, } +const NO_ACTIVE_PLAYER: &str = "com.github.altdesktop.playerctld.NoActivePlayer"; +const NO_REPLY: &str = "org.freedesktop.DBus.Error.NoReply"; +const NO_SERVICE: &str = "org.freedesktop.DBus.Error.ServiceUnknown"; +const NO_METHOD: &str = "org.freedesktop.DBus.Error.UnknownMethod"; + impl Client { pub(crate) fn new() -> Self { let (tx, rx) = broadcast::channel(32); @@ -35,44 +40,48 @@ impl Client { // D-Bus gives no event for new players, // so we have to keep polling the player list loop { - let players = player_finder - .find_all() - .expect("Failed to connect to D-Bus"); + // mpris-rs does not filter NoActivePlayer errors, so we have to do it ourselves + let players = player_finder.find_all().unwrap_or_else(|e| match e { + mpris::FindingError::DBusError(DBusError::TransportError( + transport_error, + )) if transport_error.name() == Some(NO_ACTIVE_PLAYER) + || transport_error.name() == Some(NO_REPLY) => + { + Vec::new() + } + _ => panic!("Failed to connect to D-Bus"), + }); + // Acquire the lock of current_player before players to avoid deadlock. + // There are places where we lock on current_player and players, but we always lock on current_player first. + // This is because we almost never need to lock on players without locking on current_player. + { + let mut current_player_lock = lock!(current_player); - let mut players_list_val = lock!(players_list); - for player in players { - let identity = player.identity(); + let mut players_list_val = lock!(players_list); + for player in players { + let identity = player.identity(); - if !players_list_val.contains(identity) { - debug!("Adding MPRIS player '{identity}'"); - players_list_val.insert(identity.to_string()); + if current_player_lock.is_none() { + debug!("Setting active player to '{identity}'"); + current_player_lock.replace(identity.to_string()); - let status = player - .get_playback_status() - .expect("Failed to connect to D-Bus"); - - { - let mut current_player = lock!(current_player); - - if status == PlaybackStatus::Playing || current_player.is_none() { - debug!("Setting active player to '{identity}'"); - - current_player.replace(identity.to_string()); - if let Err(err) = Self::send_update(&player, &tx) { - error!("{err:?}"); - } + if let Err(err) = Self::send_update(&player, &tx) { + error!("{err:?}"); } } + if !players_list_val.contains(identity) { + debug!("Adding MPRIS player '{identity}'"); + players_list_val.insert(identity.to_string()); - Self::listen_player_events( - identity.to_string(), - players_list.clone(), - current_player.clone(), - tx.clone(), - ); + Self::listen_player_events( + identity.to_string(), + players_list.clone(), + current_player.clone(), + tx.clone(), + ); + } } } - // wait 1 second before re-checking players sleep(Duration::from_secs(1)); } @@ -111,28 +120,56 @@ impl Client { if let Ok(player) = player_finder.find_by_name(&player_id) { let identity = player.identity(); + let handle_shutdown = |current_player_lock_option: Option< + std::sync::MutexGuard<'_, Option>, + >| { + debug!("Player '{identity}' shutting down"); + // Lock of player before players (see new() to make sure order is consistent) + if let Some(mut guard) = current_player_lock_option { + guard.take(); + } else { + lock!(current_player).take(); + } + let mut players_locked = lock!(players); + players_locked.remove(identity); + if players_locked.is_empty() { + send!(tx, PlayerUpdate::Update(Box::new(None), Status::default())); + } + }; for event in player.events()? { trace!("Received player event from '{identity}': {event:?}"); match event { Ok(Event::PlayerShutDown) => { - lock!(current_player).take(); - lock!(players).remove(identity); + handle_shutdown(None); break; } - Ok(Event::Playing) => { - lock!(current_player).replace(identity.to_string()); - - if let Err(err) = Self::send_update(&player, &tx) { - error!("{err:?}"); - } + Err(mpris::EventError::DBusError(DBusError::TransportError( + transport_error, + ))) if transport_error.name() == Some(NO_ACTIVE_PLAYER) + || transport_error.name() == Some(NO_REPLY) + || transport_error.name() == Some(NO_METHOD) + || transport_error.name() == Some(NO_SERVICE) => + { + handle_shutdown(None); + break; } Ok(_) => { - let current_player = lock!(current_player); - let current_player = current_player.as_ref(); - if let Some(current_player) = current_player { - if current_player == identity { + let mut current_player_lock = lock!(current_player); + if matches!(event, Ok(Event::Playing)) { + current_player_lock.replace(identity.to_string()); + } + if let Some(current_identity) = current_player_lock.as_ref() { + if current_identity == identity { if let Err(err) = Self::send_update(&player, &tx) { + if let Some(DBusError::TransportError(transport_error)) = + err.downcast_ref::() + { + if transport_error.name() == Some(NO_SERVICE) { + handle_shutdown(Some(current_player_lock)); + break; + } + } error!("{err:?}"); } } From 1dbd933705b1d1183e43cb054465efa8bf78d855 Mon Sep 17 00:00:00 2001 From: slowsage <84777606+slowsage@users.noreply.github.com> Date: Wed, 20 Mar 2024 12:09:54 -0400 Subject: [PATCH 12/24] ci: Build binaries on new release. --- .github/workflows/binary.yml | 32 ++++++++++++++++++++++++++++++++ Cross.toml | 10 ++++++++++ 2 files changed, 42 insertions(+) create mode 100644 .github/workflows/binary.yml create mode 100644 Cross.toml diff --git a/.github/workflows/binary.yml b/.github/workflows/binary.yml new file mode 100644 index 0000000..14e4c97 --- /dev/null +++ b/.github/workflows/binary.yml @@ -0,0 +1,32 @@ +# .github/workflows/binary.yml + +name: Binary +on: + release: + types: [created] +jobs: + build: + name: Build + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + platform: + - {target: x86_64-unknown-linux-gnu, zipext: ".tar.gz"} + - {target: aarch64-unknown-linux-gnu, zipext: ".tar.gz"} + steps: + - uses: actions/checkout@v4 + - uses: taiki-e/install-action@v2 + with: + tool: cross + - run: cargo add openssl --features vendored + - run: cross build --locked --release --target=${{ matrix.platform.target }} + - run: echo "BINARY_NAME=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[].targets[] | select( .kind | map(. == "bin") | any ) | .name')" >> $GITHUB_ENV + + - if: ${{ matrix.platform.zipext == '.tar.gz' }} + run: tar -zcvf ${{env.BINARY_NAME}}-${{github.ref_name}}-${{matrix.platform.target}}.tar.gz -C target/${{matrix.platform.target}}/release ${{env.BINARY_NAME}} + + - name: Release + run: gh release upload ${GITHUB_REF#refs/*/} ${{env.BINARY_NAME}}-${{github.ref_name}}-${{matrix.platform.target}}${{matrix.platform.zipext}} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Cross.toml b/Cross.toml new file mode 100644 index 0000000..5b2cc4c --- /dev/null +++ b/Cross.toml @@ -0,0 +1,10 @@ +[build] +pre-build = [ + "dpkg --add-architecture $CROSS_DEB_ARCH", + "apt-get update && apt-get install --assume-yes libssl-dev:$CROSS_DEB_ARCH libgtk-3-dev:$CROSS_DEB_ARCH libgtk-layer-shell-dev:$CROSS_DEB_ARCH libpulse-dev:$CROSS_DEB_ARCH", +] +[target.aarch64-unknown-linux-gnu] +image = "ghcr.io/cross-rs/aarch64-unknown-linux-gnu:main" + +[target.x86_64-unknown-linux-gnu] +image = "ghcr.io/cross-rs/x86_64-unknown-linux-gnu:main" From d65df93e3262a53db7083a024532e38d6d8ca2c1 Mon Sep 17 00:00:00 2001 From: slowsage <84777606+slowsage@users.noreply.github.com> Date: Fri, 22 Mar 2024 11:15:25 -0400 Subject: [PATCH 13/24] ci: ubuntu_setup.sh --- .github/scripts/ubuntu_setup.sh | 20 ++++++++++++++++++++ .github/workflows/binary.yml | 17 ++++++++++++----- .github/workflows/build.yml | 14 ++++---------- .github/workflows/deploy.yml | 6 ++---- Cross.toml | 5 +---- 5 files changed, 39 insertions(+), 23 deletions(-) create mode 100755 .github/scripts/ubuntu_setup.sh diff --git a/.github/scripts/ubuntu_setup.sh b/.github/scripts/ubuntu_setup.sh new file mode 100755 index 0000000..ea8f1cc --- /dev/null +++ b/.github/scripts/ubuntu_setup.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# sudo needed for github runner, not available by default for cross images +if command -v sudo >/dev/null 2>&1; then + SUDO="sudo" +else + SUDO="" +fi + +# Needed for cross-compilation +if [ -n "$CROSS_DEB_ARCH" ]; then + $SUDO dpkg --add-architecture "$CROSS_DEB_ARCH" +fi + +# CROSS_DEB_ARCH is empty for native builds +$SUDO apt-get update && $SUDO apt-get install --assume-yes \ + libssl-dev${CROSS_DEB_ARCH:+:$CROSS_DEB_ARCH} \ + libgtk-3-dev${CROSS_DEB_ARCH:+:$CROSS_DEB_ARCH} \ + libgtk-layer-shell-dev${CROSS_DEB_ARCH:+:$CROSS_DEB_ARCH} \ + libpulse-dev${CROSS_DEB_ARCH:+:$CROSS_DEB_ARCH} diff --git a/.github/workflows/binary.yml b/.github/workflows/binary.yml index 14e4c97..ed7c53e 100644 --- a/.github/workflows/binary.yml +++ b/.github/workflows/binary.yml @@ -19,14 +19,21 @@ jobs: - uses: taiki-e/install-action@v2 with: tool: cross - - run: cargo add openssl --features vendored - - run: cross build --locked --release --target=${{ matrix.platform.target }} - - run: echo "BINARY_NAME=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[].targets[] | select( .kind | map(. == "bin") | any ) | .name')" >> $GITHUB_ENV - - if: ${{ matrix.platform.zipext == '.tar.gz' }} + - name: Add OpenSSL crate (vendored) + run: cargo add openssl --features vendored + + - name: Cross Build Release + run: cross build --locked --release --target=${{ matrix.platform.target }} + + - name: Get name of Binary from metadata + run: echo "BINARY_NAME=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[].targets[] | select( .kind | map(. == "bin") | any ) | .name')" >> $GITHUB_ENV + + - name: Compress the built binary + if: ${{ matrix.platform.zipext == '.tar.gz' }} run: tar -zcvf ${{env.BINARY_NAME}}-${{github.ref_name}}-${{matrix.platform.target}}.tar.gz -C target/${{matrix.platform.target}}/release ${{env.BINARY_NAME}} - - name: Release + - name: Upload to release run: gh release upload ${GITHUB_REF#refs/*/} ${{env.BINARY_NAME}}-${{github.ref_name}}-${{matrix.platform.target}}${{matrix.platform.zipext}} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b02903c..8f8b4dd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,9 +32,7 @@ jobs: name: Cache dependencies - name: Install build deps - run: | - sudo apt-get update - sudo apt-get install libgtk-3-dev libgtk-layer-shell-dev libpulse-dev + run: ./.github/scripts/ubuntu_setup.sh - name: Clippy run: cargo clippy --no-default-features --features config+json @@ -53,9 +51,7 @@ jobs: name: Cache dependencies - name: Install build deps - run: | - sudo apt-get update - sudo apt-get install libgtk-3-dev libgtk-layer-shell-dev libpulse-dev + run: ./.github/scripts/ubuntu_setup.sh - name: Clippy run: cargo clippy --all-targets --all-features @@ -72,9 +68,7 @@ jobs: name: Cache dependencies - name: Install build deps - run: | - sudo apt-get update - sudo apt-get install libgtk-3-dev libgtk-layer-shell-dev libpulse-dev + run: ./.github/scripts/ubuntu_setup.sh - name: Build run: cargo build --verbose @@ -82,4 +76,4 @@ jobs: - name: Run tests uses: actions-rs/cargo@v1 with: - command: test \ No newline at end of file + command: test diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2d6e37b..f8f68a1 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -18,9 +18,7 @@ jobs: override: true - name: Install build deps - run: | - sudo apt-get update - sudo apt-get install libgtk-3-dev libgtk-layer-shell-dev libpulse-dev + run: ./.github/scripts/ubuntu_setup.sh - name: Update CHANGELOG id: changelog @@ -48,4 +46,4 @@ jobs: - uses: katyo/publish-crates@v1 with: - registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} \ No newline at end of file + registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/Cross.toml b/Cross.toml index 5b2cc4c..660445b 100644 --- a/Cross.toml +++ b/Cross.toml @@ -1,8 +1,5 @@ [build] -pre-build = [ - "dpkg --add-architecture $CROSS_DEB_ARCH", - "apt-get update && apt-get install --assume-yes libssl-dev:$CROSS_DEB_ARCH libgtk-3-dev:$CROSS_DEB_ARCH libgtk-layer-shell-dev:$CROSS_DEB_ARCH libpulse-dev:$CROSS_DEB_ARCH", -] +pre-build = "./.github/scripts/ubuntu_setup.sh" [target.aarch64-unknown-linux-gnu] image = "ghcr.io/cross-rs/aarch64-unknown-linux-gnu:main" From 45b43e212f819dae81d7892b647c93af372a8cc4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 14:46:05 +0000 Subject: [PATCH 14/24] build(deps): bump regex from 1.10.3 to 1.10.4 Bumps [regex](https://github.com/rust-lang/regex) from 1.10.3 to 1.10.4. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.10.3...1.10.4) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d74c6df..b080668 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2490,9 +2490,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", diff --git a/Cargo.toml b/Cargo.toml index e745d32..9839543 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -147,7 +147,7 @@ hyprland = { version = "0.3.13", features = ["silent"], optional = true } futures-util = { version = "0.3.30", optional = true } # shared -regex = { version = "1.10.3", default-features = false, features = [ +regex = { version = "1.10.4", default-features = false, features = [ "std", ], optional = true } # music, sys_info zbus = { version = "3.15.2", optional = true } # notifications, upower \ No newline at end of file From 970a6a407438bb6439e943c160c7de1b766606ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 14:46:58 +0000 Subject: [PATCH 15/24] build(deps): bump reqwest from 0.11.26 to 0.12.2 Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.11.26 to 0.12.2. - [Release notes](https://github.com/seanmonstar/reqwest/releases) - [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md) - [Commits](https://github.com/seanmonstar/reqwest/compare/v0.11.26...v0.12.2) --- updated-dependencies: - dependency-name: reqwest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 120 ++++++++++++++++++++++++++++++++++++++++++----------- Cargo.toml | 2 +- 2 files changed, 96 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d74c6df..9c1feb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1352,9 +1352,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.24" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "51ee2dd2e4f378392eeff5d51618cd9a63166a2513846bbc55f21cfacd9199d4" dependencies = [ "bytes", "fnv", @@ -1425,9 +1425,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http" -version = "0.2.9" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -1436,12 +1436,24 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", "pin-project-lite", ] @@ -1451,47 +1463,60 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - [[package]] name = "hyper" -version = "0.14.26" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", "h2", "http", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] name = "hyper-tls" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", + "http-body-util", "hyper", + "hyper-util", "native-tls", "tokio", "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2 0.5.5", + "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -2270,6 +2295,26 @@ dependencies = [ "sha2", ] +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote 1.0.35", + "syn 2.0.48", +] + [[package]] name = "pin-project-lite" version = "0.2.12" @@ -2534,9 +2579,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.26" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bf93c4af7a8bb7d879d51cebe797356ff10ae8516ace542b5182d9dcac10b2" +checksum = "2d66674f2b6fb864665eea7a3c1ac4e3dfacd2fda83cf6f935a612e01b0e3338" dependencies = [ "base64 0.21.0", "bytes", @@ -2546,8 +2591,10 @@ dependencies = [ "h2", "http", "http-body", + "http-body-util", "hyper", "hyper-tls", + "hyper-util", "ipnet", "js-sys", "log", @@ -2848,9 +2895,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smithay-client-toolkit" @@ -3291,6 +3338,28 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -3303,6 +3372,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", diff --git a/Cargo.toml b/Cargo.toml index e745d32..39b9da4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -115,7 +115,7 @@ clap = { version = "4.5.3", optional = true, features = ["derive"] } serde_json = { version = "1.0.114", optional = true } # http -reqwest = { version = "0.11.26", optional = true } +reqwest = { version = "0.12.2", optional = true } # clipboard nix = { version = "0.27.1", optional = true, features = ["event"] } From 6ce1fbc690fea504785d6e12d2892db4f0358b49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 14:47:14 +0000 Subject: [PATCH 16/24] build(deps): bump indexmap from 2.2.5 to 2.2.6 Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.2.5 to 2.2.6. - [Changelog](https://github.com/indexmap-rs/indexmap/blob/master/RELEASES.md) - [Commits](https://github.com/indexmap-rs/indexmap/compare/2.2.5...2.2.6) --- updated-dependencies: - dependency-name: indexmap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d74c6df..333b7e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1362,7 +1362,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.5", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -1585,9 +1585,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.1", @@ -1655,7 +1655,7 @@ dependencies = [ "gtk", "gtk-layer-shell", "hyprland", - "indexmap 2.2.5", + "indexmap 2.2.6", "libpulse-binding", "mpd-utils", "mpris", @@ -3273,7 +3273,7 @@ version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", @@ -3286,7 +3286,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.2.5", + "indexmap 2.2.6", "toml_datetime", "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index e745d32..036caea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,7 +94,7 @@ tracing-appender = "0.2.3" strip-ansi-escapes = "0.2.0" color-eyre = "0.6.3" serde = { version = "1.0.197", features = ["derive"] } -indexmap = "2.2.5" +indexmap = "2.2.6" dirs = "5.0.1" walkdir = "2.5.0" notify = { version = "6.1.1", default-features = false } From 3a3d3d75cd4fd8d474edc4c6ddb2c47bce60df16 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Tue, 26 Mar 2024 15:19:57 +0000 Subject: [PATCH 17/24] docs(readme): add void package --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0db0282..c1c374f 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,14 @@ A flake is included with the repo which can be used with Home Manager. CI builds are automatically cached by Garnix. You can use their binary cache by following the steps [here](https://garnix.io/docs/caching). +### Void Linux + +[void package](https://github.com/void-linux/void-packages/tree/master/srcpkgs/ironbar) + +```sh +xbps-install ironbar +``` + ### Source [repo](https://github.com/jakestanger/ironbar) @@ -183,4 +191,4 @@ All are welcome, but I ask a few basic things to help make things easier. Please - [Rustbar](https://github.com/zeroeightysix/rustbar) - Served as a good demo for writing a basic GTK bar in Rust - [Smithay Client Toolkit](https://github.com/Smithay/client-toolkit) - Essential in being able to communicate to Wayland - [gtk-layer-shell](https://github.com/wmww/gtk-layer-shell) - Ironbar and many other projects would be impossible without this -- [Mixxc](https://github.com/Elvyria/Mixxc) - Basis for Ironbar's PulseAudio client code and a cool standalone volume widget. \ No newline at end of file +- [Mixxc](https://github.com/Elvyria/Mixxc) - Basis for Ironbar's PulseAudio client code and a cool standalone volume widget. From fc42f6c540131576d6eaf1201e78ba216861947d Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Wed, 27 Mar 2024 13:22:08 +0000 Subject: [PATCH 18/24] docs(readme): add repology badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c1c374f..5fb5ecf 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,8 @@ Ironbar is designed to support anything from a lightweight bar to a full desktop ## Installation +[![Packaging status](https://repology.org/badge/vertical-allrepos/ironbar.svg)](https://repology.org/project/ironbar/versions) + ### Cargo [crate](https://crates.io/crates/ironbar) From 71b85ead782aba53485afede4078f6070906858e Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Fri, 29 Mar 2024 00:29:01 +0000 Subject: [PATCH 19/24] chore: cleanup unused dep --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 54fa058..c7639a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -139,7 +139,6 @@ futures-lite = { version = "2.3.0", optional = true } # volume libpulse-binding = { version = "2.28.1", optional = true } -# libpulse-glib-binding = { version = "2.27.1", optional = true } # workspaces swayipc-async = { version = "2.0.1", optional = true } From 8e9db141f8a668063ece3622ec91c3e22c3a87a3 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Fri, 29 Mar 2024 00:29:13 +0000 Subject: [PATCH 20/24] docs(macros): add missing comment --- src/macros.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/macros.rs b/src/macros.rs index 4cc986c..e5fd195 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -181,6 +181,13 @@ macro_rules! arc_rw { }; } +/// Wraps `val` in a new `Rc>`. +/// +/// # Usage +/// +/// ```rs +/// let val = rc_mut!(MyService::new()) +/// ``` #[macro_export] macro_rules! rc_mut { ($val:expr) => { From c7b6ee8bc00e92d075b8c66105c29e3df0906145 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Fri, 29 Mar 2024 00:29:27 +0000 Subject: [PATCH 21/24] refactor: add dead_code allow to fix build warning --- src/clients/wayland/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/clients/wayland/mod.rs b/src/clients/wayland/mod.rs index abaa869..8c7fcb8 100644 --- a/src/clients/wayland/mod.rs +++ b/src/clients/wayland/mod.rs @@ -98,6 +98,7 @@ pub enum Response { } #[derive(Debug)] +#[allow(dead_code)] struct BroadcastChannel(broadcast::Sender, Arc>>); impl From<(broadcast::Sender, broadcast::Receiver)> for BroadcastChannel { From 004ea76da5af3e8750e5a02a8780f62337b06844 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Fri, 29 Mar 2024 00:23:44 +0000 Subject: [PATCH 22/24] refactor(tray): complete client rewrite --- Cargo.lock | 36 ++-------- Cargo.toml | 2 +- src/clients/mod.rs | 15 ++-- src/clients/system_tray.rs | 127 -------------------------------- src/clients/tray.rs | 4 ++ src/modules/tray/diff.rs | 10 +-- src/modules/tray/icon.rs | 37 ++++++---- src/modules/tray/interface.rs | 76 ++++++++++++++------ src/modules/tray/mod.rs | 132 ++++++++++++++++++++++------------ 9 files changed, 193 insertions(+), 246 deletions(-) delete mode 100644 src/clients/system_tray.rs create mode 100644 src/clients/tray.rs diff --git a/Cargo.lock b/Cargo.lock index 05956ad..c6d55ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,12 +101,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "anyhow" -version = "1.0.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" - [[package]] name = "async-broadcast" version = "0.5.1" @@ -3117,18 +3111,13 @@ dependencies = [ [[package]] name = "system-tray" -version = "0.1.5" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a456e3e6cbd396f1a3a91f8f74d1fdcf2bde85c97afe174442c367f4749fc09b" +checksum = "82a053bfb84b11f5eb8655a762ba826a2524d02a2f355b0fd6fce4125272f2e0" dependencies = [ - "anyhow", - "byteorder", - "chrono", - "log", "serde", "thiserror", "tokio", - "tokio-stream", "tracing", "zbus", ] @@ -3157,18 +3146,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote 1.0.35", @@ -3243,7 +3232,6 @@ dependencies = [ "signal-hook-registry", "socket2 0.5.5", "tokio-macros", - "tracing", "windows-sys 0.48.0", ] @@ -3268,17 +3256,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-stream" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.7" @@ -4144,7 +4121,6 @@ dependencies = [ "serde_repr", "sha1", "static_assertions", - "tokio", "tracing", "uds_windows", "winapi", diff --git a/Cargo.toml b/Cargo.toml index c7639a4..23ab177 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -131,7 +131,7 @@ mpris = { version = "2.0.1", optional = true } sysinfo = { version = "0.29.11", optional = true } # tray -system-tray = { version = "0.1.5", optional = true } + system-tray = { version = "0.2.0", optional = true } # upower upower_dbus = { version = "0.3.2", optional = true } diff --git a/src/clients/mod.rs b/src/clients/mod.rs index fa9c876..a3899b2 100644 --- a/src/clients/mod.rs +++ b/src/clients/mod.rs @@ -1,3 +1,4 @@ +use crate::Ironbar; use std::sync::Arc; #[cfg(feature = "clipboard")] @@ -9,7 +10,7 @@ pub mod music; #[cfg(feature = "notifications")] pub mod swaync; #[cfg(feature = "tray")] -pub mod system_tray; +pub mod tray; #[cfg(feature = "upower")] pub mod upower; #[cfg(feature = "volume")] @@ -30,7 +31,7 @@ pub struct Clients { #[cfg(feature = "notifications")] notifications: Option>, #[cfg(feature = "tray")] - tray: Option>, + tray: Option>, #[cfg(feature = "upower")] upower: Option>>, #[cfg(feature = "volume")] @@ -85,11 +86,17 @@ impl Clients { } #[cfg(feature = "tray")] - pub fn tray(&mut self) -> Arc { + pub fn tray(&mut self) -> Arc { + // TODO: Error handling here isn't great - should throw a user-friendly error self.tray .get_or_insert_with(|| { Arc::new(crate::await_sync(async { - system_tray::create_client().await + let service_name = + format!("{}-{}", env!("CARGO_CRATE_NAME"), Ironbar::unique_id()); + + tray::Client::new(&service_name) + .await + .expect("to be able to start client") })) }) .clone() diff --git a/src/clients/system_tray.rs b/src/clients/system_tray.rs deleted file mode 100644 index aec5c0a..0000000 --- a/src/clients/system_tray.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::{arc_mut, lock, register_client, send, spawn, Ironbar}; -use color_eyre::Report; -use std::collections::BTreeMap; -use std::sync::{Arc, Mutex}; -use system_tray::message::menu::TrayMenu; -use system_tray::message::tray::StatusNotifierItem; -use system_tray::message::{NotifierItemCommand, NotifierItemMessage}; -use system_tray::StatusNotifierWatcher; -use tokio::sync::{broadcast, mpsc}; -use tracing::{debug, error, trace}; - -type Tray = BTreeMap, Option)>; - -#[derive(Debug)] -pub struct TrayEventReceiver { - tx: mpsc::Sender, - b_tx: broadcast::Sender, - _b_rx: broadcast::Receiver, - - tray: Arc>, -} - -impl TrayEventReceiver { - async fn new() -> system_tray::error::Result { - let id = format!("ironbar-{}", Ironbar::unique_id()); - - let (tx, rx) = mpsc::channel(16); - let (b_tx, b_rx) = broadcast::channel(64); - - let tray = StatusNotifierWatcher::new(rx).await?; - let mut host = Box::pin(tray.create_notifier_host(&id)).await?; - - let tray = arc_mut!(BTreeMap::new()); - - { - let b_tx = b_tx.clone(); - let tray = tray.clone(); - - spawn(async move { - while let Ok(message) = host.recv().await { - trace!("Received message: {message:?}"); - - send!(b_tx, message.clone()); - let mut tray = lock!(tray); - match message { - NotifierItemMessage::Update { - address, - item, - menu, - } => { - debug!("Adding/updating item with address '{address}'"); - tray.insert(address, (item, menu)); - } - NotifierItemMessage::Remove { address } => { - debug!("Removing item with address '{address}'"); - tray.remove(&address); - } - } - } - - Ok::<(), broadcast::error::SendError>(()) - }); - } - - Ok(Self { - tx, - b_tx, - _b_rx: b_rx, - tray, - }) - } - - pub fn subscribe( - &self, - ) -> ( - mpsc::Sender, - broadcast::Receiver, - ) { - let tx = self.tx.clone(); - let b_rx = self.b_tx.subscribe(); - - let tray = lock!(self.tray).clone(); - for (address, (item, menu)) in tray { - let update = NotifierItemMessage::Update { - address, - item, - menu, - }; - send!(self.b_tx, update); - } - - (tx, b_rx) - } -} - -/// Attempts to create a new `TrayEventReceiver` instance, -/// retrying a maximum of 10 times before panicking the thread. -pub async fn create_client() -> TrayEventReceiver { - const MAX_RETRIES: i32 = 10; - - // sometimes this can fail - let mut retries = 0; - - let value = loop { - retries += 1; - - let tray = Box::pin(TrayEventReceiver::new()).await; - - match tray { - Ok(tray) => break Some(tray), - Err(err) => error!( - "{:?}", - Report::new(err).wrap_err(format!( - "Failed to create StatusNotifierWatcher (attempt {retries})" - )) - ), - } - - if retries == MAX_RETRIES { - break None; - } - }; - - value.expect("Failed to create StatusNotifierWatcher") -} - -register_client!(TrayEventReceiver, tray); diff --git a/src/clients/tray.rs b/src/clients/tray.rs new file mode 100644 index 0000000..3b84815 --- /dev/null +++ b/src/clients/tray.rs @@ -0,0 +1,4 @@ +use crate::register_client; +pub use system_tray::client::Client; + +register_client!(Client, tray); diff --git a/src/modules/tray/diff.rs b/src/modules/tray/diff.rs index 25e27b6..dd756af 100644 --- a/src/modules/tray/diff.rs +++ b/src/modules/tray/diff.rs @@ -1,9 +1,9 @@ -use system_tray::message::menu::{MenuItem as MenuItemInfo, ToggleState}; +use system_tray::menu::{MenuItem, ToggleState}; /// Diff change type and associated info. #[derive(Debug, Clone)] pub enum Diff { - Add(MenuItemInfo), + Add(MenuItem), Update(i32, MenuItemDiff), Remove(i32), } @@ -12,7 +12,7 @@ pub enum Diff { #[derive(Debug, Clone)] pub struct MenuItemDiff { /// Text of the item, - pub label: Option, + pub label: Option>, /// Whether the item can be activated or not. pub enabled: Option, /// True if the item is visible in the menu. @@ -29,7 +29,7 @@ pub struct MenuItemDiff { } impl MenuItemDiff { - fn new(old: &MenuItemInfo, new: &MenuItemInfo) -> Self { + fn new(old: &MenuItem, new: &MenuItem) -> Self { macro_rules! diff { ($field:ident) => { if old.$field == new.$field { @@ -70,7 +70,7 @@ impl MenuItemDiff { } /// Gets a diff set between old and new state. -pub fn get_diffs(old: &[MenuItemInfo], new: &[MenuItemInfo]) -> Vec { +pub fn get_diffs(old: &[MenuItem], new: &[MenuItem]) -> Vec { let mut diffs = vec![]; for new_item in new { diff --git a/src/modules/tray/icon.rs b/src/modules/tray/icon.rs index e0a1c5b..3918dfb 100644 --- a/src/modules/tray/icon.rs +++ b/src/modules/tray/icon.rs @@ -1,4 +1,5 @@ use crate::image::ImageProvider; +use crate::modules::tray::interface::TrayMenu; use color_eyre::{Report, Result}; use glib::ffi::g_strfreev; use glib::translate::ToGlibPtr; @@ -10,7 +11,6 @@ use std::collections::HashSet; use std::ffi::CStr; use std::os::raw::{c_char, c_int}; use std::ptr; -use system_tray::message::tray::StatusNotifierItem; /// Gets the GTK icon theme search paths by calling the FFI function. /// Conveniently returns the result as a `HashSet`. @@ -38,17 +38,23 @@ fn get_icon_theme_search_paths(icon_theme: &IconTheme) -> HashSet { paths } -pub fn get_image(item: &StatusNotifierItem, icon_theme: &IconTheme, size: u32) -> Result { - get_image_from_icon_name(item, icon_theme, size).or_else(|_| get_image_from_pixmap(item, size)) +pub fn get_image( + item: &TrayMenu, + icon_theme: &IconTheme, + size: u32, + prefer_icons: bool, +) -> Result { + if !prefer_icons && item.icon_pixmap.is_some() { + get_image_from_pixmap(item, size) + } else { + get_image_from_icon_name(item, icon_theme, size) + .or_else(|_| get_image_from_pixmap(item, size)) + } } /// Attempts to get a GTK `Image` component /// for the status notifier item's icon. -fn get_image_from_icon_name( - item: &StatusNotifierItem, - icon_theme: &IconTheme, - size: u32, -) -> Result { +fn get_image_from_icon_name(item: &TrayMenu, icon_theme: &IconTheme, size: u32) -> Result { if let Some(path) = item.icon_theme_path.as_ref() { if !path.is_empty() && !get_icon_theme_search_paths(icon_theme).contains(path) { icon_theme.append_search_path(path); @@ -59,18 +65,21 @@ fn get_image_from_icon_name( icon_theme.lookup_icon(icon_name, size as i32, IconLookupFlags::empty()) }); - let pixbuf = icon_info.unwrap().load_icon()?; - - let image = Image::new(); - ImageProvider::create_and_load_surface(&pixbuf, &image)?; - Ok(image) + if let Some(icon_info) = icon_info { + let pixbuf = icon_info.load_icon()?; + let image = Image::new(); + ImageProvider::create_and_load_surface(&pixbuf, &image)?; + Ok(image) + } else { + Err(Report::msg("could not find icon")) + } } /// Attempts to get an image from the item pixmap. /// /// The pixmap is supplied in ARGB32 format, /// which has 8 bits per sample and a bit stride of `4*width`. -fn get_image_from_pixmap(item: &StatusNotifierItem, size: u32) -> Result { +fn get_image_from_pixmap(item: &TrayMenu, size: u32) -> Result { const BITS_PER_SAMPLE: i32 = 8; let pixmap = item diff --git a/src/modules/tray/interface.rs b/src/modules/tray/interface.rs index d35a1bf..4a182e9 100644 --- a/src/modules/tray/interface.rs +++ b/src/modules/tray/interface.rs @@ -1,10 +1,11 @@ -use crate::modules::tray::diff::{Diff, MenuItemDiff}; +use super::diff::{Diff, MenuItemDiff}; use crate::{spawn, try_send}; use gtk::prelude::*; use gtk::{CheckMenuItem, Image, Label, Menu, MenuItem, SeparatorMenuItem}; use std::collections::HashMap; -use system_tray::message::menu::{MenuItem as MenuItemInfo, MenuType, ToggleState, ToggleType}; -use system_tray::message::NotifierItemCommand; +use system_tray::client::ActivateRequest; +use system_tray::item::{IconPixmap, StatusNotifierItem}; +use system_tray::menu::{MenuItem as MenuItemInfo, MenuType, ToggleState, ToggleType}; use tokio::sync::mpsc; /// Calls a method on the underlying widget, @@ -49,37 +50,47 @@ macro_rules! call { /// Main tray icon to show on the bar pub(crate) struct TrayMenu { - pub(crate) widget: MenuItem, + pub widget: MenuItem, menu_widget: Menu, image_widget: Option, label_widget: Option