From dfa102c5ae2b69e7f4e0faa8c24c9b229faa4eac Mon Sep 17 00:00:00 2001 From: Be Date: Fri, 21 Nov 2025 13:56:00 -0600 Subject: [PATCH] Add setting for enabling server-side decorations (#39250) Previously, this was controllable via the undocumented ZED_WINDOW_DECORATIONS environment variable (added in #13866). Using an environment variable for this is inconvenient because it requires users to set that environment variable somehow before starting Zed, such as in the .desktop file or persistently in their shell. Controlling this via a Zed setting is more convenient. This does not modify the design of the titlebar in any way. It only moves the existing option from an environment variable to a Zed setting. Fixes #14165 Client-side decorations (default): image Server-side decorations in KDE Plasma: image Release Notes: - Changed option for Wayland server-side decorations from an environment variable to settings.json field --------- Co-authored-by: Conrad Irwin --- assets/settings/default.json | 10 ++++++++ crates/rules_library/src/rules_library.rs | 7 ++++-- .../src/settings_content/workspace.rs | 25 +++++++++++++++++++ crates/settings/src/vscode_import.rs | 1 + crates/settings_ui/src/page_data.rs | 15 +++++++++++ crates/settings_ui/src/settings_ui.rs | 1 + crates/workspace/src/workspace_settings.rs | 2 ++ crates/zed/src/zed.rs | 5 +++- 8 files changed, 63 insertions(+), 3 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index 9b289bdf088be12ec6970f81ddd7edfd55aedc66..ba79f0ccbcca3837d94adc49ddbc9c53b3ae0a5f 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -175,6 +175,16 @@ // // Default: true "zoomed_padding": true, + // What draws Zed's window decorations (titlebar): + // 1. Client application (Zed) draws its own window decorations + // "client" + // 2. Display server draws the window decorations. Not supported by GNOME Wayland. + // "server" + // + // This requires restarting Zed for changes to take effect. + // + // Default: "client" + "window_decorations": "client", // Whether to use the system provided dialogs for Open and Save As. // When set to false, Zed will use the built-in keyboard-first pickers. "use_system_path_prompts": true, diff --git a/crates/rules_library/src/rules_library.rs b/crates/rules_library/src/rules_library.rs index 207a9841e41bf35e1f63bb00b0c62073c1cf0224..b5b664f6e5c91e2a4f3760b3ad34c3b055bb2df7 100644 --- a/crates/rules_library/src/rules_library.rs +++ b/crates/rules_library/src/rules_library.rs @@ -25,7 +25,7 @@ use ui::{ Divider, KeyBinding, ListItem, ListItemSpacing, ListSubHeader, Render, Tooltip, prelude::*, }; use util::{ResultExt, TryFutureExt}; -use workspace::{Workspace, client_side_decorations}; +use workspace::{Workspace, WorkspaceSettings, client_side_decorations}; use zed_actions::assistant::InlineAssist; use prompt_store::*; @@ -122,7 +122,10 @@ pub fn open_rules_library( let window_decorations = match std::env::var("ZED_WINDOW_DECORATIONS") { Ok(val) if val == "server" => gpui::WindowDecorations::Server, Ok(val) if val == "client" => gpui::WindowDecorations::Client, - _ => gpui::WindowDecorations::Client, + _ => match WorkspaceSettings::get_global(cx).window_decorations { + settings::WindowDecorations::Server => gpui::WindowDecorations::Server, + settings::WindowDecorations::Client => gpui::WindowDecorations::Client, + }, }; cx.open_window( WindowOptions { diff --git a/crates/settings/src/settings_content/workspace.rs b/crates/settings/src/settings_content/workspace.rs index f078c873179d2b50893e608bc51e609be9850a12..088d478e464bd0f4e9a92419440c16576005fc95 100644 --- a/crates/settings/src/settings_content/workspace.rs +++ b/crates/settings/src/settings_content/workspace.rs @@ -109,6 +109,9 @@ pub struct WorkspaceSettingsContent { /// /// Default: true pub zoomed_padding: Option, + /// What draws window decorations/titlebar, the client application (Zed) or display server + /// Default: client + pub window_decorations: Option, } #[with_fallible_options] @@ -290,6 +293,28 @@ pub enum BottomDockLayout { RightAligned, } +#[derive( + Copy, + Clone, + Default, + Debug, + Serialize, + Deserialize, + PartialEq, + JsonSchema, + MergeFrom, + strum::VariantArray, + strum::VariantNames, +)] +#[serde(rename_all = "snake_case")] +pub enum WindowDecorations { + /// Zed draws its own window decorations/titlebar (client-side decoration) + #[default] + Client, + /// Show system's window titlebar (server-side decoration; not supported by GNOME Wayland) + Server, +} + #[derive( Copy, Clone, diff --git a/crates/settings/src/vscode_import.rs b/crates/settings/src/vscode_import.rs index 4d893011d49d2094614c6e06918ecf6e8fade774..22081727d8ff767b861a776f0a821e3b4a8d5fdf 100644 --- a/crates/settings/src/vscode_import.rs +++ b/crates/settings/src/vscode_import.rs @@ -843,6 +843,7 @@ impl VsCodeSettings { resize_all_panels_in_dock: None, restore_on_file_reopen: self.read_bool("workbench.editor.restoreViewState"), restore_on_startup: None, + window_decorations: None, show_call_status_icon: None, use_system_path_prompts: self.read_bool("files.simpleDialog.enable"), use_system_prompts: None, diff --git a/crates/settings_ui/src/page_data.rs b/crates/settings_ui/src/page_data.rs index 76874c2ad9594cd9955cbe759c458fe9cf007c2e..edd488f419eeee0a7074a95697d9615317891a4d 100644 --- a/crates/settings_ui/src/page_data.rs +++ b/crates/settings_ui/src/page_data.rs @@ -3264,6 +3264,21 @@ pub(crate) fn settings_data(cx: &App) -> Vec { metadata: None, files: USER, }), + SettingsPageItem::SettingItem(SettingItem { + title: "Window Decorations", + description: "(Linux only) whether Zed or your compositor should draw window decorations.", + field: Box::new(SettingField { + json_path: Some("window_decorations"), + pick: |settings_content| { + settings_content.workspace.window_decorations.as_ref() + }, + write: |settings_content, value| { + settings_content.workspace.window_decorations = value; + }, + }), + metadata: None, + files: USER, + }), SettingsPageItem::SectionHeader("Pane Modifiers"), SettingsPageItem::SettingItem(SettingItem { title: "Inactive Opacity", diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index ef8cf4928665113a72d97b804931295d6181dde4..4f29945edb2e212e3638db60213dde082a41baf6 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -513,6 +513,7 @@ fn init_renderers(cx: &mut App) { .add_basic_renderer::(render_dropdown) .add_basic_renderer::(render_dropdown) .add_basic_renderer::(render_dropdown) + .add_basic_renderer::(render_dropdown) // please semicolon stay on next line ; } diff --git a/crates/workspace/src/workspace_settings.rs b/crates/workspace/src/workspace_settings.rs index 24958df7c6d5d36fee243022d700ccf56a570a19..4ce0394fe5fdc74754c1147138cb33c67e076d88 100644 --- a/crates/workspace/src/workspace_settings.rs +++ b/crates/workspace/src/workspace_settings.rs @@ -31,6 +31,7 @@ pub struct WorkspaceSettings { pub close_on_file_delete: bool, pub use_system_window_tabs: bool, pub zoomed_padding: bool, + pub window_decorations: settings::WindowDecorations, } #[derive(Copy, Clone, PartialEq, Debug, Default)] @@ -105,6 +106,7 @@ impl Settings for WorkspaceSettings { close_on_file_delete: workspace.close_on_file_delete.unwrap(), use_system_window_tabs: workspace.use_system_window_tabs.unwrap(), zoomed_padding: workspace.zoomed_padding.unwrap(), + window_decorations: workspace.window_decorations.unwrap(), } } } diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index df46794bb833320f2793fdb798df735fc72c8b3f..be38b3f0952d5ccab6d9d729d77f3fce1e407a4d 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -307,7 +307,10 @@ pub fn build_window_options(display_uuid: Option, cx: &mut App) -> WindowO let window_decorations = match std::env::var("ZED_WINDOW_DECORATIONS") { Ok(val) if val == "server" => gpui::WindowDecorations::Server, Ok(val) if val == "client" => gpui::WindowDecorations::Client, - _ => gpui::WindowDecorations::Client, + _ => match WorkspaceSettings::get_global(cx).window_decorations { + settings::WindowDecorations::Server => gpui::WindowDecorations::Server, + settings::WindowDecorations::Client => gpui::WindowDecorations::Client, + }, }; let use_system_window_tabs = WorkspaceSettings::get_global(cx).use_system_window_tabs;