Add setting to show/hide title bar (#37428)

Ben Gubler created

Closes #5120

Release Notes:

- Added settings for hiding and showing title bar



https://github.com/user-attachments/assets/aaed52d0-6278-4544-8932-c6bab531512a

Change summary

assets/settings/default.json               |  2 
crates/title_bar/src/title_bar.rs          | 49 ++++++++++++++++++++++-
crates/title_bar/src/title_bar_settings.rs | 13 ++++++
crates/workspace/src/workspace.rs          |  5 ++
docs/src/configuring-zed.md                |  1 
docs/src/visual-customization.md           |  1 
6 files changed, 67 insertions(+), 4 deletions(-)

Detailed changes

assets/settings/default.json 🔗

@@ -391,6 +391,8 @@
   "use_system_window_tabs": false,
   // Titlebar related settings
   "title_bar": {
+    // When to show the title bar: "always" | "never" | "hide_in_full_screen".
+    "show": "always",
     // Whether to show the branch icon beside branch switcher in the titlebar.
     "show_branch_icon": false,
     // Whether to show the branch name button in the titlebar.

crates/title_bar/src/title_bar.rs 🔗

@@ -4,7 +4,7 @@ mod onboarding_banner;
 pub mod platform_title_bar;
 mod platforms;
 mod system_window_tabs;
-mod title_bar_settings;
+pub mod title_bar_settings;
 
 #[cfg(feature = "stories")]
 mod stories;
@@ -35,7 +35,7 @@ use remote::RemoteConnectionOptions;
 use settings::{Settings, SettingsLocation};
 use std::{path::Path, sync::Arc};
 use theme::ActiveTheme;
-use title_bar_settings::TitleBarSettings;
+use title_bar_settings::{TitleBarSettings, TitleBarVisibility};
 use ui::{
     Avatar, Button, ButtonLike, ButtonStyle, Chip, ContextMenu, Icon, IconName, IconSize,
     IconWithIndicator, Indicator, PopoverMenu, PopoverMenuHandle, Tooltip, h_flex, prelude::*,
@@ -73,8 +73,49 @@ pub fn init(cx: &mut App) {
         let Some(window) = window else {
             return;
         };
-        let item = cx.new(|cx| TitleBar::new("title-bar", workspace, window, cx));
-        workspace.set_titlebar_item(item.into(), window, cx);
+        let should_show = match TitleBarSettings::get_global(cx).show {
+            TitleBarVisibility::Always => true,
+            TitleBarVisibility::Never => false,
+            TitleBarVisibility::HideInFullScreen => !window.is_fullscreen(),
+        };
+        if should_show {
+            let item = cx.new(|cx| TitleBar::new("title-bar", workspace, window, cx));
+            workspace.set_titlebar_item(item.into(), window, cx);
+        }
+
+        cx.observe_global_in::<settings::SettingsStore>(window, |workspace, window, cx| {
+            let should_show = match TitleBarSettings::get_global(cx).show {
+                TitleBarVisibility::Always => true,
+                TitleBarVisibility::Never => false,
+                TitleBarVisibility::HideInFullScreen => !window.is_fullscreen(),
+            };
+            if should_show {
+                if workspace.titlebar_item().is_none() {
+                    let item = cx.new(|cx| TitleBar::new("title-bar", workspace, window, cx));
+                    workspace.set_titlebar_item(item.into(), window, cx);
+                }
+            } else {
+                workspace.clear_titlebar_item(window, cx);
+            }
+        })
+        .detach();
+
+        cx.observe_window_bounds(window, |workspace, window, cx| {
+            let should_show = match TitleBarSettings::get_global(cx).show {
+                TitleBarVisibility::Always => true,
+                TitleBarVisibility::Never => false,
+                TitleBarVisibility::HideInFullScreen => !window.is_fullscreen(),
+            };
+            if should_show {
+                if workspace.titlebar_item().is_none() {
+                    let item = cx.new(|cx| TitleBar::new("title-bar", workspace, window, cx));
+                    workspace.set_titlebar_item(item.into(), window, cx);
+                }
+            } else {
+                workspace.clear_titlebar_item(window, cx);
+            }
+        })
+        .detach();
 
         #[cfg(not(target_os = "macos"))]
         workspace.register_action(|workspace, action: &OpenApplicationMenu, window, cx| {

crates/title_bar/src/title_bar_settings.rs 🔗

@@ -3,8 +3,17 @@ use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
 
+#[derive(Copy, Clone, Serialize, Deserialize, JsonSchema, Debug, SettingsUi)]
+#[serde(rename_all = "snake_case")]
+pub enum TitleBarVisibility {
+    Always,
+    Never,
+    HideInFullScreen,
+}
+
 #[derive(Copy, Clone, Deserialize, Debug)]
 pub struct TitleBarSettings {
+    pub show: TitleBarVisibility,
     pub show_branch_icon: bool,
     pub show_onboarding_banner: bool,
     pub show_user_picture: bool,
@@ -20,6 +29,10 @@ pub struct TitleBarSettings {
 #[settings_ui(group = "Title Bar")]
 #[settings_key(key = "title_bar")]
 pub struct TitleBarSettingsContent {
+    /// Controls when the title bar is visible: "always" | "never" | "hide_in_full_screen".
+    ///
+    /// Default: "always"
+    pub show: Option<TitleBarVisibility>,
     /// Whether to show the branch icon beside branch switcher in the title bar.
     ///
     /// Default: false

crates/workspace/src/workspace.rs 🔗

@@ -2043,6 +2043,11 @@ impl Workspace {
         cx.notify();
     }
 
+    pub fn clear_titlebar_item(&mut self, _: &mut Window, cx: &mut Context<Self>) {
+        self.titlebar_item = None;
+        cx.notify();
+    }
+
     pub fn set_prompt_for_new_path(&mut self, prompt: PromptForNewPath) {
         self.on_prompt_for_new_path = Some(prompt)
     }

docs/src/configuring-zed.md 🔗

@@ -4106,6 +4106,7 @@ Run the {#action theme_selector::Toggle} action in the command palette to see a
 
 ```json
 "title_bar": {
+  "show": "always",
   "show_branch_icon": false,
   "show_branch_name": true,
   "show_project_items": true,

docs/src/visual-customization.md 🔗

@@ -108,6 +108,7 @@ To disable this behavior use:
 ```json
   // Control which items are shown/hidden in the title bar
   "title_bar": {
+    "show": "always",               // When to show: always | never | hide_in_full_screen
     "show_branch_icon": false,      // Show/hide branch icon beside branch switcher
     "show_branch_name": true,       // Show/hide branch name
     "show_project_items": true,     // Show/hide project host and name