diff --git a/.github/scripts/ubuntu_setup.sh b/.github/scripts/ubuntu_setup.sh index db9ca763..74b93d24 100755 --- a/.github/scripts/ubuntu_setup.sh +++ b/.github/scripts/ubuntu_setup.sh @@ -17,5 +17,6 @@ $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} \ + libdbusmenu-gtk3-dev${CROSS_DEB_ARCH:+:$CROSS_DEB_ARCH} \ libpulse-dev${CROSS_DEB_ARCH:+:$CROSS_DEB_ARCH} \ libluajit-5.1-dev${CROSS_DEB_ARCH:+:$CROSS_DEB_ARCH} diff --git a/Cargo.lock b/Cargo.lock index 047bc5cf..4bf620f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -691,6 +691,34 @@ dependencies = [ "winapi", ] +[[package]] +name = "dbusmenu-glib-sys" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff9ed40330718c94342b953c997ac19d840db07a7710fe35b45a5d3a3a1d6eb" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "dbusmenu-gtk3-sys" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f30ba5f8aec0e38a84c579bc8ee3db6f6417b201e729fdd96a23d1f61cb6eca" +dependencies = [ + "dbusmenu-glib-sys", + "gdk-pixbuf-sys", + "gdk-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "libc", + "system-deps", +] + [[package]] name = "deranged" version = "0.3.11" @@ -3229,10 +3257,12 @@ dependencies = [ [[package]] name = "system-tray" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66066cf85f8a4985ae5a40ca4387036e4f870d95fbf113ffaab714796785d0f2" +checksum = "c5eff7a9f41bc02826920bf9da8b03fb74cb9c55bac250b4bc470af12d980285" dependencies = [ + "dbusmenu-gtk3-sys", + "gtk", "serde", "thiserror 2.0.0", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 951407ba..d86e8c59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -148,7 +148,7 @@ futures-signals = { version = "0.3.34", optional = true } sysinfo = { version = "0.29.11", optional = true } # tray -system-tray = { version = "0.3.0", optional = true } +system-tray = { version = "0.4.0", features = ["dbusmenu-gtk3"], optional = true } png = { version = "0.17.14", optional = true } # upower diff --git a/docs/Compiling.md b/docs/Compiling.md index 7a9a3e87..ceafa75f 100644 --- a/docs/Compiling.md +++ b/docs/Compiling.md @@ -22,6 +22,8 @@ You also need rust; only the latest stable version is supported. pacman -S gtk3 gtk-layer-shell # for http support pacman -S openssl +# for tray support +pacman -S libdbusmenu-gtk3 # for volume support pacman -S libpulse # for lua/cairo support @@ -34,6 +36,8 @@ pacman -S luajit lua51-lgi apt install build-essential libgtk-3-dev libgtk-layer-shell-dev # for http support apt install libssl-dev +# for tray support +apt install libdbusmenu-gtk3-dev # for volume support apt install libpulse-dev # for lua/cairo support @@ -46,6 +50,8 @@ apt install luajit-dev lua-lgi dnf install gtk3-devel gtk-layer-shell-devel # for http support dnf install openssl-devel +# for tray support +dnf install libdbusmenu-gtk3-devel # for volume support dnf install pulseaudio-libs-devel # for lua/cairo support diff --git a/flake.nix b/flake.nix index df751d22..1c5ef93a 100644 --- a/flake.nix +++ b/flake.nix @@ -129,6 +129,7 @@ hicolor-icon-theme gsettings-desktop-schemas libxkbcommon + libdbusmenu-gtk3 libpulseaudio luajit luajitPackages.lgi diff --git a/nix/default.nix b/nix/default.nix index db1e3b89..eb99bbf0 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -12,6 +12,7 @@ gtk-layer-shell, gnome, libxkbcommon, + libdbusmenu-gtk3, libpulseaudio, openssl, luajit, @@ -54,9 +55,10 @@ hicolor-icon-theme gsettings-desktop-schemas libxkbcommon ] - ++ (if hasFeature "http" then [ openssl ] else []) - ++ (if hasFeature "volume" then [ libpulseaudio ] else []) - ++ (if hasFeature "cairo" then [ luajit ] else []); + ++ lib.optionals (hasFeature "http") [ openssl ] + ++ lib.optionals (hasFeature "tray") [ libdbusmenu-gtk3 ] + ++ lib.optionals (hasFeature "volume")[ libpulseaudio ] + ++ lib.optionals (hasFeature "cairo") [ luajit ]; propagatedBuildInputs = [ gtk3 ]; @@ -72,10 +74,10 @@ # gtk-launch --suffix PATH : "${lib.makeBinPath [ gtk3 ]}" '' - + (if hasFeature "cairo" then '' + + lib.optionalString (hasFeature "cairo") '' --prefix LUA_PATH : "./?.lua;${lgi}/share/lua/5.1/?.lua;${lgi}/share/lua/5.1/?/init.lua;${luajit}/share/lua/5.1/\?.lua;${luajit}/share/lua/5.1/?/init.lua" --prefix LUA_CPATH : "./?.so;${lgi}/lib/lua/5.1/?.so;${luajit}/lib/lua/5.1/?.so;${luajit}/lib/lua/5.1/loadall.so" - '' else ""); + ''; preFixup = '' gappsWrapperArgs+=( diff --git a/shell.nix b/shell.nix index b15e8e9b..17db0f78 100644 --- a/shell.nix +++ b/shell.nix @@ -9,6 +9,7 @@ pkgs.mkShell { gtk-layer-shell gcc openssl + libdbusmenu-gtk3 libpulseaudio luajit luajitPackages.lgi diff --git a/src/modules/tray/diff.rs b/src/modules/tray/diff.rs deleted file mode 100644 index 8afa3da0..00000000 --- a/src/modules/tray/diff.rs +++ /dev/null @@ -1,107 +0,0 @@ -use system_tray::menu::{MenuItem, ToggleState}; - -/// Diff change type and associated info. -#[derive(Debug, Clone)] -pub enum Diff { - Add(MenuItem), - Update(i32, MenuItemDiff), - Remove(i32), -} - -/// Diff info to be applied to an existing menu item as an update. -#[derive(Debug, Clone)] -pub struct MenuItemDiff { - /// Text of the item, - pub label: Option>, - /// Whether the item can be activated or not. - pub enabled: Option, - /// True if the item is visible in the menu. - pub visible: Option, - /// Icon name of the item, following the freedesktop.org icon spec. - pub icon_name: Option>, - /// PNG icon data. - pub icon_data: Option>>, - /// Describe the current state of a "togglable" item. Can be one of: - /// - Some(true): on - /// - Some(false): off - /// - None: indeterminate - pub toggle_state: Option, - /// A submenu for this item, typically this would ve revealed to the user by hovering the current item - pub submenu: Vec, -} - -impl MenuItemDiff { - fn new(old: &MenuItem, new: &MenuItem) -> Self { - macro_rules! diff { - ($field:ident) => { - if old.$field == new.$field { - None - } else { - Some(new.$field) - } - }; - - (&$field:ident) => { - if &old.$field == &new.$field { - None - } else { - Some(new.$field.clone()) - } - }; - } - - Self { - label: diff!(&label), - enabled: diff!(enabled), - visible: diff!(visible), - icon_name: diff!(&icon_name), - icon_data: diff!(&icon_data), - toggle_state: diff!(toggle_state), - submenu: get_diffs(&old.submenu, &new.submenu), - } - } - - /// Whether this diff contains any changes - fn has_diff(&self) -> bool { - self.label.is_some() - || self.enabled.is_some() - || self.visible.is_some() - // || self.icon_name.is_some() - || self.toggle_state.is_some() - || !self.submenu.is_empty() - } -} - -/// Gets a diff set between old and new state. -pub fn get_diffs(old: &[MenuItem], new: &[MenuItem]) -> Vec { - let mut diffs = vec![]; - - for new_item in new { - let old_item = old.iter().find(|&item| item.id == new_item.id); - - let diff = match old_item { - Some(old_item) => { - let item_diff = MenuItemDiff::new(old_item, new_item); - if item_diff.has_diff() { - Some(Diff::Update(old_item.id, item_diff)) - } else { - None - } - } - None => Some(Diff::Add(new_item.clone())), - }; - - if let Some(diff) = diff { - diffs.push(diff); - } - } - - for old_item in old { - let new_item = new.iter().find(|&item| item.id == old_item.id); - if new_item.is_none() { - diffs.push(Diff::Remove(old_item.id)); - } - } - - diffs -} diff --git a/src/modules/tray/interface.rs b/src/modules/tray/interface.rs index 95162bce..0cd39304 100644 --- a/src/modules/tray/interface.rs +++ b/src/modules/tray/interface.rs @@ -1,119 +1,34 @@ -use super::diff::{Diff, MenuItemDiff}; -use crate::image::ImageProvider; -use crate::modules::tray::icon::PngData; -use crate::{spawn, try_send}; -use glib::Propagation; use gtk::prelude::*; -use gtk::{ - CheckMenuItem, Container, IconTheme, Image, Label, Menu, MenuItem, Orientation, - SeparatorMenuItem, -}; -use std::collections::HashMap; -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; -use tracing::{error, warn}; - -/// Calls a method on the underlying widget, -/// passing in a single argument. -/// -/// This is useful to avoid matching on -/// `TrayMenuWidget` constantly. -/// -/// # Example -/// ```rust -/// call!(container, add, my_widget) -/// ``` -/// is the same as: -/// ``` -/// match &my_widget { -/// TrayMenuWidget::Separator(w) => { -/// container.add(w); -/// } -/// TrayMenuWidget::Standard(w) => { -/// container.add(w); -/// } -/// TrayMenuWidget::Checkbox(w) => { -/// container.add(w); -/// } -/// } -/// ``` -macro_rules! call { - ($parent:expr, $method:ident, $child:expr) => { - match &$child { - TrayMenuWidget::Separator(w) => { - $parent.$method(w); - } - TrayMenuWidget::Standard(w) => { - $parent.$method(w); - } - TrayMenuWidget::Checkbox(w) => { - $parent.$method(w); - } - } - }; -} +use gtk::{Image, Label, MenuItem}; +use system_tray::item::{IconPixmap, StatusNotifierItem, Tooltip}; /// Main tray icon to show on the bar pub(crate) struct TrayMenu { pub widget: MenuItem, - menu_widget: Menu, + menu_widget: Option, image_widget: Option, label_widget: Option