Skip to content

Commit

Permalink
Merge pull request #56 from trakout/linux-ksni-set_menu_item_label
Browse files Browse the repository at this point in the history
Adds menu item update capability for Linux (KSNI)
  • Loading branch information
olback authored Apr 7, 2024
2 parents 3a3dd57 + 50534b3 commit 1a05d0a
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 5 deletions.
4 changes: 4 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ jobs:
name: Run Check (libappindicator)
command: cargo check --verbose --features libappindicator

- run:
name: Run Check on examples/linux-edit-menu-items
command: cd examples/linux-edit-menu-items && cargo check --verbose

- run:
name: Run Check on examples/linux-embeded-icon
command: cd examples/linux-embeded-icon && cargo check --verbose
Expand Down
2 changes: 2 additions & 0 deletions examples/linux-edit-menu-items/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/

10 changes: 10 additions & 0 deletions examples/linux-edit-menu-items/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "linux-edit-menu-items"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
tray-item = { path = "../../", features = ["ksni"] }
png = "0.16"
55 changes: 55 additions & 0 deletions examples/linux-edit-menu-items/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use {std::io::Cursor, std::sync::mpsc, tray_item::IconSource, tray_item::TrayItem};

enum Message {
Quit,
Update,
}

fn main() {
let cursor_red = Cursor::new(include_bytes!("../../resources/tray_icon-red.png"));
let decoder_red = png::Decoder::new(cursor_red);
let (info_red, mut reader_red) = decoder_red.read_info().unwrap();
let mut buf_red = vec![0; info_red.buffer_size()];
reader_red.next_frame(&mut buf_red).unwrap();

let icon_red = IconSource::Data {
data: buf_red,
height: 32,
width: 32,
};

let mut tray = TrayItem::new("Tray Example", icon_red).unwrap();

tray.add_label("Tray Label").unwrap();

let (tx, rx) = mpsc::sync_channel::<Message>(2);
let update_tx = tx.clone();
let id_menu = tray
.inner_mut()
.add_menu_item_with_id("Update Menu Item", move || {
update_tx.send(Message::Update).unwrap();
})
.unwrap();

let quit_tx = tx.clone();
tray.add_menu_item("Quit", move || {
quit_tx.send(Message::Quit).unwrap();
})
.unwrap();

loop {
match rx.recv() {
Ok(Message::Quit) => {
println!("Quit");
break;
}
Ok(Message::Update) => {
println!("Update Menu Item!");
tray.inner_mut()
.set_menu_item_label("Menu Updated", id_menu)
.unwrap();
}
_ => {}
}
}
}
43 changes: 38 additions & 5 deletions src/api/linux_ksni/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::{IconSource, TIError};
use ksni::{menu::StandardItem, Handle, Icon};
use std::sync::Arc;
use std::sync::{Arc, Mutex};

enum TrayItem {
Label(String),
MenuItem {
id: u32,
label: String,
action: Arc<dyn Fn() + Send + Sync + 'static>,
},
Expand All @@ -15,6 +16,7 @@ struct Tray {
title: String,
icon: IconSource,
actions: Vec<TrayItem>,
next_id: u32,
}

pub struct TrayItemLinux {
Expand Down Expand Up @@ -64,7 +66,7 @@ impl ksni::Tray for Tray {
..Default::default()
}
.into(),
TrayItem::MenuItem { label, action } => {
TrayItem::MenuItem { label, action, .. } => {
let action = action.clone();
StandardItem {
label: label.clone(),
Expand All @@ -87,6 +89,7 @@ impl TrayItemLinux {
title: title.to_string(),
icon,
actions: vec![],
next_id: 0,
});

let handle = svc.handle();
Expand All @@ -113,16 +116,46 @@ impl TrayItemLinux {
where
F: Fn() -> () + Send + Sync + 'static,
{
let action = Arc::new(move || {
cb();
});
self.add_menu_item_with_id(label, cb)?;
Ok(())
}

pub fn add_menu_item_with_id<F>(&mut self, label: &str, cb: F) -> Result<u32, TIError>
where
F: Fn() + Send + Sync + 'static,
{
let action = Arc::new(cb);
let item_id = Arc::new(Mutex::new(0));
let item_id_clone = Arc::clone(&item_id);

self.tray.update(move |tray| {
let mut id = item_id_clone.lock().unwrap();
*id = tray.next_id;
tray.next_id += 1;

tray.actions.push(TrayItem::MenuItem {
id: *id,
label: label.to_string(),
action: action.clone(),
});
});

let final_id = *item_id.lock().unwrap();
Ok(final_id)
}

pub fn set_menu_item_label(&mut self, label: &str, id: u32) -> Result<(), TIError> {
self.tray.update(move |tray| {
if let Some(item) = tray.actions.iter_mut().find_map(|item| match item {
TrayItem::MenuItem {
id: item_id, label, ..
} if *item_id == id => Some(label),
_ => None,
}) {
*item = label.to_string();
}
});

Ok(())
}

Expand Down

0 comments on commit 1a05d0a

Please sign in to comment.