diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 12338b75fb..52e8e859ad 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -3339,6 +3339,13 @@ impl<'a, T: View> ViewContext<'a, T> { } } + pub fn set_window_edited(&mut self, edited: bool) { + let window_id = self.window_id(); + if let Some((_, window)) = self.presenters_and_platform_windows.get_mut(&window_id) { + window.set_edited(edited); + } + } + pub fn add_model(&mut self, build_model: F) -> ModelHandle where S: Entity, diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 6d841f3962..6c259537ad 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -97,6 +97,7 @@ pub trait Window: WindowContext { fn prompt(&self, level: PromptLevel, msg: &str, answers: &[&str]) -> oneshot::Receiver; fn activate(&self); fn set_title(&mut self, title: &str); + fn set_edited(&mut self, edited: bool); } pub trait WindowContext { diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index ac5073d893..e16bac5a0d 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -397,6 +397,17 @@ impl platform::Window for Window { msg_send![app, changeWindowsItem:window title:title filename:false] } } + + fn set_edited(&mut self, edited: bool) { + unsafe { + let window = self.0.borrow().native_window; + msg_send![window, setDocumentEdited: edited as BOOL] + } + + // Changing the document edited state resets the traffic light position, + // so we have to move it again. + self.0.borrow().move_traffic_light(); + } } impl platform::WindowContext for Window { diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index b1b460ff70..fd07ef80a2 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -38,6 +38,7 @@ pub struct Window { resize_handlers: Vec>, close_handlers: Vec>, pub(crate) title: Option, + pub(crate) edited: bool, pub(crate) pending_prompts: RefCell>>, } @@ -191,6 +192,7 @@ impl Window { scale_factor: 1.0, current_scene: None, title: None, + edited: false, pending_prompts: Default::default(), } } @@ -258,6 +260,10 @@ impl super::Window for Window { fn set_title(&mut self, title: &str) { self.title = Some(title.to_string()) } + + fn set_edited(&mut self, edited: bool) { + self.edited = edited; + } } pub fn platform() -> Platform { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index b1a4fbd293..55da35ca85 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -731,6 +731,7 @@ pub struct Workspace { leader_state: LeaderState, follower_states_by_leader: FollowerStatesByLeader, last_leaders_by_pane: HashMap, PeerId>, + window_edited: bool, _observe_current_user: Task<()>, } @@ -846,6 +847,7 @@ impl Workspace { leader_state: Default::default(), follower_states_by_leader: Default::default(), last_leaders_by_pane: Default::default(), + window_edited: false, _observe_current_user, }; this.project_remote_id_changed(this.project.read(cx).remote_id(), cx); @@ -1474,6 +1476,7 @@ impl Workspace { if pane == self.active_pane { self.active_item_path_changed(cx); } + self.update_window_edited(cx); } } } else { @@ -1778,6 +1781,16 @@ impl Workspace { cx.set_window_title(&title); } + fn update_window_edited(&mut self, cx: &mut ViewContext) { + let is_edited = self + .items(cx) + .any(|item| item.has_conflict(cx) || item.is_dirty(cx)); + if is_edited != self.window_edited { + self.window_edited = is_edited; + cx.set_window_edited(self.window_edited) + } + } + fn render_collaborators(&self, theme: &Theme, cx: &mut RenderContext) -> Vec { let mut collaborators = self .project