use std::sync::Arc;
use winit::window::Window;
use crate::config::Config;
use crate::menu::state::{Capture, MenuState};
use super::WindowManager;
const HAS_NATIVE_MENU_BAR: bool = cfg!(any(target_os = "macos", target_os = "windows"));
pub(crate) struct NativeMenuInputs {
pub(crate) config: Arc<Config>,
pub(crate) capture: Capture,
pub(crate) state: MenuState,
}
impl WindowManager {
pub(crate) fn sync_menus(&mut self) {
let windows = self.window_list();
let arrangements = self.arrangement_list();
for window_state in self.windows.values_mut() {
let mut state = window_state.menu_state();
state.windows = windows.clone();
state.arrangements = arrangements.clone();
let config = window_state.config.load();
window_state
.tab_bar_ui
.sync_app_menu(&config.keybindings, state);
}
if !HAS_NATIVE_MENU_BAR {
return;
}
let Some(inputs) = self.native_menu_inputs() else {
return;
};
let bindings = &inputs.config.keybindings;
let Some(menu) = &self.menu else {
return;
};
if let Some(reason) = menu.rebuild_reason(bindings, &inputs.capture) {
log::debug!("menu: rebuilding ({reason:?})");
let attached: Vec<Arc<Window>> = self
.windows
.values()
.filter_map(|ws| ws.window.clone())
.collect();
if let Some(menu) = &mut self.menu
&& let Err(e) = menu.rebuild(bindings, inputs.capture.clone(), &attached)
{
log::warn!("menu: rebuild failed: {e}");
}
}
if let Some(menu) = &mut self.menu {
menu.apply_state(&inputs.state);
}
}
pub(crate) fn native_menu_inputs(&self) -> Option<NativeMenuInputs> {
let focused = self.focused_window()?;
let mut state = focused.menu_state();
state.windows = self.window_list();
state.arrangements = self.arrangement_list();
let settings_focused = self
.settings_window
.as_ref()
.is_some_and(|sw| sw.is_focused());
let capture = if !cfg!(target_os = "macos") {
None
} else if settings_focused {
Some(Default::default())
} else {
focused.menu_capture()
};
Some(NativeMenuInputs {
config: focused.config.load_full(),
capture,
state,
})
}
fn window_list(&self) -> Vec<(usize, String)> {
let mut list: Vec<(usize, String)> = self
.windows
.values()
.map(|ws| {
let title = ws
.tab_manager
.active_tab()
.map(|t| t.title.trim().to_string())
.unwrap_or_default();
(ws.window_index, title)
})
.collect();
list.sort_by_key(|(number, _)| *number);
list
}
fn arrangement_list(&self) -> Vec<(crate::arrangements::ArrangementId, String)> {
self.arrangement_manager
.arrangements_ordered()
.into_iter()
.map(|a| (a.id, a.name.clone()))
.collect()
}
}