mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-08-17 14:51:04 +02:00
refactor(tray): complete client rewrite
This commit is contained in:
parent
c7b6ee8bc0
commit
004ea76da5
9 changed files with 193 additions and 246 deletions
|
@ -2,19 +2,21 @@ mod diff;
|
|||
mod icon;
|
||||
mod interface;
|
||||
|
||||
use crate::clients::system_tray::TrayEventReceiver;
|
||||
use crate::clients::tray;
|
||||
use crate::config::CommonConfig;
|
||||
use crate::modules::tray::diff::get_diffs;
|
||||
use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext};
|
||||
use crate::{glib_recv, spawn};
|
||||
use color_eyre::Result;
|
||||
use crate::{glib_recv, lock, send_async, spawn};
|
||||
use color_eyre::{Report, Result};
|
||||
use gtk::{prelude::*, PackDirection};
|
||||
use gtk::{IconTheme, MenuBar};
|
||||
use interface::TrayMenu;
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
use system_tray::message::{NotifierItemCommand, NotifierItemMessage};
|
||||
use system_tray::client::Event;
|
||||
use system_tray::client::{ActivateRequest, UpdateEvent};
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::{debug, error, warn};
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct TrayModule {
|
||||
|
@ -49,8 +51,8 @@ where
|
|||
}
|
||||
|
||||
impl Module<MenuBar> for TrayModule {
|
||||
type SendMessage = NotifierItemMessage;
|
||||
type ReceiveMessage = NotifierItemCommand;
|
||||
type SendMessage = Event;
|
||||
type ReceiveMessage = ActivateRequest;
|
||||
|
||||
fn name() -> &'static str {
|
||||
"tray"
|
||||
|
@ -64,26 +66,39 @@ impl Module<MenuBar> for TrayModule {
|
|||
) -> Result<()> {
|
||||
let tx = context.tx.clone();
|
||||
|
||||
let client = context.client::<TrayEventReceiver>();
|
||||
let client = context.client::<tray::Client>();
|
||||
let mut tray_rx = client.subscribe();
|
||||
|
||||
let (tray_tx, mut tray_rx) = client.subscribe();
|
||||
let initial_items = lock!(client.items()).clone();
|
||||
|
||||
// listen to tray updates
|
||||
spawn(async move {
|
||||
while let Ok(message) = tray_rx.recv().await {
|
||||
tx.send(ModuleUpdateEvent::Update(message)).await?;
|
||||
for (key, (item, menu)) in initial_items.into_iter() {
|
||||
send_async!(
|
||||
tx,
|
||||
ModuleUpdateEvent::Update(Event::Add(key.clone(), item.into()))
|
||||
);
|
||||
|
||||
if let Some(menu) = menu.clone() {
|
||||
send_async!(
|
||||
tx,
|
||||
ModuleUpdateEvent::Update(Event::Update(key, UpdateEvent::Menu(menu)))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok::<(), mpsc::error::SendError<ModuleUpdateEvent<Self::SendMessage>>>(())
|
||||
while let Ok(message) = tray_rx.recv().await {
|
||||
send_async!(tx, ModuleUpdateEvent::Update(message))
|
||||
}
|
||||
});
|
||||
|
||||
// send tray commands
|
||||
spawn(async move {
|
||||
while let Some(cmd) = rx.recv().await {
|
||||
tray_tx.send(cmd).await?;
|
||||
client.activate(cmd).await?;
|
||||
}
|
||||
|
||||
Ok::<(), mpsc::error::SendError<NotifierItemCommand>>(())
|
||||
Ok::<_, Report>(())
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
@ -114,7 +129,7 @@ impl Module<MenuBar> for TrayModule {
|
|||
|
||||
// listen for UI updates
|
||||
glib_recv!(context.subscribe(), update =>
|
||||
on_update(update, &container, &mut menus, &icon_theme, self.icon_size, &context.controller_tx)
|
||||
on_update(update, &container, &mut menus, &icon_theme, self.icon_size, self.prefer_theme_icons, &context.controller_tx)
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -128,52 +143,81 @@ impl Module<MenuBar> for TrayModule {
|
|||
/// Handles UI updates as callback,
|
||||
/// getting the diff since the previous update and applying it to the menu.
|
||||
fn on_update(
|
||||
update: NotifierItemMessage,
|
||||
update: Event,
|
||||
container: &MenuBar,
|
||||
menus: &mut HashMap<Box<str>, TrayMenu>,
|
||||
icon_theme: &IconTheme,
|
||||
icon_size: u32,
|
||||
tx: &mpsc::Sender<NotifierItemCommand>,
|
||||
prefer_icons: bool,
|
||||
tx: &mpsc::Sender<ActivateRequest>,
|
||||
) {
|
||||
match update {
|
||||
NotifierItemMessage::Update {
|
||||
item,
|
||||
address,
|
||||
menu,
|
||||
} => {
|
||||
if let (Some(menu_opts), Some(menu_path)) = (menu, &item.menu) {
|
||||
let submenus = menu_opts.submenus;
|
||||
Event::Add(address, item) => {
|
||||
debug!("Received new tray item at '{address}': {item:?}");
|
||||
|
||||
let mut menu_item = menus.remove(address.as_str()).unwrap_or_else(|| {
|
||||
let item = TrayMenu::new(tx.clone(), address.clone(), menu_path.to_string());
|
||||
container.add(&item.widget);
|
||||
let mut menu_item = TrayMenu::new(tx.clone(), address.clone(), *item);
|
||||
container.add(&menu_item.widget);
|
||||
|
||||
item
|
||||
});
|
||||
|
||||
let label = item.title.as_ref().unwrap_or(&address);
|
||||
if let Some(label_widget) = menu_item.label_widget() {
|
||||
label_widget.set_label(label);
|
||||
match icon::get_image(&menu_item, icon_theme, icon_size, prefer_icons) {
|
||||
Ok(image) => menu_item.set_image(&image),
|
||||
Err(_) => {
|
||||
let label = menu_item.title.clone().unwrap_or(address.clone());
|
||||
menu_item.set_label(&label)
|
||||
}
|
||||
};
|
||||
|
||||
if item.icon_name.as_ref() != menu_item.icon_name() {
|
||||
match icon::get_image(&item, icon_theme, icon_size) {
|
||||
Ok(image) => menu_item.set_image(&image),
|
||||
Err(_) => menu_item.set_label(label),
|
||||
};
|
||||
menu_item.widget.show();
|
||||
menus.insert(address.into(), menu_item);
|
||||
}
|
||||
Event::Update(address, update) => {
|
||||
debug!("Received tray update for '{address}': {update:?}");
|
||||
|
||||
let Some(menu_item) = menus.get_mut(address.as_str()) else {
|
||||
error!("Attempted to update menu at '{address}' but could not find it");
|
||||
return;
|
||||
};
|
||||
|
||||
match update {
|
||||
UpdateEvent::AttentionIcon(_icon) => {
|
||||
warn!("received unimplemented NewAttentionIcon event");
|
||||
}
|
||||
UpdateEvent::Icon(icon) => {
|
||||
if icon.as_ref() != menu_item.icon_name() {
|
||||
match icon::get_image(menu_item, icon_theme, icon_size, prefer_icons) {
|
||||
Ok(image) => menu_item.set_image(&image),
|
||||
Err(_) => menu_item.show_label(),
|
||||
};
|
||||
}
|
||||
|
||||
let diffs = get_diffs(menu_item.state(), &submenus);
|
||||
menu_item.apply_diffs(diffs);
|
||||
menu_item.widget.show();
|
||||
menu_item.set_icon_name(icon);
|
||||
}
|
||||
UpdateEvent::OverlayIcon(_icon) => {
|
||||
warn!("received unimplemented NewOverlayIcon event");
|
||||
}
|
||||
UpdateEvent::Status(_status) => {
|
||||
warn!("received unimplemented NewStatus event");
|
||||
}
|
||||
UpdateEvent::Title(title) => {
|
||||
if let Some(label_widget) = menu_item.label_widget() {
|
||||
label_widget.set_label(&title.unwrap_or_default());
|
||||
}
|
||||
}
|
||||
// UpdateEvent::Tooltip(_tooltip) => {
|
||||
// warn!("received unimplemented NewAttentionIcon event");
|
||||
// }
|
||||
UpdateEvent::Menu(menu) => {
|
||||
debug!("received new menu for '{}'", address);
|
||||
|
||||
menu_item.set_state(submenus);
|
||||
menu_item.set_icon_name(item.icon_name);
|
||||
let diffs = get_diffs(menu_item.state(), &menu.submenus);
|
||||
|
||||
menus.insert(address.into(), menu_item);
|
||||
menu_item.apply_diffs(diffs);
|
||||
menu_item.set_state(menu.submenus);
|
||||
}
|
||||
}
|
||||
}
|
||||
NotifierItemMessage::Remove { address } => {
|
||||
Event::Remove(address) => {
|
||||
debug!("Removing tray item at '{address}'");
|
||||
|
||||
if let Some(menu) = menus.get(address.as_str()) {
|
||||
container.remove(&menu.widget);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue