Skip to content

Commit 0d76ffd

Browse files
Desktop: Mac remove menubar flicker (#3335)
* remove unnecessary folders from bundling for mac * mac remove menu bar flicker * clean up implementation
1 parent 6d669ad commit 0d76ffd

2 files changed

Lines changed: 66 additions & 14 deletions

File tree

desktop/bundle/src/mac.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ const HELPER_BIN: &str = "graphite-desktop-platform-mac-helper";
1212

1313
const EXEC_PATH: &str = "Contents/MacOS";
1414
const FRAMEWORKS_PATH: &str = "Contents/Frameworks";
15-
const RESOURCES_PATH: &str = "Contents/Resources";
1615
const FRAMEWORK: &str = "Chromium Embedded Framework.framework";
1716

1817
pub fn main() -> Result<(), Box<dyn Error>> {
@@ -56,10 +55,6 @@ fn create_app(app_dir: &Path, id: &str, name: &str, bin: &Path, is_helper: bool)
5655
fs::create_dir_all(app_dir.join(EXEC_PATH)).unwrap();
5756

5857
let app_contents_dir: &Path = &app_dir.join("Contents");
59-
for p in &[EXEC_PATH, RESOURCES_PATH, FRAMEWORKS_PATH] {
60-
fs::create_dir_all(app_contents_dir.join(p)).unwrap();
61-
}
62-
6358
create_info_plist(app_contents_dir, id, name, is_helper).unwrap();
6459
fs::copy(bin, app_dir.join(EXEC_PATH).join(name)).unwrap();
6560
}

desktop/src/window/mac/menu.rs

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use muda::Menu as MudaMenu;
22
use muda::accelerator::Accelerator;
3-
use muda::{AboutMetadataBuilder, CheckMenuItem, IsMenuItem, MenuEvent, MenuId, MenuItem, MenuItemKind, PredefinedMenuItem, Submenu};
3+
use muda::{AboutMetadataBuilder, CheckMenuItem, IsMenuItem, MenuEvent, MenuId, MenuItem, MenuItemKind, PredefinedMenuItem, Result, Submenu};
44

55
use crate::event::{AppEvent, AppEventScheduler};
66
use crate::wrapper::messages::MenuItem as WrapperMenuItem;
@@ -38,14 +38,26 @@ impl Menu {
3838
}
3939

4040
pub(super) fn update(&self, entries: Vec<WrapperMenuItem>) {
41-
// remove all items except the first (app menu)
42-
self.inner.items().iter().skip(1).for_each(|item: &muda::MenuItemKind| {
43-
self.inner.remove(menu_item_kind_to_dyn(item)).unwrap();
44-
});
45-
46-
let items = menu_items_from_wrapper(entries);
47-
let items = items.iter().map(|item| menu_item_kind_to_dyn(item)).collect::<Vec<&dyn IsMenuItem>>();
48-
self.inner.append_items(items.as_ref()).unwrap();
41+
let new_entries = menu_items_from_wrapper(entries);
42+
let existing_entries = self.inner.items();
43+
44+
let mut new_entries_iter = new_entries.iter();
45+
let mut existing_entries_iter = existing_entries.iter().skip(1); // Skip first menu (app menu)
46+
47+
let incremental_update_ok = std::iter::from_fn(move || match (existing_entries_iter.next(), new_entries_iter.next()) {
48+
(Some(MenuItemKind::Submenu(old)), Some(MenuItemKind::Submenu(new))) if old.text() == new.text() => {
49+
replace_children(old, 0, new.items());
50+
Some(true)
51+
}
52+
(None, None) => None,
53+
_ => Some(false),
54+
})
55+
.all(|b| b);
56+
57+
if !incremental_update_ok {
58+
// Fallback to full replace
59+
replace_children(&self.inner, 1, new_entries); // Skip first menu (app menu)
60+
}
4961
}
5062
}
5163

@@ -97,3 +109,48 @@ fn u64_to_menu_id(id: u64) -> String {
97109
fn menu_id_to_u64(id: &MenuId) -> Option<u64> {
98110
u64::from_str_radix(&id.0, 16).ok()
99111
}
112+
113+
fn replace_children<'a, T: Into<MenuContainer<'a>>>(menu: T, skip: usize, new_items: Vec<MenuItemKind>) {
114+
let menu: MenuContainer = menu.into();
115+
let items = menu.items();
116+
for item in items.iter().skip(skip) {
117+
menu.remove(menu_item_kind_to_dyn(item)).unwrap();
118+
}
119+
let items = new_items.iter().map(|item| menu_item_kind_to_dyn(item)).collect::<Vec<&dyn IsMenuItem>>();
120+
menu.append_items(items.as_ref()).unwrap();
121+
}
122+
123+
enum MenuContainer<'a> {
124+
Menu(&'a MudaMenu),
125+
Submenu(&'a Submenu),
126+
}
127+
impl<'a> MenuContainer<'a> {
128+
fn items(&self) -> Vec<MenuItemKind> {
129+
match self {
130+
MenuContainer::Menu(menu) => menu.items(),
131+
MenuContainer::Submenu(submenu) => submenu.items(),
132+
}
133+
}
134+
fn remove(&self, item: &dyn IsMenuItem) -> Result<()> {
135+
match self {
136+
MenuContainer::Menu(menu) => menu.remove(item),
137+
MenuContainer::Submenu(submenu) => submenu.remove(item),
138+
}
139+
}
140+
fn append_items(&self, items: &[&dyn IsMenuItem]) -> Result<()> {
141+
match self {
142+
MenuContainer::Menu(menu) => menu.append_items(items),
143+
MenuContainer::Submenu(submenu) => submenu.append_items(items),
144+
}
145+
}
146+
}
147+
impl<'a> From<&'a MudaMenu> for MenuContainer<'a> {
148+
fn from(menu: &'a MudaMenu) -> Self {
149+
MenuContainer::Menu(menu)
150+
}
151+
}
152+
impl<'a> From<&'a Submenu> for MenuContainer<'a> {
153+
fn from(submenu: &'a Submenu) -> Self {
154+
MenuContainer::Submenu(submenu)
155+
}
156+
}

0 commit comments

Comments
 (0)