@@ -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<String>) {}
#[cfg(target_os = "windows")]
fn get_raw_handle(&self) -> windows::HWND;
@@ -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<String>) {
+ 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()
}
@@ -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<String>) {
+ 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) {
@@ -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::<SettingsStore>(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<Self>) -> 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::<Vec<_>>();
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();
}
@@ -955,7 +955,7 @@ async fn installation_id() -> Result<IdType> {
async fn restore_or_create_workspace(app_state: Arc<AppState>, 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<Result<(), Error>> = Vec::new();
let mut tasks = Vec::new();