From d5cc1cbaa97501ff1966f60f6db41d1042e1ca4d Mon Sep 17 00:00:00 2001 From: Smit Barmase Date: Wed, 9 Jul 2025 09:44:11 -0700 Subject: [PATCH] title_bar: Add setting to always show menu for Linux and Windows (#34139) Closes #22869 Release Notes: - Added `show_menus` setting to always show menu bar for Linux and Windows. --------- Co-authored-by: Cole Miller Co-authored-by: Danilo Leal --- assets/settings/default.json | 4 +- crates/gpui/src/platform/mac/platform.rs | 21 ++++++--- crates/title_bar/src/application_menu.rs | 15 ++++-- crates/title_bar/src/platform_title_bar.rs | 26 +++++----- crates/title_bar/src/title_bar.rs | 55 ++++++++++++++++++---- crates/title_bar/src/title_bar_settings.rs | 5 ++ docs/src/visual-customization.md | 3 +- 7 files changed, 97 insertions(+), 32 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index 08daa236ab..9e487a733d 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -362,7 +362,9 @@ // Whether to show user picture in the titlebar. "show_user_picture": true, // Whether to show the sign in button in the titlebar. - "show_sign_in": true + "show_sign_in": true, + // Whether to show the menus in the titlebar. + "show_menus": false }, // Scrollbar related settings "scrollbar": { diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index d5ecd1c066..d9bb665469 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -7,7 +7,7 @@ use super::{ use crate::{ Action, AnyWindowHandle, BackgroundExecutor, ClipboardEntry, ClipboardItem, ClipboardString, CursorStyle, ForegroundExecutor, Image, ImageFormat, KeyContext, Keymap, MacDispatcher, - MacDisplay, MacWindow, Menu, MenuItem, PathPromptOptions, Platform, PlatformDisplay, + MacDisplay, MacWindow, Menu, MenuItem, OwnedMenu, PathPromptOptions, Platform, PlatformDisplay, PlatformKeyboardLayout, PlatformTextSystem, PlatformWindow, Result, SemanticVersion, Task, WindowAppearance, WindowParams, hash, }; @@ -170,6 +170,7 @@ pub(crate) struct MacPlatformState { open_urls: Option)>>, finish_launching: Option>, dock_menu: Option, + menus: Option>, } impl Default for MacPlatform { @@ -207,6 +208,7 @@ impl MacPlatform { finish_launching: None, dock_menu: None, on_keyboard_layout_change: None, + menus: None, })) } @@ -226,7 +228,7 @@ impl MacPlatform { unsafe fn create_menu_bar( &self, - menus: Vec, + menus: &Vec, delegate: id, actions: &mut Vec>, keymap: &Keymap, @@ -241,7 +243,7 @@ impl MacPlatform { menu.setTitle_(menu_title); menu.setDelegate_(delegate); - for item_config in menu_config.items { + for item_config in &menu_config.items { menu.addItem_(Self::create_menu_item( item_config, delegate, @@ -277,7 +279,7 @@ impl MacPlatform { dock_menu.setDelegate_(delegate); for item_config in menu_items { dock_menu.addItem_(Self::create_menu_item( - item_config, + &item_config, delegate, actions, keymap, @@ -289,7 +291,7 @@ impl MacPlatform { } unsafe fn create_menu_item( - item: MenuItem, + item: &MenuItem, delegate: id, actions: &mut Vec>, keymap: &Keymap, @@ -399,7 +401,7 @@ impl MacPlatform { let tag = actions.len() as NSInteger; let _: () = msg_send![item, setTag: tag]; - actions.push(action); + actions.push(action.boxed_clone()); item } MenuItem::Submenu(Menu { name, items }) => { @@ -865,10 +867,15 @@ impl Platform for MacPlatform { let app: id = msg_send![APP_CLASS, sharedApplication]; let mut state = self.0.lock(); let actions = &mut state.menu_actions; - let menu = self.create_menu_bar(menus, NSWindow::delegate(app), actions, keymap); + let menu = self.create_menu_bar(&menus, NSWindow::delegate(app), actions, keymap); drop(state); app.setMainMenu_(menu); } + self.0.lock().menus = Some(menus.into_iter().map(|menu| menu.owned()).collect()); + } + + fn get_menus(&self) -> Option> { + self.0.lock().menus.clone() } fn set_dock_menu(&self, menu: Vec, keymap: &Keymap) { diff --git a/crates/title_bar/src/application_menu.rs b/crates/title_bar/src/application_menu.rs index a7d99cf757..a5d5f154c9 100644 --- a/crates/title_bar/src/application_menu.rs +++ b/crates/title_bar/src/application_menu.rs @@ -1,4 +1,5 @@ use gpui::{Entity, OwnedMenu, OwnedMenuItem}; +use settings::Settings; #[cfg(not(target_os = "macos"))] use gpui::{Action, actions}; @@ -11,6 +12,8 @@ use serde::Deserialize; use smallvec::SmallVec; use ui::{ContextMenu, PopoverMenu, PopoverMenuHandle, Tooltip, prelude::*}; +use crate::title_bar_settings::TitleBarSettings; + #[cfg(not(target_os = "macos"))] actions!( app_menu, @@ -242,15 +245,21 @@ impl ApplicationMenu { cx.defer_in(window, move |_, window, cx| next_handle.show(window, cx)); } - pub fn all_menus_shown(&self) -> bool { - self.entries.iter().any(|entry| entry.handle.is_deployed()) + pub fn all_menus_shown(&self, cx: &mut Context) -> bool { + show_menus(cx) + || self.entries.iter().any(|entry| entry.handle.is_deployed()) || self.pending_menu_open.is_some() } } +pub(crate) fn show_menus(cx: &mut App) -> bool { + TitleBarSettings::get_global(cx).show_menus + && (cfg!(not(target_os = "macos")) || option_env!("ZED_USE_CROSS_PLATFORM_MENU").is_some()) +} + impl Render for ApplicationMenu { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { - let all_menus_shown = self.all_menus_shown(); + let all_menus_shown = self.all_menus_shown(cx); if let Some(pending_menu_open) = self.pending_menu_open.take() { if let Some(entry) = self diff --git a/crates/title_bar/src/platform_title_bar.rs b/crates/title_bar/src/platform_title_bar.rs index 5331ed39dd..30b1b4c3f8 100644 --- a/crates/title_bar/src/platform_title_bar.rs +++ b/crates/title_bar/src/platform_title_bar.rs @@ -1,6 +1,6 @@ use gpui::{ - AnyElement, Context, Decorations, InteractiveElement, IntoElement, MouseButton, ParentElement, - Pixels, StatefulInteractiveElement, Styled, Window, WindowControlArea, div, px, + AnyElement, Context, Decorations, Hsla, InteractiveElement, IntoElement, MouseButton, + ParentElement, Pixels, StatefulInteractiveElement, Styled, Window, WindowControlArea, div, px, }; use smallvec::SmallVec; use std::mem; @@ -37,6 +37,18 @@ impl PlatformTitleBar { px(32.) } + pub fn title_bar_color(&self, window: &mut Window, cx: &mut Context) -> Hsla { + if cfg!(any(target_os = "linux", target_os = "freebsd")) { + if window.is_window_active() && !self.should_move { + cx.theme().colors().title_bar_background + } else { + cx.theme().colors().title_bar_inactive_background + } + } else { + cx.theme().colors().title_bar_background + } + } + pub fn set_children(&mut self, children: T) where T: IntoIterator, @@ -50,15 +62,7 @@ impl Render for PlatformTitleBar { let supported_controls = window.window_controls(); let decorations = window.window_decorations(); let height = Self::height(window); - let titlebar_color = if cfg!(any(target_os = "linux", target_os = "freebsd")) { - if window.is_window_active() && !self.should_move { - cx.theme().colors().title_bar_background - } else { - cx.theme().colors().title_bar_inactive_background - } - } else { - cx.theme().colors().title_bar_background - }; + let titlebar_color = self.title_bar_color(window, cx); let close_action = Box::new(workspace::CloseWindow); let children = mem::take(&mut self.children); diff --git a/crates/title_bar/src/title_bar.rs b/crates/title_bar/src/title_bar.rs index f2006f639d..5c91625412 100644 --- a/crates/title_bar/src/title_bar.rs +++ b/crates/title_bar/src/title_bar.rs @@ -8,7 +8,10 @@ mod title_bar_settings; #[cfg(feature = "stories")] mod stories; -use crate::{application_menu::ApplicationMenu, platform_title_bar::PlatformTitleBar}; +use crate::{ + application_menu::{ApplicationMenu, show_menus}, + platform_title_bar::PlatformTitleBar, +}; #[cfg(not(target_os = "macos"))] use crate::application_menu::{ @@ -133,6 +136,8 @@ impl Render for TitleBar { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let title_bar_settings = *TitleBarSettings::get_global(cx); + let show_menus = show_menus(cx); + let mut children = Vec::new(); children.push( @@ -142,10 +147,14 @@ impl Render for TitleBar { let mut render_project_items = title_bar_settings.show_branch_name || title_bar_settings.show_project_items; title_bar - .when_some(self.application_menu.clone(), |title_bar, menu| { - render_project_items &= !menu.read(cx).all_menus_shown(); - title_bar.child(menu) - }) + .when_some( + self.application_menu.clone().filter(|_| !show_menus), + |title_bar, menu| { + render_project_items &= + !menu.update(cx, |menu, cx| menu.all_menus_shown(cx)); + title_bar.child(menu) + }, + ) .when(render_project_items, |title_bar| { title_bar .when(title_bar_settings.show_project_items, |title_bar| { @@ -190,11 +199,39 @@ impl Render for TitleBar { .into_any_element(), ); - self.platform_titlebar.update(cx, |this, _| { - this.set_children(children); - }); + if show_menus { + self.platform_titlebar.update(cx, |this, _| { + this.set_children( + self.application_menu + .clone() + .map(|menu| menu.into_any_element()), + ); + }); - self.platform_titlebar.clone().into_any_element() + let height = PlatformTitleBar::height(window); + let title_bar_color = self.platform_titlebar.update(cx, |platform_titlebar, cx| { + platform_titlebar.title_bar_color(window, cx) + }); + + v_flex() + .w_full() + .child(self.platform_titlebar.clone().into_any_element()) + .child( + h_flex() + .bg(title_bar_color) + .h(height) + .pl_2() + .justify_between() + .w_full() + .children(children), + ) + .into_any_element() + } else { + self.platform_titlebar.update(cx, |this, _| { + this.set_children(children); + }); + self.platform_titlebar.clone().into_any_element() + } } } diff --git a/crates/title_bar/src/title_bar_settings.rs b/crates/title_bar/src/title_bar_settings.rs index cb8f3fa565..a98e984d80 100644 --- a/crates/title_bar/src/title_bar_settings.rs +++ b/crates/title_bar/src/title_bar_settings.rs @@ -11,6 +11,7 @@ pub struct TitleBarSettings { pub show_branch_name: bool, pub show_project_items: bool, pub show_sign_in: bool, + pub show_menus: bool, } #[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema, Debug)] @@ -39,6 +40,10 @@ pub struct TitleBarSettingsContent { /// /// Default: true pub show_sign_in: Option, + /// Whether to show the menus in the title bar. + /// + /// Default: false + pub show_menus: Option, } impl Settings for TitleBarSettings { diff --git a/docs/src/visual-customization.md b/docs/src/visual-customization.md index e68e7ffabf..636e0f9c4e 100644 --- a/docs/src/visual-customization.md +++ b/docs/src/visual-customization.md @@ -112,7 +112,8 @@ To disable this behavior use: "show_project_items": true, // Show/hide project host and name "show_onboarding_banner": true, // Show/hide onboarding banners "show_user_picture": true, // Show/hide user avatar - "show_sign_in": true // Show/hide sign-in button + "show_sign_in": true, // Show/hide sign-in button + "show_menus": false // Show/hide menus }, ```