-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(tray): vastly improve rendering performance
- Loading branch information
1 parent
0616633
commit 133632d
Showing
5 changed files
with
650 additions
and
291 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
use system_tray::message::menu::{MenuItem as MenuItemInfo, ToggleState}; | ||
|
||
/// Diff change type and associated info. | ||
#[derive(Debug, Clone)] | ||
pub enum Diff { | ||
Add(MenuItemInfo), | ||
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<String>, | ||
/// Whether the item can be activated or not. | ||
pub enabled: Option<bool>, | ||
/// True if the item is visible in the menu. | ||
pub visible: Option<bool>, | ||
/// Icon name of the item, following the freedesktop.org icon spec. | ||
// pub icon_name: Option<Option<String>>, | ||
/// Describe the current state of a "togglable" item. Can be one of: | ||
/// - Some(true): on | ||
/// - Some(false): off | ||
/// - None: indeterminate | ||
pub toggle_state: Option<ToggleState>, | ||
/// A submenu for this item, typically this would ve revealed to the user by hovering the current item | ||
pub submenu: Vec<Diff>, | ||
} | ||
|
||
impl MenuItemDiff { | ||
fn new(old: &MenuItemInfo, new: &MenuItemInfo) -> 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), | ||
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: &[MenuItemInfo], new: &[MenuItemInfo]) -> Vec<Diff> { | ||
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 | ||
} |
Oops, something went wrong.