diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index eb1d73814388a26503e9ada782bc358dc712b53c..d3425c8835bb474ffbed6bc79371340d569d1bfb 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -522,6 +522,7 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle { fn merge_all_windows(&self) {} fn move_tab_to_new_window(&self) {} fn toggle_window_tab_overview(&self) {} + fn set_tabbing_identifier(&self, _identifier: Option) {} #[cfg(target_os = "windows")] fn get_raw_handle(&self) -> windows::HWND; diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 0262cbb1213ca670cece780959c740f292764630..686cfb314e58c4e10e916a07931fb5f4248ea54e 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -781,6 +781,8 @@ impl MacWindow { if let Some(tabbing_identifier) = tabbing_identifier { let tabbing_id = NSString::alloc(nil).init_str(tabbing_identifier.as_str()); let _: () = msg_send![native_window, setTabbingIdentifier: tabbing_id]; + } else { + let _: () = msg_send![native_window, setTabbingIdentifier:nil]; } } WindowKind::PopUp => { @@ -1018,6 +1020,25 @@ impl PlatformWindow for MacWindow { } } + fn set_tabbing_identifier(&self, tabbing_identifier: Option) { + let native_window = self.0.lock().native_window; + unsafe { + let allows_automatic_window_tabbing = tabbing_identifier.is_some(); + if allows_automatic_window_tabbing { + let () = msg_send![class!(NSWindow), setAllowsAutomaticWindowTabbing: YES]; + } else { + let () = msg_send![class!(NSWindow), setAllowsAutomaticWindowTabbing: NO]; + } + + if let Some(tabbing_identifier) = tabbing_identifier { + let tabbing_id = NSString::alloc(nil).init_str(tabbing_identifier.as_str()); + let _: () = msg_send![native_window, setTabbingIdentifier: tabbing_id]; + } else { + let _: () = msg_send![native_window, setTabbingIdentifier:nil]; + } + } + } + fn scale_factor(&self) -> f32 { self.0.as_ref().lock().scale_factor() } diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 4504f512551b678b9304a4c180f54b15c34af956..c2719665d423a4431184d56a9b6bff16f8ad443b 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -4390,6 +4390,13 @@ impl Window { self.platform_window.toggle_window_tab_overview() } + /// Sets the tabbing identifier for the window. + /// This is macOS specific. + pub fn set_tabbing_identifier(&self, tabbing_identifier: Option) { + self.platform_window + .set_tabbing_identifier(tabbing_identifier) + } + /// Toggles the inspector mode on this window. #[cfg(any(feature = "inspector", debug_assertions))] pub fn toggle_inspector(&mut self, cx: &mut App) { diff --git a/crates/title_bar/src/system_window_tabs.rs b/crates/title_bar/src/system_window_tabs.rs index cc50fbc2b99b56c2d8dab95e0c56deb33da2bb4b..ba898da716f042573840f8f9c9f375747ac5cc04 100644 --- a/crates/title_bar/src/system_window_tabs.rs +++ b/crates/title_bar/src/system_window_tabs.rs @@ -1,4 +1,4 @@ -use settings::Settings; +use settings::{Settings, SettingsStore}; use gpui::{ AnyWindowHandle, Context, Hsla, InteractiveElement, MouseButton, ParentElement, ScrollHandle, @@ -11,7 +11,7 @@ use ui::{ LabelSize, Tab, h_flex, prelude::*, right_click_menu, }; use workspace::{ - CloseWindow, ItemSettings, Workspace, + CloseWindow, ItemSettings, Workspace, WorkspaceSettings, item::{ClosePosition, ShowCloseButton}, }; @@ -53,6 +53,46 @@ impl SystemWindowTabs { } pub fn init(cx: &mut App) { + let mut was_use_system_window_tabs = + WorkspaceSettings::get_global(cx).use_system_window_tabs; + + cx.observe_global::(move |cx| { + let use_system_window_tabs = WorkspaceSettings::get_global(cx).use_system_window_tabs; + if use_system_window_tabs == was_use_system_window_tabs { + return; + } + was_use_system_window_tabs = use_system_window_tabs; + + let tabbing_identifier = if use_system_window_tabs { + Some(String::from("zed")) + } else { + None + }; + + if use_system_window_tabs { + SystemWindowTabController::init(cx); + } + + cx.windows().iter().for_each(|handle| { + let _ = handle.update(cx, |_, window, cx| { + window.set_tabbing_identifier(tabbing_identifier.clone()); + if use_system_window_tabs { + let tabs = if let Some(tabs) = window.tabbed_windows() { + tabs + } else { + vec![SystemWindowTab::new( + SharedString::from(window.window_title()), + window.window_handle(), + )] + }; + + SystemWindowTabController::add_tab(cx, handle.window_id(), tabs); + } + }); + }); + }) + .detach(); + cx.observe_new(|workspace: &mut Workspace, _, _| { workspace.register_action_renderer(|div, _, window, cx| { let window_id = window.window_handle().window_id(); @@ -336,6 +376,7 @@ impl SystemWindowTabs { impl Render for SystemWindowTabs { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { + let use_system_window_tabs = WorkspaceSettings::get_global(cx).use_system_window_tabs; let active_background_color = cx.theme().colors().title_bar_background; let inactive_background_color = cx.theme().colors().tab_bar_background; let entity = cx.entity(); @@ -368,7 +409,9 @@ impl Render for SystemWindowTabs { .collect::>(); let number_of_tabs = tab_items.len().max(1); - if !window.tab_bar_visible() && !visible { + if (!window.tab_bar_visible() && !visible) + || (!use_system_window_tabs && number_of_tabs == 1) + { return h_flex().into_any_element(); } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 79cf2bfa66fb217680dea86720eb46402f116958..d1d221fb37ddf4d76804f326f3d60ae7a09cdcbc 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -955,7 +955,7 @@ async fn installation_id() -> Result { async fn restore_or_create_workspace(app_state: Arc, cx: &mut AsyncApp) -> Result<()> { if let Some(locations) = restorable_workspace_locations(cx, &app_state).await { let use_system_window_tabs = cx - .update(|cx| WorkspaceSettings::get(None, cx).use_system_window_tabs) + .update(|cx| WorkspaceSettings::get_global(cx).use_system_window_tabs) .unwrap_or(false); let mut results: Vec> = Vec::new(); let mut tasks = Vec::new();